Map Generator

I’m converting the GTA III map to Unity, but it takes a lot of time to place the models in the scene. I use ZModeler to convert the GTA dff models to 3ds, but they have to be scaled to .75 to fit. That’s already done using the import propeties.

The file which contains the placement data looks like this:

ID, ModelName, PosX, PosZ, PosY, ScaleX, ScaleZ, ScaleY, RotX, RotZ, RotY, RotW (ID can’t be used, rotations are in Quaternions)

I’ve tried to do it manually, but it takes to much time. How can I make it render itself? Preferably not runtime.

G-Modifications

so you have a file that has placement data?

Write an editor script that parses through said file and places each object where it needs to be.

That consists of 3 major steps

parse file
instantiate models
transform models

Is there a specific step you’re having trouble with?

Thanks for your reply. I have indeed the placement data.

I’ve tried something but it doens’t work (I get a lot of compilation errors):

#pragma strict
import System.IO;

class MapGenerator extends EditorWindow
{    
	var filePath : String;
	var objects : Object[];
	var mapName : String;
	
	@MenuItem("Window/GTA Map Generator")
	
	static function Init()
	{
		var window = GetWindow(MapGenerator);
		window.Show();
	}
	
	function OnGUI()
	{
		objects = Resources.LoadAll("Map/" + mapName);
		
		GUILayout.Label("GTA Map Generator");
		EditorGUILayout.TextField("File path: ", filePath);
		EditorGUILayout.TextField("Map name: ", mapName);
		
		if(GUILayout.Button("Render"))
		{
			LoadFile();
		}      
    }
    
    function LoadFile()
    {
    	var sr = new StreamReader(filePath);
    	var fileContents = sr.ReadToEnd();
    	sr.Close();
    	
    	var lines = fileContents.Split("\n"[0]);
    	
    	for(var i : int; i < lines.Length; i++)
    	{
    		var lineElements = lines[i].Split(","[0]);
    		
    		for(var j : int; j < objects.Length; j++)
    		{
    			if(lineElements[1] == objects[j].name)
    			{
    				Instantiate(objects[j], Vector3(lineElements[2] * 0.75, lineElements[4] * 0.75, lineElements[3] * 0.75), Quaternion.Euler(lineElements[9], lineElements[11], lineElements[10]));
    			}
    		}
    	}
    }
}

I need also an error log when the object couldn’t be rendered.

G-Modifications

Could you post the errors?

As for logging an error, there are a few ways you can do it.
You can have a dialog box pop up with the error in it, not sure if it ll pause your code or not.

EditorUtility.DisplayDialog ("Spawn Error", "Could not instantiate model.", "Ok");

Or if you want an actual error, like the compilation errors then you can use

Debug.LogError("Error spawning model.")

There is also

Debug.LogWarning(System.Exception)

and

Debug.LogException("Can't spawn model.")

The second parameter of these called ‘context’ is used to link the error to a GameObject in the scene.
But if you cant spawn the GameObject then I dont see why you would need this. lol :slight_smile:

Thanks, but I don’t know that where I should put that.

I’ve tried a bit harder and the error are gone, but the tekstfields clear themself al the time:

#pragma strict
import System.IO;

class MapGenerator extends EditorWindow
{    
	var filePath : String;
	var filePathString : String = "D:/My Documents/Games/Simulator +/Map/Data/data/maps/industnw/industnw.ipl";
	var objects : Object[];
	var mapName : String;
	var mapNameString : String = "industnw";
	
	@MenuItem("Window/GTA Map Generator")
	
	static function Init()
	{
		var window = GetWindow(MapGenerator);
		window.Show();
	}
	
	function OnGUI()
	{
		GUILayout.Label("GTA Map Generator");
		filePath = EditorGUILayout.TextField("File path: ", filePathString);
		mapName = EditorGUILayout.TextField("Map name: ", mapNameString);
		
		objects = Resources.LoadAll("Map/" + mapName);
		
		if(GUILayout.Button("Render"))
		{
			LoadFile();
		}   
    }
    
    function LoadFile()
    {
    	var sr = new StreamReader(filePath);
    	var fileContents = sr.ReadToEnd();
    	sr.Close();
    	
    	var lines = fileContents.Split("\n"[0]);
    	
    	for(var i : int; i < lines.Length; i++)
    	{
    		var lineElements = lines[i].Split(","[0]);
    		
    		for(var j : int; j < objects.Length; j++)
    		{
    			if(lineElements[1] == objects[j].ToString)
    			{
    				Instantiate(objects[j], Vector3(float.Parse(lineElements[2]) * 0.75, float.Parse(lineElements[4]) * 0.75, float.Parse(lineElements[3]) * 0.75), Quaternion.Euler(float.Parse(lineElements[9]), float.Parse(lineElements[11]), float.Parse(lineElements[10])));
    			}
    		}
    	}
    }
}
filePath = EditorGUILayout.TextField("File path: ", filePathString);
mapName = EditorGUILayout.TextField("Map name: ", mapNameString);

They are clearing themselves cause every time OnGUI is called you are setting them to the value of filePathString and mapNameString
The second variable should be the variable you are setting it to which is the variable you are editing, that way they are in sync and are getting the right values

This is how it should look

filePath = EditorGUILayout.TextField("File path: ", filePath);
mapName = EditorGUILayout.TextField("Map name: ", mapName);

As for placing an error, you should do it where the error could occur, in this case, it could occur when you instantiate the model. So you are going to want to try to instantiate it and catch any errors
So use a try catch on our instantiation

if(lineElements[1] == objects[j].ToString) {
    try {
        Instantiate(objects[j], Vector3(float.Parse(lineElements[2]) * 0.75, float.Parse(lineElements[4]) * 0.75, float.Parse(lineElements[3]) * 0.75), Quaternion.Euler(float.Parse(lineElements[9]), float.Parse(lineElements[11]), float.Parse(lineElements[10])));
    } catch {
        Debug.LogError("Error spawning model");
        // or   Debug.LogError("Error spawning " + objects[j].name);
    }
}

Thanks, but now I get this error when I hit “Render”:

IndexOutOfRangeException: Array index is out of range.
MapGenerator.LoadFile () (at Assets/Resources/Scripts/MapGenerator.js:49)
MapGenerator.OnGUI () (at Assets/Resources/Scripts/MapGenerator.js:29)
System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)
var sr = new StreamReader(filePath);

This is your error, the value of filePath is being sent in with a value that can’t be executed as a file path.
I’m assuming you are using Windows, so when you enter the file path you would be putting a \ between directorys.
In C# and most of all language uses a single \ to denote the following character as a special character
ex \t is equal to a tab
So you would need to add a second \ before your \ so that it reads it as a single
So if your file is on your desktop then your filePath should look like

C:\\Users\\Magnite7\\Desktop\\

I’ve found that I had an error in my filepath, but now I get this error:

IndexOutOfRangeException: Array index is out of range.
MapGenerator.LoadFile () (at Assets/Resources/Scripts/MapGenerator.js:49)
MapGenerator.OnGUI () (at Assets/Resources/Scripts/MapGenerator.js:29)
System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)

This is because of

if(lineElements[1] == objects[j].ToString)

You are using lineElements[1] without checking if it is null, so if it doesn’t exist you are still trying to access it.
Use an if statement to make sure it exists.

if (lineElements[1] != null) {
    if(lineElements[1] == objects[j].ToString) {
        try {
            Instantiate(objects[j], Vector3(float.Parse(lineElements[2]) * 0.75, float.Parse(lineElements[4]) * 0.75, float.Parse(lineElements[3]) * 0.75), Quaternion.Euler(float.Parse(lineElements[9]), float.Parse(lineElements[11]), float.Parse(lineElements[10])));
        } catch {
            Debug.LogError("Error spawning model");
            // or   Debug.LogError("Error spawning " + objects[j].name);
        }
    }
}

I forgot to edit the file. The first line contained some data for the engine of GTA III.

But I get these errors:

Assets/Resources/Scripts/MapGenerator.js(55,49): BCE0044: expecting }, found 'catch'.

And

Assets/Resources/Scripts/MapGenerator.js(57,108): BCE0044: expecting :, found ';'.

And I’m not sure if the models are loaded, they are 3ds files.

Post the code you have right now, it’s hard to debug with no reference to all the changes you’ve made. lol

Here it is:

import System.IO;

class MapGenerator extends EditorWindow
{    
	var filePath : String;
	var filePathString : String = "D:/My Documents/Games/Simulator +/Map/Data/data/maps/industnw/industnw.ipl";
	var objects : Object[];
	var mapName : String;
	var mapNameString : String = "INDUSTNW";
	
	@MenuItem("Window/GTA Map Generator")
	
	static function Init()
	{
		var window = GetWindow(MapGenerator);
		window.Show();
	}
	
	function OnGUI()
	{
		GUILayout.Label("GTA Map Generator");
		filePath = EditorGUILayout.TextField("File path: ", filePath);
		mapName = EditorGUILayout.TextField("Map name: ", mapName);
		
		objects = Resources.LoadAll("Map/" + mapName);
		
		if(GUILayout.Button("Render"))
		{
			LoadFile();
		}   
    }
    
    function LoadFile()
    {
    	var sr = new StreamReader(filePath);
    	var fileContents = sr.ReadToEnd();
    	sr.Close();
    	
    	var lines = fileContents.Split("\n"[0]);
    	
    	for(var i : int; i < lines.Length; i++)
    	{
    		var lineElements = lines[i].Split(","[0]);
    		
    		for(var j : int; j < objects.Length; j++)
    		{
    			if (lineElements[1] != null)
    			{
					if(lineElements[1] == objects[j].ToString)
					{
						try
						{
							Instantiate(objects[j], Vector3(float.Parse(lineElements[2]) * 0.75, float.Parse(lineElements[4]) * 0.75, float.Parse(lineElements[3]) * 0.75), Quaternion.Euler(float.Parse(lineElements[9]), float.Parse(lineElements[11]), float.Parse(lineElements[10])));
						}
						catch
						{
							Debug.LogError("Error spawning " + objects[j].name);
						}
					}
				}
    		}
    	}
    }
}

Alright, this is cause I don’t know JavaScript. But in JavaScript try catch should have a parameter

This is how it should be set up

try {

} catch (error) {

}

Add the “(error)” and it should work.

If you wish, error could be used to print the exact error message being sent by Unity with
error.Message

Thanks, but now when I press “Render” nothing happens. You can see that it’s loading something, but no objects are added to the scene.

 Instantiate(objects[j], Vector3(float.Parse(lineElements[2]) * 0.75, float.Parse(lineElements[4]) * 0.75, float.Parse(lineElements[3]) * 0.75), Quaternion.Euler(float.Parse(lineElements[9]), float.Parse(lineElements[11]), float.Parse(lineElements[10])));

Is it adding it the hierarchy? or not at all?

So you know, according to your first post you want it scaled by .75, you are multiplying the vector3 position elements by .75 not the scale

Nop, the objects are not added to the hierarchy. Is it because the files are 3ds files? Or are they not loaded?

And because the objects are scaled to .75 I had to convert the position also to .75.

G-Modifications