#if UNITY_EDITOR using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using UnityEditor; using UnityEngine; [CustomEditor(typeof(World))] public class WorldEditor : Editor { public override void OnInspectorGUI() { GUILayout.Label("Server file for a* pathfinding"); if (GUILayout.Button("Generate .mapdata")) { GenerateAStarMapData(World.WORLD_SIZE_X, World.WORLD_SIZE_Y); } GUILayout.Label("Server file for height data"); if (GUILayout.Button("Generate .heightmap")) { generateHeightMap(); } //if (GUILayout.Button("Generate Object Data")) //{ // generateObjectData(); //} //if (GUILayout.Button("Turn All Box Colliders into Mesh Colliders")) //{ // turnAllBoxCollidersIntoMesh(); //} } public void generateHeightMap() { int[] heightData = new int[World.WORLD_SIZE_X * World.WORLD_SIZE_Y]; for (int i = 0; i < World.WORLD_SIZE_Y; i++) { for (int j = 0; j < World.WORLD_SIZE_X; j++) { Vector3 position = new Vector3(j, 0.0f, i); Terrain t = Misc.GetClosestCurrentTerrain(position); float height = t.SampleHeight(position); heightData[i * World.WORLD_SIZE_X + j] = (int)(height * 100); } } using (FileStream fileStream = new FileStream("output/.heightmap", FileMode.Create)) // destiny file directory. { using (BinaryWriter binaryWriter = new BinaryWriter(fileStream)) { byte[] mapWidth = convInt(World.WORLD_SIZE_X); for (int i = 0; i < 4; i++) { fileStream.WriteByte(mapWidth[i]); } byte[] mapHeight = convInt(World.WORLD_SIZE_Y); for (int i = 0; i < 4; i++) { fileStream.WriteByte(mapHeight[i]); } for (int i = 0; i < heightData.Length; i++) { byte[] value = convInt((int)(heightData[i])); for (int j = 0; j < 4; j++) { fileStream.WriteByte(value[j]); } } fileStream.Close(); } //now write the data file //write world collision map to a png file Texture2D texture = new Texture2D(World.WORLD_SIZE_X, World.WORLD_SIZE_Y, TextureFormat.RGB24, false); // create texture2D to store the map in, written to file at the end of the method // set all pixels to black for (int i = 0; i < World.WORLD_SIZE_Y; i++) { for (int j = 0; j < World.WORLD_SIZE_X; j++) { float f = (float)heightData[i * World.WORLD_SIZE_X + j]; Color c = new Color(f / 1000.0f, 0.0f, 0.0f); texture.SetPixel(j, i, c); } } texture.Apply(); byte[] fileData = texture.EncodeToPNG(); System.IO.File.WriteAllBytes("output/heightmap.png", fileData); } } public void GenerateAStarMapData(int width, int height) { Debug.ClearDeveloperConsole(); Debug.Log("Generating A* Path Data..."); RaycastHit[] hits = new RaycastHit[5]; FileStream fileStream = new FileStream("output/.astar", FileMode.Create); byte[] mapWidth = convInt(width); for (int i = 0; i < 4; i++) { fileStream.WriteByte(mapWidth[i]); } byte[] mapHeight = convInt(height); for (int i = 0; i < 4; i++) { fileStream.WriteByte(mapHeight[i]); } for (int z = 0; z < height; z++) { for (int x = 0; x < width; x++) { bool collision = false; Terrain terrain = Misc.GetClosestCurrentTerrain(new Vector3(x, 0, z)); float terrainHeight = terrain.SampleHeight(new Vector3(x, 0, z)) - 0.1f; float startingHeight = terrainHeight + 5.1f; float distance = Mathf.Abs(startingHeight - terrainHeight); Vector3 rayOrigin = new Vector3(x + 0.5f, startingHeight, z + 0.5f); Ray ray = new Ray(rayOrigin, Vector3.down); int ignoredLayers = LayerMask.GetMask("Ignore Raycast", "Water", "BlockPlayer"); int hitCount = Physics.SphereCastNonAlloc(ray.origin, .5f, ray.direction, hits, distance, ~ignoredLayers); if (hitCount > 0) { bool isClosestHitWithObject = false; float closestDistance = float.PositiveInfinity; for (int i = 0; i < hitCount; i++) { if (hits[i].distance < closestDistance) { isClosestHitWithObject = !hits[i].collider.TryGetComponent(out Terrain _); closestDistance = hits[i].distance; } } collision = isClosestHitWithObject; } byte[] value = convInt(collision ? 1 : 0); for (int j = 0; j < 4; j++) { fileStream.WriteByte(value[j]); } } } fileStream.Close(); Debug.Log("Task complete."); } //We don't need this anymore. -Thomas09- I've made a system private void turnAllBoxCollidersIntoMesh() { Debug.ClearDeveloperConsole(); Debug.Log("Converting All Box Colliders into Mesh Colliders"); var gameObjectsWithBoxColliders = FindObjectsOfType(); for (int i = 0; i < gameObjectsWithBoxColliders.Length; i++) { var go = gameObjectsWithBoxColliders[i].gameObject; var meshCollider = go.GetComponent(); //If an existing MeshCollider exists, just Destroy it if (go.GetComponent() != null) { DestroyImmediate(meshCollider); } meshCollider = go.AddComponent(); var meshfilter = go.GetComponent(); if (meshfilter != null) { meshCollider.sharedMesh = meshfilter.sharedMesh; } DestroyImmediate(go.GetComponent()); } } private void generateObjectData() { Debug.ClearDeveloperConsole(); Debug.Log("Generate Object Data..."); //Get All GameObjects in Scene with World Object Type var initialArray_1 = FindObjectsOfType(); //Filter WorldObject gameobjects that has MeshColliders; List initialArray_2 = new List(); for (int i = 0; i < initialArray_1.Length; i++) { var go = initialArray_1[i]; if (go.GetComponent() != null) { initialArray_2.Add(go.gameObject); } } //Get All GameObjects in initialArray_2 with MeshFilter Component List meshAndTransform = new List(); for (int i = 0; i < initialArray_2.Count; i++) { var meshfilter = initialArray_2[i].GetComponent(); if (meshfilter != null) { meshAndTransform.Add(new MeshAndTransform { Mesh = meshfilter.sharedMesh, Transform = meshfilter.transform }); } } List objectsAndTiles = new List(); for (int i = 0; i < meshAndTransform.Count; i++) { List vertices = meshAndTransform[i].Mesh.vertices.ToList(); var transform = meshAndTransform[i].Transform; HashSet overlapHashSet = new HashSet(); for (int j = 0; j < vertices.Count; j++) { var posV3 = transform.TransformPoint(vertices[j]); var posX = posV3.x < 0 ? posV3.x - 1 : posV3.x; var posY = posV3.z < 0 ? posV3.z - 1 : posV3.z; overlapHashSet.Add(new Vector2((int)posX, (int)posY)); } objectsAndTiles.Add(new ObjectsAndTilesData { GameObjectName = transform.gameObject.name, OverlapHashSet = overlapHashSet }); } //Write it to file using (FileStream fileStream = new FileStream("outputTileData.csv", FileMode.Create)) { for (int i = 0; i < objectsAndTiles.Count; i++) { var name = objectsAndTiles[i].GameObjectName; var overlaptiles = objectsAndTiles[i].OverlapHashSet.ToList(); var count = overlaptiles.Count; string cov = name + ", " + count + ", "; for (int j = 0; j < overlaptiles.Count; j++) { cov += overlaptiles[j].ToString(); if (j < overlaptiles.Count - 1) { cov += ", "; } } if (i < objectsAndTiles.Count - 1) { cov += Environment.NewLine; } byte[] covByteArray = Encoding.Default.GetBytes(cov); fileStream.Write(covByteArray, 0, covByteArray.Length); } fileStream.Close(); } Debug.Log("Done! Check the root project folder! There should be a outputTileData.csv there!"); } public byte[] convInt(int i) { byte[] b = new byte[4]; b[3] = (byte)i; b[2] = (byte)(i >> 8); b[1] = (byte)(i >> 16); b[0] = (byte)(i >> 24); return b; } public void generateNavigationHeightmap() { Debug.ClearDeveloperConsole(); Debug.Log("Generating Collision Maps."); //find a reference to terrain for height checking Terrain terrain = GameObject.Find("Terrain").GetComponent(); float[] navigationHeightData = new float[1024 * 1024]; //now loop through all tiles of the game for (int i = 0; i < 1024; i++) { for (int j = 0; j < 1024; j++) { RaycastHit rch; if (Physics.Raycast(new Vector3(j, terrain.SampleHeight(new Vector3(j, 0, i)) + 10.0f, i), new Vector3(0, -1.0f, 0), out rch, 20.0f)) { navigationHeightData[i * 1024 + j] = rch.point.y; } } } //write world collision map to a png file Texture2D texture = new Texture2D(1024, 1024, TextureFormat.RGB24, false); // create texture2D to store the map in, written to file at the end of the method // set all pixels to black for (int i = 0; i < 1024; i++) { for (int j = 0; j < 1024; j++) { Color c = Color.black; c.r = navigationHeightData[i * 1024 + j] / 100.0f; texture.SetPixel(j, i, c); } } texture.Apply(); byte[] fileData = texture.EncodeToPNG(); System.IO.File.WriteAllBytes("NavigationHeightMap.png", fileData); } public void generateCollisionMap() { Debug.ClearDeveloperConsole(); Debug.Log("Generating Collision Maps."); //find a reference to terrain for height checking Terrain terrain;// = GameObject.Find("Terrain").GetComponent(); //create data for the map bool[] collisionMapData = new bool[1024 * 1024]; for (int i = 0; i < collisionMapData.Length; i++) collisionMapData[i] = false; //now loop through all tiles of the game for (int i = 0; i < 1024; i++) { for (int j = 0; j < 1024; j++) { terrain = Misc.GetClosestCurrentTerrain(new Vector3(j, 0, i)); bool collision = false; for (int y = 0; y < 10; y++) { for (int x = 0; x < 10; x++) { float rX = ((float)x / 10) + j + -0.5f; float rZ = ((float)y / 10) + i + -0.5f; float rY = terrain.SampleHeight(new Vector3(rX, 0, rZ)) - 0.05f; Ray ray = new Ray(new Vector3(rX, rY, rZ), new Vector3(0, 1, 0)); RaycastHit rch; if (Physics.Raycast(new Vector3(j, terrain.SampleHeight(new Vector3(j, 0, i)) + 10.0f, i), new Vector3(0, -1.0f, 0), out rch, 20.0f)) //if (Physics.Raycast(ray, 20.5f)) { if (rch.collider.gameObject.GetComponent() == null) { collision = true; } else if (rch.collider.gameObject.GetComponent().canWalkOnTop == false) { collision = true; } } } } if (collision) { collisionMapData[i * 1024 + j] = true; Debug.Log("Collision x:" + j + " y: " + i); } } } //write world collision map to a png file Texture2D texture = new Texture2D(1024, 1024, TextureFormat.RGB24, false); // create texture2D to store the map in, written to file at the end of the method // set all pixels to black for (int i = 0; i < 1024; i++) { for (int j = 0; j < 1024; j++) { Color c = Color.black; if (collisionMapData[i * 1024 + j]) c = Color.red; texture.SetPixel(j, i, c); } } texture.Apply(); byte[] fileData = texture.EncodeToPNG(); System.IO.File.WriteAllBytes("collisionMap.png", fileData); } } #endif