/// <summary> /// Run this safe method if you want to edit anything on the specific tree instance. /// This will cause the changes to be saved over the chunks and it will be "safe". /// </summary> /// <param name="treeInstance">the tree instance</param> /// <param name="treeInstanceID">The id of the tree instance</param> /// <param name="action">the action</param> public static void RunActionOnTreeInstance(this Terrain terrain, TreeInstance treeInstance, int treeInstanceID, System.Func <TreeInstance, TreeInstance> action, System.Action <Sectors.ChunkObject> runOnChunk) { UNTerrain baseTerrain = terrain.GetComponent <UNTerrain>(); if (baseTerrain != null) { TIChunk chunk = baseTerrain.sector.getChunk(treeInstance.position.LocalToWorld(terrain.terrainData.size, Vector3.zero), 0) as TIChunk; if (chunk != null) { if (action != null) { TreeInstance result = action(treeInstance); if (chunk != null) { for (int i = 0; i < chunk.objects.Count; i++) { if (chunk.objects[i].instanceID == treeInstanceID) { chunk.objects[i].treeInstance = result; // update tree instance if (runOnChunk != null) { runOnChunk(chunk.objects[i]); } break; } } } } } } }
/// <summary> /// Called when the size is changed /// </summary> protected override void OnSizeChanged() { base.OnSizeChanged(); UNTerrain baseTerrain = GetComponentInParent <UNTerrain>(); terrainRelativeSize = size.GetRelativeScale(baseTerrain); }
/// <summary> /// Pack the data and create a data instance /// </summary> public static T2 Pack <T1, T2>(Terrain terrain, int treeInstanceID, int health, PacketType type) where T2 : UNNetworkData <T1> { T2 instance = System.Activator.CreateInstance <T2>(); instance.terrainID = terrain.name; instance.treeInstanceID = treeInstanceID; instance.eventType = type; UNTerrain UNTerrain = terrain.GetComponent <UNTerrain>(); if (instance.minHealth == -1 && instance.maxHealth == -1 && UNTerrain != null) { TreeInstance treeInstance = UNTerrain.terrain.terrainData.GetTreeInstance(treeInstanceID); HarvestableTIPoolItem harvestableComponent = UNTerrain.terrain.terrainData.treePrototypes[treeInstance.prototypeIndex].prefab.GetComponent <HarvestableTIPoolItem>(); if (harvestableComponent != null) { instance.minHealth = harvestableComponent.minHealth; instance.maxHealth = harvestableComponent.maxHealth; } else { harvestableComponent = UNTerrain.Pool.TryGetType <HarvestableTIPoolItem>(); if (harvestableComponent != null) { instance.minHealth = harvestableComponent.minHealth; instance.maxHealth = harvestableComponent.maxHealth; } } } instance.health = health; return(instance); }
/// <summary> /// Get relative to terrain scale. (in order to use terrain's properties) /// </summary> /// <param name="pos"></param> /// <param name="terrain"></param> /// <returns></returns> public static Vector2 GetRelativeScale(this Vector2 scale, UNTerrain terrain) { Vector2 relatedScale = new Vector2(scale.x / (terrain.terrainData.multiThreaded_terrainDataSize.x / terrain.terrainData.multiThreaded_detailWidth), scale.y / (terrain.terrainData.multiThreaded_terrainDataSize.z / terrain.terrainData.multiThreaded_detailHeight)); return(relatedScale); }
/// <summary> /// Convert a tree and assign a Pool item to it. /// </summary> /// <param name="terrain">the terrain.</param> /// <param name="treeInstanceID">the tree instance id</param> /// <param name="UNTerrain">the UN terrain instance</param> public static void ConvertTreeInstance(this Terrain terrain, int treeInstanceID, UNTerrain UNTerrain) { TreeInstance tree = terrain.terrainData.GetTreeInstance(treeInstanceID); Vector3 treeScale = tree.GetWorldScale(); Quaternion treeRotation = tree.GetWorldRotation(); terrain.terrainData.RemoveTreeInstance(treeInstanceID, UNTerrain); Vector3 pos = tree.position.LocalToWorld(terrain.terrainData.size, terrain.transform.position); UNTerrain.Pool.TryResetOnUID(treeInstanceID, true); var item = UNTerrain.Pool.TryPool <HarvestableTIPoolItem>(tree.prototypeIndex, 0, treeInstanceID, true); if (item != null) { item.transform.rotation = treeRotation; item.transform.localScale = treeScale; item.MoveItem(pos); } }
/// <summary> /// Restore a certain tree instance from the terrain. /// </summary> /// <param name="treeInstanceID">the tree instance id of the tree you wish to restore.</param> /// <param name="originalHeight">the original height of the targeted tree.</param> public static void RestoreTreeInstance(this TerrainData terrainData, int treeInstanceID, UNTerrain UNTerrain) { TreeInstance treeInstance = terrainData.GetTreeInstance(treeInstanceID); Sectors.ChunkObject chunkObject; // Update the sector chunk... TIChunk chunk = UNTerrain.sector.getChunk(treeInstance.position.LocalToWorld(UNTerrain.terrainData.multiThreaded_terrainDataSize, Vector3.zero), 0) as TIChunk; if (chunk != null) { for (int i = 0; i < chunk.objects.Count; i++) { chunkObject = chunk.objects[i]; if (chunkObject.instanceID == treeInstanceID) { UNTerrain.Pool.TryResetOnUID(treeInstanceID, true); treeInstance.heightScale = chunkObject.originalHeight; terrainData.SetTreeInstance(treeInstanceID, treeInstance); chunkObject.treeInstance = treeInstance; UNSeeker seeker; for (int c = 0; c < UNSeeker.FReceivers.Count; c++) { seeker = UNSeeker.FReceivers[c] as UNSeeker; Targets.UNTarget.CheckTargets(seeker, seeker.seekingDistance); // check targets to verify colliders assigning } break; } } } }
/// <summary> /// Remove a certain tree instance from the terrain. /// </summary> /// <param name="treeInstanceID">the tree instance id of the tree you wish to remove.</param> public static void RemoveTreeInstance(this TerrainData terrainData, int treeInstanceID, UNTerrain UNTerrain) { TreeInstance _treeInstance = terrainData.GetTreeInstance(treeInstanceID); UNTerrain.terrain.RunActionOnTreeInstance(_treeInstance, treeInstanceID, (TreeInstance treeInstance) => { treeInstance.heightScale = UNTerrain.removedTreeInstanceHeight; terrainData.SetTreeInstance(treeInstanceID, treeInstance); return(treeInstance); }, (Sectors.ChunkObject chunkObject) => { chunkObject.Remove(); }); }
/// <summary> /// Check and assign nearby tree instances. /// </summary> public void CheckForNearbyTreeInstances(UNSeeker seeker, UNTerrain terrain) { if (objects.Count == 0) { return; // no objects found on this specific chunk. } objects.Sort((ChunkObject objA, ChunkObject objB) => { return(Vector2.Distance(objA.depthPosition, seeker.threadPositionDepth).CompareTo(Vector2.Distance(objB.depthPosition, seeker.threadPositionDepth))); }); ChunkObject item; PoolItem PoolItem; ThreadTask <PoolItem, Vector3, TreeInstance> threadTask; for (int b = 0; b < objects.Count; b++) { item = objects[b]; if (Vector2.Distance(item.depthPosition, seeker.threadPositionDepth) > seeker.seekingDistance || item.isRemoved) { continue; // continue if out of distance or if the tree is "removed" } PoolItem = terrain.Pool.TryPool <TerrainPoolItem>(item.prototypeID, UNTerrain.collidersPoolItemInstanceIncrease, item.instanceID, false); // add 1000 at the start to provide a unique symbol. if (PoolItem != null) { threadTask = new ThreadTask <PoolItem, Vector3, TreeInstance>((PoolItem _PoolItem, Vector3 _pos, TreeInstance _item) => { Vector3 scale = _item.GetWorldScale(); Quaternion rotation = _item.GetWorldRotation(); _PoolItem.transform.rotation = rotation; _PoolItem.transform.localScale = scale; _PoolItem.MoveItem(_pos); }, PoolItem, item.worldPosition, item.treeInstance); ThreadManager.instance.RunOnUnityThread(threadTask); } else { if (!terrain.Pool.IsAlreadyPooled(item.instanceID)) { List <PoolItem> PoolItems = terrain.Pool.GetPoolOfItem(item.prototypeID, UNTerrain.collidersPoolItemInstanceIncrease); if (PoolItems.Count > 0) { PoolItems.Sort((PoolItem PoolItemA, PoolItem PoolItemB) => { return(Vector2.Distance(PoolItemA.threadPositionDepth, seeker.threadPositionDepth).CompareTo(Vector2.Distance(PoolItemB.threadPositionDepth, seeker.threadPositionDepth))); }); PoolItem = PoolItems[PoolItems.Count - 1]; terrain.Pool.PoolItem(PoolItem, false, item.instanceID); threadTask = new ThreadTask <PoolItem, Vector3, TreeInstance>((PoolItem _PoolItem, Vector3 _pos, TreeInstance _item) => { Vector3 scale = _item.GetWorldScale(); Quaternion rotation = _item.GetWorldRotation(); _PoolItem.transform.rotation = rotation; _PoolItem.transform.localScale = scale; _PoolItem.MoveItem(_pos); }, PoolItem, item.worldPosition, item.treeInstance); ThreadManager.instance.RunOnUnityThread(threadTask); } } } } }