2062 lines
61 KiB
C#
2062 lines
61 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using Gaia.FullSerializer;
|
|
using UnityEngine;
|
|
|
|
namespace Gaia
|
|
{
|
|
[ExecuteInEditMode]
|
|
public class Spawner : MonoBehaviour
|
|
{
|
|
private class SpawnLocation
|
|
{
|
|
public Vector3 m_location;
|
|
|
|
public float m_seedDistance;
|
|
}
|
|
|
|
[fsIgnore]
|
|
public GaiaResource m_resources;
|
|
|
|
public string m_resourcesPath;
|
|
|
|
public string m_spawnerID = Guid.NewGuid().ToString();
|
|
|
|
public GaiaConstants.OperationMode m_mode;
|
|
|
|
public int m_seed = DateTime.Now.Millisecond;
|
|
|
|
public GaiaConstants.SpawnerShape m_spawnerShape;
|
|
|
|
public GaiaConstants.SpawnerRuleSelector m_spawnRuleSelector = GaiaConstants.SpawnerRuleSelector.WeightedFittest;
|
|
|
|
public GaiaConstants.SpawnerLocation m_spawnLocationAlgorithm;
|
|
|
|
public GaiaConstants.SpawnerLocationCheckType m_spawnLocationCheckType;
|
|
|
|
public float m_locationIncrement = 1f;
|
|
|
|
public float m_maxJitteredLocationOffsetPct = 0.9f;
|
|
|
|
public int m_locationChecksPerInt = 1;
|
|
|
|
public int m_maxRandomClusterSize = 50;
|
|
|
|
public float m_spawnRange = 500f;
|
|
|
|
public AnimationCurve m_spawnFitnessAttenuator = new AnimationCurve(new Keyframe(0f, 1f), new Keyframe(1f, 1f));
|
|
|
|
public GaiaConstants.ImageFitnessFilterMode m_areaMaskMode;
|
|
|
|
public bool m_enableColliderCacheAtRuntime;
|
|
|
|
public Texture2D m_imageMask;
|
|
|
|
public bool m_imageMaskInvert;
|
|
|
|
public bool m_imageMaskNormalise;
|
|
|
|
public bool m_imageMaskFlip;
|
|
|
|
public int m_imageMaskSmoothIterations = 3;
|
|
|
|
[fsIgnore]
|
|
public HeightMap m_imageMaskHM;
|
|
|
|
private FractalGenerator m_noiseGenerator;
|
|
|
|
public float m_noiseMaskSeed;
|
|
|
|
public int m_noiseMaskOctaves = 8;
|
|
|
|
public float m_noiseMaskPersistence = 0.25f;
|
|
|
|
public float m_noiseMaskFrequency = 1f;
|
|
|
|
public float m_noiseMaskLacunarity = 1.5f;
|
|
|
|
public float m_noiseZoom = 10f;
|
|
|
|
public bool m_noiseInvert;
|
|
|
|
public float m_spawnInterval = 5f;
|
|
|
|
public string m_triggerTags = "Player";
|
|
|
|
public float m_triggerRange = 130f;
|
|
|
|
public List<SpawnRule> m_spawnerRules = new List<SpawnRule>();
|
|
|
|
public LayerMask m_spawnCollisionLayers;
|
|
|
|
public int m_spawnColliderLayer;
|
|
|
|
public bool m_showGizmos = true;
|
|
|
|
public bool m_showDebug;
|
|
|
|
public bool m_showStatistics = true;
|
|
|
|
public bool m_showTerrainHelper = true;
|
|
|
|
public XorshiftPlus m_rndGenerator;
|
|
|
|
private bool m_cacheDetails;
|
|
|
|
private Dictionary<int, List<HeightMap>> m_detailMapCache = new Dictionary<int, List<HeightMap>>();
|
|
|
|
private bool m_cacheTextures;
|
|
|
|
private bool m_textureMapsDirty;
|
|
|
|
private Dictionary<int, List<HeightMap>> m_textureMapCache = new Dictionary<int, List<HeightMap>>();
|
|
|
|
private bool m_cacheTags;
|
|
|
|
private Dictionary<string, Quadtree<GameObject>> m_taggedGameObjectCache = new Dictionary<string, Quadtree<GameObject>>();
|
|
|
|
public TreeManager m_treeCache = new TreeManager();
|
|
|
|
private bool m_cacheHeightMaps;
|
|
|
|
private bool m_heightMapDirty;
|
|
|
|
private Dictionary<int, UnityHeightMap> m_heightMapCache = new Dictionary<int, UnityHeightMap>();
|
|
|
|
private Dictionary<string, HeightMap> m_stampCache = new Dictionary<string, HeightMap>();
|
|
|
|
[fsIgnore]
|
|
public GameObject m_areaBoundsColliderCache;
|
|
|
|
[fsIgnore]
|
|
public GameObject m_goColliderCache;
|
|
|
|
[fsIgnore]
|
|
public GameObject m_goParentGameObject;
|
|
|
|
private bool m_cancelSpawn;
|
|
|
|
public int m_totalRuleCnt;
|
|
|
|
public int m_activeRuleCnt;
|
|
|
|
public int m_inactiveRuleCnt;
|
|
|
|
public ulong m_maxInstanceCnt;
|
|
|
|
public ulong m_activeInstanceCnt;
|
|
|
|
public ulong m_inactiveInstanceCnt;
|
|
|
|
public ulong m_totalInstanceCnt;
|
|
|
|
private float m_terrainHeight;
|
|
|
|
private float m_checkDistance;
|
|
|
|
private RaycastHit m_checkHitInfo;
|
|
|
|
public IEnumerator m_updateCoroutine;
|
|
|
|
public float m_updateTimeAllowed = 1f / 30f;
|
|
|
|
public float m_spawnProgress;
|
|
|
|
public bool m_spawnComplete = true;
|
|
|
|
public Bounds m_spawnerBounds;
|
|
|
|
private bool m_isTextureSpawner;
|
|
|
|
private bool m_isDetailSpawner;
|
|
|
|
private bool m_isTreeSpawnwer;
|
|
|
|
private bool m_isGameObjectSpawner;
|
|
|
|
private void OnEnable()
|
|
{
|
|
if (m_spawnCollisionLayers.value == 0)
|
|
{
|
|
m_spawnCollisionLayers = TerrainHelper.GetActiveTerrainLayer();
|
|
}
|
|
m_spawnColliderLayer = TerrainHelper.GetActiveTerrainLayerAsInt();
|
|
if (m_rndGenerator == null)
|
|
{
|
|
m_rndGenerator = new XorshiftPlus(m_seed);
|
|
}
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
}
|
|
|
|
public void StartEditorUpdates()
|
|
{
|
|
}
|
|
|
|
public void StopEditorUpdates()
|
|
{
|
|
}
|
|
|
|
private void EditorUpdate()
|
|
{
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
if (Application.isPlaying)
|
|
{
|
|
Transform transform = base.transform.Find("Bounds_ColliderCache");
|
|
if (transform != null)
|
|
{
|
|
m_areaBoundsColliderCache = transform.gameObject;
|
|
m_areaBoundsColliderCache.SetActive(value: false);
|
|
}
|
|
if (!m_enableColliderCacheAtRuntime)
|
|
{
|
|
transform = base.transform.Find("GameObject_ColliderCache");
|
|
if (transform != null)
|
|
{
|
|
m_goColliderCache = transform.gameObject;
|
|
m_goColliderCache.SetActive(value: false);
|
|
}
|
|
}
|
|
}
|
|
if (m_mode == GaiaConstants.OperationMode.RuntimeInterval || m_mode == GaiaConstants.OperationMode.RuntimeTriggeredInterval)
|
|
{
|
|
Initialise();
|
|
InvokeRepeating("RunSpawnerIteration", 1f, m_spawnInterval);
|
|
}
|
|
}
|
|
|
|
public void Initialise()
|
|
{
|
|
if (m_showDebug)
|
|
{
|
|
Debug.Log("Initialising spawner");
|
|
}
|
|
m_spawnColliderLayer = TerrainHelper.GetActiveTerrainLayerAsInt();
|
|
List<Transform> list = new List<Transform>();
|
|
foreach (Transform item in base.transform)
|
|
{
|
|
list.Add(item);
|
|
}
|
|
foreach (Transform item2 in list)
|
|
{
|
|
if (Application.isPlaying)
|
|
{
|
|
UnityEngine.Object.Destroy(item2.gameObject);
|
|
}
|
|
else
|
|
{
|
|
UnityEngine.Object.DestroyImmediate(item2.gameObject);
|
|
}
|
|
}
|
|
SetUpSpawnerTypeFlags();
|
|
if (IsGameObjectSpawner())
|
|
{
|
|
m_goParentGameObject = new GameObject("Spawned_GameObjects");
|
|
m_goParentGameObject.transform.parent = base.transform;
|
|
m_areaBoundsColliderCache = new GameObject("Bounds_ColliderCache");
|
|
m_areaBoundsColliderCache.transform.parent = base.transform;
|
|
m_goColliderCache = new GameObject("GameObject_ColliderCache");
|
|
m_goColliderCache.transform.parent = base.transform;
|
|
}
|
|
ResetRandomGenertor();
|
|
Terrain terrain = TerrainHelper.GetTerrain(base.transform.position);
|
|
if (terrain != null)
|
|
{
|
|
m_terrainHeight = terrain.terrainData.size.y;
|
|
}
|
|
m_spawnerBounds = new Bounds(base.transform.position, new Vector3(m_spawnRange * 2f, m_spawnRange * 2f, m_spawnRange * 2f));
|
|
foreach (SpawnRule spawnerRule in m_spawnerRules)
|
|
{
|
|
spawnerRule.m_currInstanceCnt = 0uL;
|
|
spawnerRule.m_activeInstanceCnt = 0uL;
|
|
spawnerRule.m_inactiveInstanceCnt = 0uL;
|
|
}
|
|
UpdateCounters();
|
|
}
|
|
|
|
private void PreSpawnInitialise()
|
|
{
|
|
m_spawnerBounds = new Bounds(base.transform.position, new Vector3(m_spawnRange * 2f, m_spawnRange * 2f, m_spawnRange * 2f));
|
|
if (m_rndGenerator == null)
|
|
{
|
|
ResetRandomGenertor();
|
|
}
|
|
m_spawnColliderLayer = TerrainHelper.GetActiveTerrainLayerAsInt();
|
|
SetUpSpawnerTypeFlags();
|
|
if (IsGameObjectSpawner())
|
|
{
|
|
if (base.transform.Find("Spawned_GameObjects") == null)
|
|
{
|
|
m_goParentGameObject = new GameObject("Spawned_GameObjects");
|
|
m_goParentGameObject.transform.parent = base.transform;
|
|
}
|
|
if (base.transform.Find("Bounds_ColliderCache") == null)
|
|
{
|
|
m_areaBoundsColliderCache = new GameObject("Bounds_ColliderCache");
|
|
m_areaBoundsColliderCache.transform.parent = base.transform;
|
|
}
|
|
if (base.transform.Find("GameObject_ColliderCache") == null)
|
|
{
|
|
m_goColliderCache = new GameObject("GameObject_ColliderCache");
|
|
m_goColliderCache.transform.parent = base.transform;
|
|
}
|
|
}
|
|
foreach (SpawnRule spawnerRule in m_spawnerRules)
|
|
{
|
|
spawnerRule.Initialise(this);
|
|
}
|
|
if (m_areaMaskMode == GaiaConstants.ImageFitnessFilterMode.PerlinNoise)
|
|
{
|
|
m_noiseGenerator = new FractalGenerator(m_noiseMaskFrequency, m_noiseMaskLacunarity, m_noiseMaskOctaves, m_noiseMaskPersistence, m_noiseMaskSeed, FractalGenerator.Fractals.Perlin);
|
|
}
|
|
else if (m_areaMaskMode == GaiaConstants.ImageFitnessFilterMode.BillowNoise)
|
|
{
|
|
m_noiseGenerator = new FractalGenerator(m_noiseMaskFrequency, m_noiseMaskLacunarity, m_noiseMaskOctaves, m_noiseMaskPersistence, m_noiseMaskSeed, FractalGenerator.Fractals.Billow);
|
|
}
|
|
else if (m_areaMaskMode == GaiaConstants.ImageFitnessFilterMode.RidgedNoise)
|
|
{
|
|
m_noiseGenerator = new FractalGenerator(m_noiseMaskFrequency, m_noiseMaskLacunarity, m_noiseMaskOctaves, m_noiseMaskPersistence, m_noiseMaskSeed, FractalGenerator.Fractals.RidgeMulti);
|
|
}
|
|
UpdateCounters();
|
|
}
|
|
|
|
public void SetUpSpawnerTypeFlags()
|
|
{
|
|
m_isDetailSpawner = false;
|
|
for (int i = 0; i < m_spawnerRules.Count; i++)
|
|
{
|
|
if (m_spawnerRules[i].m_resourceType == GaiaConstants.SpawnerResourceType.TerrainDetail)
|
|
{
|
|
m_isDetailSpawner = true;
|
|
break;
|
|
}
|
|
}
|
|
m_isTextureSpawner = false;
|
|
for (int j = 0; j < m_spawnerRules.Count; j++)
|
|
{
|
|
if (m_spawnerRules[j].m_resourceType == GaiaConstants.SpawnerResourceType.TerrainTexture)
|
|
{
|
|
m_isTextureSpawner = true;
|
|
break;
|
|
}
|
|
}
|
|
for (int k = 0; k < m_spawnerRules.Count; k++)
|
|
{
|
|
if (m_spawnerRules[k].m_resourceType == GaiaConstants.SpawnerResourceType.TerrainTree)
|
|
{
|
|
m_isTreeSpawnwer = true;
|
|
break;
|
|
}
|
|
}
|
|
m_isGameObjectSpawner = false;
|
|
for (int l = 0; l < m_spawnerRules.Count; l++)
|
|
{
|
|
if (m_spawnerRules[l].m_resourceType == GaiaConstants.SpawnerResourceType.GameObject)
|
|
{
|
|
m_isGameObjectSpawner = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void AssociateAssets()
|
|
{
|
|
if (m_resources != null)
|
|
{
|
|
m_resources.AssociateAssets();
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning("Could not associated assets for " + base.name + " - resources file was missing");
|
|
}
|
|
}
|
|
|
|
public int[] GetMissingResources()
|
|
{
|
|
List<int> list = new List<int>();
|
|
for (int i = 0; i < m_spawnerRules.Count; i++)
|
|
{
|
|
if (m_spawnerRules[i].m_isActive && !m_spawnerRules[i].ResourceIsLoadedInTerrain(this))
|
|
{
|
|
list.Add(i);
|
|
}
|
|
}
|
|
return list.ToArray();
|
|
}
|
|
|
|
public void AddResourcesToTerrain(int[] rules)
|
|
{
|
|
for (int i = 0; i < rules.GetLength(0); i++)
|
|
{
|
|
if (!m_spawnerRules[rules[i]].ResourceIsLoadedInTerrain(this))
|
|
{
|
|
m_spawnerRules[rules[i]].AddResourceToTerrain(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void PostSpawn()
|
|
{
|
|
m_spawnProgress = 0f;
|
|
m_spawnComplete = true;
|
|
m_updateCoroutine = null;
|
|
UpdateCounters();
|
|
}
|
|
|
|
public bool IsTextureSpawner()
|
|
{
|
|
return m_isTextureSpawner;
|
|
}
|
|
|
|
public bool IsDetailSpawner()
|
|
{
|
|
return m_isDetailSpawner;
|
|
}
|
|
|
|
public bool IsTreeSpawner()
|
|
{
|
|
return m_isTreeSpawnwer;
|
|
}
|
|
|
|
public bool IsGameObjectSpawner()
|
|
{
|
|
return m_isGameObjectSpawner;
|
|
}
|
|
|
|
public void ResetSpawner()
|
|
{
|
|
Initialise();
|
|
}
|
|
|
|
public void CancelSpawn()
|
|
{
|
|
m_cancelSpawn = true;
|
|
m_spawnProgress = 0f;
|
|
}
|
|
|
|
public bool IsSpawning()
|
|
{
|
|
return !m_spawnComplete;
|
|
}
|
|
|
|
private bool CanSpawnInstances()
|
|
{
|
|
bool result = false;
|
|
for (int i = 0; i < m_spawnerRules.Count; i++)
|
|
{
|
|
SpawnRule spawnRule = m_spawnerRules[i];
|
|
if (spawnRule.m_isActive)
|
|
{
|
|
if (spawnRule.m_ignoreMaxInstances)
|
|
{
|
|
return true;
|
|
}
|
|
if (spawnRule.m_activeInstanceCnt < spawnRule.m_maxInstances)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public void RunSpawnerIteration()
|
|
{
|
|
m_cancelSpawn = false;
|
|
m_spawnComplete = false;
|
|
PreSpawnInitialise();
|
|
if (m_activeRuleCnt <= 0)
|
|
{
|
|
if (m_showDebug)
|
|
{
|
|
Debug.Log($"{base.gameObject.name}: There are no active spawn rules. Can't spawn without rules.");
|
|
}
|
|
m_spawnComplete = true;
|
|
return;
|
|
}
|
|
if (!CanSpawnInstances())
|
|
{
|
|
if (m_showDebug)
|
|
{
|
|
Debug.Log($"{base.gameObject.name}: Can't spawn or activate new instance - max instance count reached.");
|
|
}
|
|
m_spawnComplete = true;
|
|
return;
|
|
}
|
|
Terrain terrain = TerrainHelper.GetTerrain(base.transform.position);
|
|
if (terrain != null)
|
|
{
|
|
m_terrainHeight = terrain.terrainData.size.y;
|
|
if (m_resources != null && m_resources.m_terrainHeight != m_terrainHeight)
|
|
{
|
|
Debug.LogWarning($"There is a mismatch between your resources Terrain Height {m_resources.m_terrainHeight} and your actual Terrain Height {m_terrainHeight}. Your Spawn may not work as intended!");
|
|
}
|
|
}
|
|
if (m_mode == GaiaConstants.OperationMode.RuntimeTriggeredInterval)
|
|
{
|
|
m_checkDistance = m_triggerRange + 1f;
|
|
List<GameObject> list = new List<GameObject>();
|
|
string[] array = new string[0];
|
|
if (!string.IsNullOrEmpty(m_triggerTags))
|
|
{
|
|
array = m_triggerTags.Split(',');
|
|
}
|
|
else
|
|
{
|
|
Debug.LogError("You have not supplied a trigger tag. Spawner will not spawn!");
|
|
}
|
|
int num = 0;
|
|
if (m_triggerTags.Length <= 0 || array.Length == 0)
|
|
{
|
|
if (m_showDebug)
|
|
{
|
|
Debug.Log($"{base.gameObject.name}: No triggers found");
|
|
}
|
|
m_spawnComplete = true;
|
|
return;
|
|
}
|
|
for (num = 0; num < array.Length; num++)
|
|
{
|
|
list.AddRange(GameObject.FindGameObjectsWithTag(array[num]));
|
|
}
|
|
for (num = 0; num < list.Count; num++)
|
|
{
|
|
m_checkDistance = Vector3.Distance(base.transform.position, list[num].transform.position);
|
|
if (m_checkDistance <= m_triggerRange)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (m_checkDistance > m_triggerRange)
|
|
{
|
|
if (m_showDebug)
|
|
{
|
|
Debug.Log($"{base.gameObject.name}: No triggers were close enough");
|
|
}
|
|
m_spawnComplete = true;
|
|
return;
|
|
}
|
|
}
|
|
if (!Application.isPlaying)
|
|
{
|
|
AddToSession(GaiaOperation.OperationType.Spawn, "Spawning " + base.transform.name);
|
|
}
|
|
if (m_spawnLocationAlgorithm == GaiaConstants.SpawnerLocation.RandomLocation || m_spawnLocationAlgorithm == GaiaConstants.SpawnerLocation.RandomLocationClustered)
|
|
{
|
|
StartCoroutine(RunRandomSpawnerIteration());
|
|
}
|
|
else
|
|
{
|
|
StartCoroutine(RunAreaSpawnerIteration());
|
|
}
|
|
}
|
|
|
|
public IEnumerator RunRandomSpawnerIteration()
|
|
{
|
|
if (m_showDebug)
|
|
{
|
|
Debug.Log($"{base.gameObject.name}: Running random iteration");
|
|
}
|
|
SpawnInfo spawnInfo = new SpawnInfo();
|
|
List<SpawnLocation> spawnLocations = new List<SpawnLocation>();
|
|
int spawnLocationsIdx = 0;
|
|
int failedSpawns = 0;
|
|
m_spawnProgress = 0f;
|
|
m_spawnComplete = false;
|
|
float currentTime = Time.realtimeSinceStartup;
|
|
float accumulatedTime = 0f;
|
|
spawnInfo.m_textureStrengths = new float[Terrain.activeTerrain.terrainData.alphamapLayers];
|
|
CreateSpawnCaches();
|
|
LoadImageMask();
|
|
for (int checks = 0; checks < m_locationChecksPerInt; checks++)
|
|
{
|
|
SpawnLocation spawnLocation = new SpawnLocation();
|
|
if (m_spawnLocationAlgorithm == GaiaConstants.SpawnerLocation.RandomLocation)
|
|
{
|
|
spawnLocation.m_location = GetRandomV3(m_spawnRange);
|
|
spawnLocation.m_location = base.transform.position + spawnLocation.m_location;
|
|
}
|
|
else if (spawnLocations.Count == 0 || spawnLocations.Count > m_maxRandomClusterSize || failedSpawns > m_maxRandomClusterSize)
|
|
{
|
|
spawnLocation.m_location = GetRandomV3(m_spawnRange);
|
|
spawnLocation.m_location = base.transform.position + spawnLocation.m_location;
|
|
failedSpawns = 0;
|
|
spawnLocationsIdx = 0;
|
|
spawnLocations.Clear();
|
|
}
|
|
else
|
|
{
|
|
if (spawnLocationsIdx >= spawnLocations.Count)
|
|
{
|
|
spawnLocationsIdx = 0;
|
|
}
|
|
spawnLocation.m_location = GetRandomV3(spawnLocations[spawnLocationsIdx].m_seedDistance);
|
|
spawnLocation.m_location = spawnLocations[spawnLocationsIdx++].m_location + spawnLocation.m_location;
|
|
}
|
|
if (CheckLocation(spawnLocation.m_location, ref spawnInfo))
|
|
{
|
|
if (m_spawnRuleSelector == GaiaConstants.SpawnerRuleSelector.All)
|
|
{
|
|
for (int i = 0; i < m_spawnerRules.Count; i++)
|
|
{
|
|
SpawnRule rule = m_spawnerRules[i];
|
|
spawnInfo.m_fitness = rule.GetFitness(ref spawnInfo);
|
|
if (TryExecuteRule(ref rule, ref spawnInfo))
|
|
{
|
|
failedSpawns = 0;
|
|
spawnLocation.m_seedDistance = rule.GetSeedThrowRange(ref spawnInfo);
|
|
spawnLocations.Add(spawnLocation);
|
|
}
|
|
else
|
|
{
|
|
failedSpawns++;
|
|
}
|
|
}
|
|
}
|
|
else if (m_spawnRuleSelector == GaiaConstants.SpawnerRuleSelector.Random)
|
|
{
|
|
SpawnRule rule = m_spawnerRules[GetRandomInt(0, m_spawnerRules.Count - 1)];
|
|
spawnInfo.m_fitness = rule.GetFitness(ref spawnInfo);
|
|
if (TryExecuteRule(ref rule, ref spawnInfo))
|
|
{
|
|
failedSpawns = 0;
|
|
spawnLocation.m_seedDistance = rule.GetSeedThrowRange(ref spawnInfo);
|
|
spawnLocations.Add(spawnLocation);
|
|
}
|
|
else
|
|
{
|
|
failedSpawns++;
|
|
}
|
|
}
|
|
else if (m_spawnRuleSelector == GaiaConstants.SpawnerRuleSelector.Fittest)
|
|
{
|
|
SpawnRule rule2 = null;
|
|
float num = 0f;
|
|
for (int i = 0; i < m_spawnerRules.Count; i++)
|
|
{
|
|
SpawnRule rule = m_spawnerRules[i];
|
|
float fitness = rule.GetFitness(ref spawnInfo);
|
|
if (fitness > num)
|
|
{
|
|
num = fitness;
|
|
rule2 = rule;
|
|
}
|
|
else if (GaiaUtils.Math_ApproximatelyEqual(fitness, num, 0.005f) && GetRandomFloat(0f, 1f) > 0.5f)
|
|
{
|
|
num = fitness;
|
|
rule2 = rule;
|
|
}
|
|
}
|
|
spawnInfo.m_fitness = num;
|
|
if (TryExecuteRule(ref rule2, ref spawnInfo))
|
|
{
|
|
failedSpawns = 0;
|
|
spawnLocation.m_seedDistance = rule2.GetSeedThrowRange(ref spawnInfo);
|
|
spawnLocations.Add(spawnLocation);
|
|
}
|
|
else
|
|
{
|
|
failedSpawns++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SpawnRule rule3;
|
|
SpawnRule rule2 = (rule3 = null);
|
|
float fitness2;
|
|
float num = (fitness2 = 0f);
|
|
for (int i = 0; i < m_spawnerRules.Count; i++)
|
|
{
|
|
SpawnRule rule = m_spawnerRules[i];
|
|
float fitness = rule.GetFitness(ref spawnInfo);
|
|
if (GetRandomFloat(0f, 1f) < fitness)
|
|
{
|
|
rule3 = rule;
|
|
fitness2 = fitness;
|
|
}
|
|
if (fitness > num)
|
|
{
|
|
rule2 = rule;
|
|
num = fitness;
|
|
}
|
|
}
|
|
if (rule3 == null)
|
|
{
|
|
rule3 = rule2;
|
|
fitness2 = num;
|
|
}
|
|
if (rule3 != null)
|
|
{
|
|
spawnInfo.m_fitness = fitness2;
|
|
if (TryExecuteRule(ref rule3, ref spawnInfo))
|
|
{
|
|
failedSpawns = 0;
|
|
spawnLocation.m_seedDistance = rule3.GetSeedThrowRange(ref spawnInfo);
|
|
spawnLocations.Add(spawnLocation);
|
|
}
|
|
else
|
|
{
|
|
failedSpawns++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
m_spawnProgress = (float)checks / (float)m_locationChecksPerInt;
|
|
float realtimeSinceStartup = Time.realtimeSinceStartup;
|
|
float num2 = realtimeSinceStartup - currentTime;
|
|
currentTime = realtimeSinceStartup;
|
|
accumulatedTime += num2;
|
|
if (accumulatedTime > m_updateTimeAllowed)
|
|
{
|
|
accumulatedTime = 0f;
|
|
yield return null;
|
|
}
|
|
if (!CanSpawnInstances() || m_cancelSpawn)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
DeleteSpawnCaches();
|
|
PostSpawn();
|
|
}
|
|
|
|
public IEnumerator RunAreaSpawnerIteration()
|
|
{
|
|
if (m_showDebug)
|
|
{
|
|
Debug.Log($"{base.gameObject.name}: Running area iteration");
|
|
}
|
|
SpawnInfo spawnInfo = new SpawnInfo();
|
|
Vector3 locationWU = default(Vector3);
|
|
m_spawnProgress = 0f;
|
|
m_spawnComplete = false;
|
|
float currentTime = Time.realtimeSinceStartup;
|
|
float accumulatedTime = 0f;
|
|
CreateSpawnCaches();
|
|
LoadImageMask();
|
|
spawnInfo.m_textureStrengths = new float[Terrain.activeTerrain.terrainData.alphamapLayers];
|
|
float num = base.transform.position.x - m_spawnRange + m_locationIncrement / 2f;
|
|
float xWUMax = num + m_spawnRange * 2f;
|
|
float yMid = base.transform.position.y;
|
|
float zWUMin = base.transform.position.z - m_spawnRange + m_locationIncrement / 2f;
|
|
float zWUMax = zWUMin + m_spawnRange * 2f;
|
|
float jitMin = -1f * m_maxJitteredLocationOffsetPct * m_locationIncrement;
|
|
float jitMax = 1f * m_maxJitteredLocationOffsetPct * m_locationIncrement;
|
|
long currChecks = 0L;
|
|
long totalChecks = (long)((xWUMax - num) / m_locationIncrement * ((zWUMax - zWUMin) / m_locationIncrement));
|
|
for (float xWU = num; xWU < xWUMax; xWU += m_locationIncrement)
|
|
{
|
|
for (float zWU = zWUMin; zWU < zWUMax; zWU += m_locationIncrement)
|
|
{
|
|
currChecks++;
|
|
locationWU.x = xWU;
|
|
locationWU.y = yMid;
|
|
locationWU.z = zWU;
|
|
if (m_spawnLocationAlgorithm == GaiaConstants.SpawnerLocation.EveryLocationJittered)
|
|
{
|
|
locationWU.x += GetRandomFloat(jitMin, jitMax);
|
|
locationWU.z += GetRandomFloat(jitMin, jitMax);
|
|
}
|
|
if (CheckLocation(locationWU, ref spawnInfo))
|
|
{
|
|
if (m_spawnRuleSelector == GaiaConstants.SpawnerRuleSelector.All)
|
|
{
|
|
for (int i = 0; i < m_spawnerRules.Count; i++)
|
|
{
|
|
SpawnRule rule = m_spawnerRules[i];
|
|
spawnInfo.m_fitness = rule.GetFitness(ref spawnInfo);
|
|
TryExecuteRule(ref rule, ref spawnInfo);
|
|
}
|
|
}
|
|
else if (m_spawnRuleSelector == GaiaConstants.SpawnerRuleSelector.Random)
|
|
{
|
|
int i = GetRandomInt(0, m_spawnerRules.Count - 1);
|
|
SpawnRule rule = m_spawnerRules[i];
|
|
spawnInfo.m_fitness = rule.GetFitness(ref spawnInfo);
|
|
TryExecuteRule(ref rule, ref spawnInfo);
|
|
}
|
|
else if (m_spawnRuleSelector == GaiaConstants.SpawnerRuleSelector.Fittest)
|
|
{
|
|
SpawnRule rule2 = null;
|
|
float num2 = 0f;
|
|
for (int i = 0; i < m_spawnerRules.Count; i++)
|
|
{
|
|
SpawnRule rule = m_spawnerRules[i];
|
|
float fitness = rule.GetFitness(ref spawnInfo);
|
|
if (fitness > num2)
|
|
{
|
|
num2 = fitness;
|
|
rule2 = rule;
|
|
}
|
|
else if (GaiaUtils.Math_ApproximatelyEqual(fitness, num2, 0.005f) && GetRandomFloat(0f, 1f) > 0.5f)
|
|
{
|
|
num2 = fitness;
|
|
rule2 = rule;
|
|
}
|
|
}
|
|
spawnInfo.m_fitness = num2;
|
|
TryExecuteRule(ref rule2, ref spawnInfo);
|
|
}
|
|
else
|
|
{
|
|
SpawnRule rule3;
|
|
SpawnRule rule2 = (rule3 = null);
|
|
float fitness2;
|
|
float num2 = (fitness2 = 0f);
|
|
for (int i = 0; i < m_spawnerRules.Count; i++)
|
|
{
|
|
SpawnRule rule = m_spawnerRules[i];
|
|
float fitness = rule.GetFitness(ref spawnInfo);
|
|
if (GetRandomFloat(0f, 1f) < fitness)
|
|
{
|
|
rule3 = rule;
|
|
fitness2 = fitness;
|
|
}
|
|
if (fitness > num2)
|
|
{
|
|
rule2 = rule;
|
|
num2 = fitness;
|
|
}
|
|
}
|
|
if (rule3 == null)
|
|
{
|
|
rule3 = rule2;
|
|
fitness2 = num2;
|
|
}
|
|
if (rule3 != null)
|
|
{
|
|
spawnInfo.m_fitness = fitness2;
|
|
TryExecuteRule(ref rule3, ref spawnInfo);
|
|
}
|
|
}
|
|
if (m_textureMapsDirty)
|
|
{
|
|
List<HeightMap> textureMaps = spawnInfo.m_spawner.GetTextureMaps(spawnInfo.m_hitTerrain.GetInstanceID());
|
|
if (textureMaps != null)
|
|
{
|
|
for (int j = 0; j < spawnInfo.m_textureStrengths.Length; j++)
|
|
{
|
|
textureMaps[j][spawnInfo.m_hitLocationNU.z, spawnInfo.m_hitLocationNU.x] = spawnInfo.m_textureStrengths[j];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
m_spawnProgress = (float)currChecks / (float)totalChecks;
|
|
float realtimeSinceStartup = Time.realtimeSinceStartup;
|
|
float num3 = realtimeSinceStartup - currentTime;
|
|
currentTime = realtimeSinceStartup;
|
|
accumulatedTime += num3;
|
|
if (accumulatedTime > m_updateTimeAllowed)
|
|
{
|
|
accumulatedTime = 0f;
|
|
yield return null;
|
|
}
|
|
if (!CanSpawnInstances() || m_cancelSpawn)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
DeleteSpawnCaches(flushDirty: true);
|
|
PostSpawn();
|
|
}
|
|
|
|
public void GroundToTerrain()
|
|
{
|
|
Terrain terrain = TerrainHelper.GetTerrain(base.transform.position);
|
|
if (terrain == null)
|
|
{
|
|
terrain = Terrain.activeTerrain;
|
|
}
|
|
if (terrain == null)
|
|
{
|
|
Debug.LogError("Could not fit to terrain - no terrain present");
|
|
return;
|
|
}
|
|
Bounds bounds = default(Bounds);
|
|
if (TerrainHelper.GetTerrainBounds(terrain, ref bounds))
|
|
{
|
|
base.transform.position = new Vector3(base.transform.position.x, terrain.transform.position.y, base.transform.position.z);
|
|
}
|
|
}
|
|
|
|
public void FitToTerrain()
|
|
{
|
|
Terrain terrain = TerrainHelper.GetTerrain(base.transform.position);
|
|
if (terrain == null)
|
|
{
|
|
terrain = Terrain.activeTerrain;
|
|
}
|
|
if (terrain == null)
|
|
{
|
|
Debug.LogError("Could not fit to terrain - no terrain present");
|
|
return;
|
|
}
|
|
Bounds bounds = default(Bounds);
|
|
if (TerrainHelper.GetTerrainBounds(terrain, ref bounds))
|
|
{
|
|
base.transform.position = new Vector3(bounds.center.x, terrain.transform.position.y, bounds.center.z);
|
|
m_spawnRange = bounds.extents.x;
|
|
}
|
|
}
|
|
|
|
public bool IsFitToTerrain()
|
|
{
|
|
Terrain terrain = TerrainHelper.GetTerrain(base.transform.position);
|
|
if (terrain == null)
|
|
{
|
|
terrain = Terrain.activeTerrain;
|
|
}
|
|
if (terrain == null)
|
|
{
|
|
Debug.LogError("Could not check if fit to terrain - no terrain present");
|
|
return false;
|
|
}
|
|
Bounds bounds = default(Bounds);
|
|
if (TerrainHelper.GetTerrainBounds(terrain, ref bounds))
|
|
{
|
|
if (bounds.center.x != base.transform.position.x || bounds.center.z != base.transform.position.z || bounds.extents.x != m_spawnRange)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public bool LoadImageMask()
|
|
{
|
|
m_imageMaskHM = null;
|
|
if (m_areaMaskMode == GaiaConstants.ImageFitnessFilterMode.None || m_areaMaskMode == GaiaConstants.ImageFitnessFilterMode.PerlinNoise)
|
|
{
|
|
return false;
|
|
}
|
|
if (m_areaMaskMode == GaiaConstants.ImageFitnessFilterMode.ImageRedChannel || m_areaMaskMode == GaiaConstants.ImageFitnessFilterMode.ImageGreenChannel || m_areaMaskMode == GaiaConstants.ImageFitnessFilterMode.ImageBlueChannel || m_areaMaskMode == GaiaConstants.ImageFitnessFilterMode.ImageAlphaChannel || m_areaMaskMode == GaiaConstants.ImageFitnessFilterMode.ImageGreyScale)
|
|
{
|
|
if (m_imageMask == null)
|
|
{
|
|
Debug.LogError("You requested an image mask but did not supply one. Please select mask texture.");
|
|
return false;
|
|
}
|
|
GaiaUtils.MakeTextureReadable(m_imageMask);
|
|
GaiaUtils.MakeTextureUncompressed(m_imageMask);
|
|
m_imageMaskHM = new HeightMap(m_imageMask.width, m_imageMask.height);
|
|
for (int i = 0; i < m_imageMaskHM.Width(); i++)
|
|
{
|
|
for (int j = 0; j < m_imageMaskHM.Depth(); j++)
|
|
{
|
|
switch (m_areaMaskMode)
|
|
{
|
|
case GaiaConstants.ImageFitnessFilterMode.ImageGreyScale:
|
|
m_imageMaskHM[i, j] = m_imageMask.GetPixel(i, j).grayscale;
|
|
break;
|
|
case GaiaConstants.ImageFitnessFilterMode.ImageRedChannel:
|
|
m_imageMaskHM[i, j] = m_imageMask.GetPixel(i, j).r;
|
|
break;
|
|
case GaiaConstants.ImageFitnessFilterMode.ImageGreenChannel:
|
|
m_imageMaskHM[i, j] = m_imageMask.GetPixel(i, j).g;
|
|
break;
|
|
case GaiaConstants.ImageFitnessFilterMode.ImageBlueChannel:
|
|
m_imageMaskHM[i, j] = m_imageMask.GetPixel(i, j).b;
|
|
break;
|
|
case GaiaConstants.ImageFitnessFilterMode.ImageAlphaChannel:
|
|
m_imageMaskHM[i, j] = m_imageMask.GetPixel(i, j).a;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Terrain.activeTerrain == null)
|
|
{
|
|
Debug.LogError("You requested an terrain texture mask but there is no active terrain.");
|
|
return false;
|
|
}
|
|
Terrain activeTerrain = Terrain.activeTerrain;
|
|
GaiaSplatPrototype[] gaiaSplatPrototypes = GaiaSplatPrototype.GetGaiaSplatPrototypes(activeTerrain);
|
|
switch (m_areaMaskMode)
|
|
{
|
|
case GaiaConstants.ImageFitnessFilterMode.TerrainTexture0:
|
|
if (gaiaSplatPrototypes.Length < 1)
|
|
{
|
|
Debug.LogError("You requested an terrain texture mask 0 but there is no active texture in slot 0.");
|
|
return false;
|
|
}
|
|
m_imageMaskHM = new HeightMap(activeTerrain.terrainData.GetAlphamaps(0, 0, activeTerrain.terrainData.alphamapWidth, activeTerrain.terrainData.alphamapHeight), 0);
|
|
break;
|
|
case GaiaConstants.ImageFitnessFilterMode.TerrainTexture1:
|
|
if (gaiaSplatPrototypes.Length < 2)
|
|
{
|
|
Debug.LogError("You requested an terrain texture mask 1 but there is no active texture in slot 1.");
|
|
return false;
|
|
}
|
|
m_imageMaskHM = new HeightMap(activeTerrain.terrainData.GetAlphamaps(0, 0, activeTerrain.terrainData.alphamapWidth, activeTerrain.terrainData.alphamapHeight), 1);
|
|
break;
|
|
case GaiaConstants.ImageFitnessFilterMode.TerrainTexture2:
|
|
if (gaiaSplatPrototypes.Length < 3)
|
|
{
|
|
Debug.LogError("You requested an terrain texture mask 2 but there is no active texture in slot 2.");
|
|
return false;
|
|
}
|
|
m_imageMaskHM = new HeightMap(activeTerrain.terrainData.GetAlphamaps(0, 0, activeTerrain.terrainData.alphamapWidth, activeTerrain.terrainData.alphamapHeight), 2);
|
|
break;
|
|
case GaiaConstants.ImageFitnessFilterMode.TerrainTexture3:
|
|
if (gaiaSplatPrototypes.Length < 4)
|
|
{
|
|
Debug.LogError("You requested an terrain texture mask 3 but there is no active texture in slot 3.");
|
|
return false;
|
|
}
|
|
m_imageMaskHM = new HeightMap(activeTerrain.terrainData.GetAlphamaps(0, 0, activeTerrain.terrainData.alphamapWidth, activeTerrain.terrainData.alphamapHeight), 3);
|
|
break;
|
|
case GaiaConstants.ImageFitnessFilterMode.TerrainTexture4:
|
|
if (gaiaSplatPrototypes.Length < 5)
|
|
{
|
|
Debug.LogError("You requested an terrain texture mask 4 but there is no active texture in slot 4.");
|
|
return false;
|
|
}
|
|
m_imageMaskHM = new HeightMap(activeTerrain.terrainData.GetAlphamaps(0, 0, activeTerrain.terrainData.alphamapWidth, activeTerrain.terrainData.alphamapHeight), 4);
|
|
break;
|
|
case GaiaConstants.ImageFitnessFilterMode.TerrainTexture5:
|
|
if (gaiaSplatPrototypes.Length < 6)
|
|
{
|
|
Debug.LogError("You requested an terrain texture mask 5 but there is no active texture in slot 5.");
|
|
return false;
|
|
}
|
|
m_imageMaskHM = new HeightMap(activeTerrain.terrainData.GetAlphamaps(0, 0, activeTerrain.terrainData.alphamapWidth, activeTerrain.terrainData.alphamapHeight), 5);
|
|
break;
|
|
case GaiaConstants.ImageFitnessFilterMode.TerrainTexture6:
|
|
if (gaiaSplatPrototypes.Length < 7)
|
|
{
|
|
Debug.LogError("You requested an terrain texture mask 6 but there is no active texture in slot 6.");
|
|
return false;
|
|
}
|
|
m_imageMaskHM = new HeightMap(activeTerrain.terrainData.GetAlphamaps(0, 0, activeTerrain.terrainData.alphamapWidth, activeTerrain.terrainData.alphamapHeight), 6);
|
|
break;
|
|
case GaiaConstants.ImageFitnessFilterMode.TerrainTexture7:
|
|
if (gaiaSplatPrototypes.Length < 8)
|
|
{
|
|
Debug.LogError("You requested an terrain texture mask 7 but there is no active texture in slot 7.");
|
|
return false;
|
|
}
|
|
m_imageMaskHM = new HeightMap(activeTerrain.terrainData.GetAlphamaps(0, 0, activeTerrain.terrainData.alphamapWidth, activeTerrain.terrainData.alphamapHeight), 7);
|
|
break;
|
|
}
|
|
m_imageMaskHM.Flip();
|
|
}
|
|
if (m_imageMaskSmoothIterations > 0)
|
|
{
|
|
m_imageMaskHM.Smooth(m_imageMaskSmoothIterations);
|
|
}
|
|
if (m_imageMaskFlip)
|
|
{
|
|
m_imageMaskHM.Flip();
|
|
}
|
|
if (m_imageMaskNormalise)
|
|
{
|
|
m_imageMaskHM.Normalise();
|
|
}
|
|
if (m_imageMaskInvert)
|
|
{
|
|
m_imageMaskHM.Invert();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public void CreateSpawnCaches()
|
|
{
|
|
m_cacheTextures = false;
|
|
m_textureMapsDirty = false;
|
|
for (int i = 0; i < m_spawnerRules.Count; i++)
|
|
{
|
|
if (m_spawnerRules[i].CacheTextures(this))
|
|
{
|
|
CacheTextureMapsFromTerrain(Terrain.activeTerrain.GetInstanceID());
|
|
m_cacheTextures = true;
|
|
break;
|
|
}
|
|
}
|
|
m_cacheDetails = false;
|
|
for (int i = 0; i < m_spawnerRules.Count; i++)
|
|
{
|
|
if (m_spawnerRules[i].CacheDetails(this))
|
|
{
|
|
CacheDetailMapsFromTerrain(Terrain.activeTerrain.GetInstanceID());
|
|
m_cacheDetails = true;
|
|
break;
|
|
}
|
|
}
|
|
CacheTreesFromTerrain();
|
|
m_cacheTags = false;
|
|
List<string> tagList = new List<string>();
|
|
for (int i = 0; i < m_spawnerRules.Count; i++)
|
|
{
|
|
m_spawnerRules[i].AddProximityTags(this, ref tagList);
|
|
}
|
|
if (tagList.Count > 0)
|
|
{
|
|
CacheTaggedGameObjectsFromScene(tagList);
|
|
m_cacheTags = true;
|
|
}
|
|
m_cacheHeightMaps = false;
|
|
for (int i = 0; i < m_spawnerRules.Count; i++)
|
|
{
|
|
if (m_spawnerRules[i].CacheHeightMaps(this))
|
|
{
|
|
CacheHeightMapFromTerrain(Terrain.activeTerrain.GetInstanceID());
|
|
m_cacheHeightMaps = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void CreateSpawnCaches(GaiaConstants.SpawnerResourceType resourceType, int resourceIdx)
|
|
{
|
|
m_cacheTextures = false;
|
|
m_textureMapsDirty = false;
|
|
m_cacheDetails = false;
|
|
m_cacheTags = false;
|
|
switch (resourceType)
|
|
{
|
|
case GaiaConstants.SpawnerResourceType.TerrainTexture:
|
|
if (resourceIdx < m_resources.m_texturePrototypes.Length)
|
|
{
|
|
CacheTextureMapsFromTerrain(Terrain.activeTerrain.GetInstanceID());
|
|
m_cacheTextures = true;
|
|
List<string> tagList3 = new List<string>();
|
|
m_resources.m_texturePrototypes[resourceIdx].AddTags(ref tagList3);
|
|
if (tagList3.Count > 0)
|
|
{
|
|
CacheTaggedGameObjectsFromScene(tagList3);
|
|
m_cacheTags = true;
|
|
}
|
|
}
|
|
break;
|
|
case GaiaConstants.SpawnerResourceType.TerrainDetail:
|
|
if (resourceIdx < m_resources.m_detailPrototypes.Length)
|
|
{
|
|
CacheDetailMapsFromTerrain(Terrain.activeTerrain.GetInstanceID());
|
|
m_cacheDetails = true;
|
|
if (m_resources.m_detailPrototypes[resourceIdx].ChecksTextures())
|
|
{
|
|
CacheTextureMapsFromTerrain(Terrain.activeTerrain.GetInstanceID());
|
|
m_cacheTextures = true;
|
|
}
|
|
List<string> tagList2 = new List<string>();
|
|
m_resources.m_detailPrototypes[resourceIdx].AddTags(ref tagList2);
|
|
if (tagList2.Count > 0)
|
|
{
|
|
CacheTaggedGameObjectsFromScene(tagList2);
|
|
m_cacheTags = true;
|
|
}
|
|
}
|
|
break;
|
|
case GaiaConstants.SpawnerResourceType.TerrainTree:
|
|
if (resourceIdx < m_resources.m_treePrototypes.Length)
|
|
{
|
|
if (m_resources.m_treePrototypes[resourceIdx].ChecksTextures())
|
|
{
|
|
CacheTextureMapsFromTerrain(Terrain.activeTerrain.GetInstanceID());
|
|
m_cacheTextures = true;
|
|
}
|
|
CacheTreesFromTerrain();
|
|
List<string> tagList4 = new List<string>();
|
|
m_resources.m_treePrototypes[resourceIdx].AddTags(ref tagList4);
|
|
if (tagList4.Count > 0)
|
|
{
|
|
CacheTaggedGameObjectsFromScene(tagList4);
|
|
m_cacheTags = true;
|
|
}
|
|
}
|
|
break;
|
|
case GaiaConstants.SpawnerResourceType.GameObject:
|
|
if (resourceIdx < m_resources.m_gameObjectPrototypes.Length)
|
|
{
|
|
if (m_resources.m_gameObjectPrototypes[resourceIdx].ChecksTextures())
|
|
{
|
|
CacheTextureMapsFromTerrain(Terrain.activeTerrain.GetInstanceID());
|
|
m_cacheTextures = true;
|
|
}
|
|
List<string> tagList = new List<string>();
|
|
m_resources.m_gameObjectPrototypes[resourceIdx].AddTags(ref tagList);
|
|
if (tagList.Count > 0)
|
|
{
|
|
CacheTaggedGameObjectsFromScene(tagList);
|
|
m_cacheTags = true;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
public void DeleteSpawnCaches(bool flushDirty = false)
|
|
{
|
|
if (m_cacheTextures)
|
|
{
|
|
if (flushDirty && m_textureMapsDirty && !m_cancelSpawn)
|
|
{
|
|
m_textureMapsDirty = false;
|
|
SaveTextureMapsToTerrain(Terrain.activeTerrain.GetInstanceID());
|
|
}
|
|
DeleteTextureMapCache();
|
|
m_cacheTextures = false;
|
|
}
|
|
if (m_cacheDetails)
|
|
{
|
|
if (!m_cancelSpawn)
|
|
{
|
|
SaveDetailMapsToTerrain(Terrain.activeTerrain.GetInstanceID());
|
|
}
|
|
DeleteDetailMapCache();
|
|
m_cacheDetails = false;
|
|
}
|
|
if (m_cacheTags)
|
|
{
|
|
DeleteTagCache();
|
|
m_cacheTags = false;
|
|
}
|
|
if (m_cacheHeightMaps)
|
|
{
|
|
if (flushDirty && m_heightMapDirty && !m_cancelSpawn)
|
|
{
|
|
m_heightMapDirty = false;
|
|
SaveHeightMapToTerrain(Terrain.activeTerrain.GetInstanceID());
|
|
}
|
|
DeleteHeightMapCache();
|
|
m_cacheHeightMaps = false;
|
|
}
|
|
}
|
|
|
|
public bool TryExecuteRule(ref SpawnRule rule, ref SpawnInfo spawnInfo)
|
|
{
|
|
if (rule != null && (rule.m_ignoreMaxInstances || rule.m_activeInstanceCnt < rule.m_maxInstances))
|
|
{
|
|
spawnInfo.m_fitness *= m_spawnFitnessAttenuator.Evaluate(Mathf.Clamp01(spawnInfo.m_hitDistanceWU / m_spawnRange));
|
|
if (m_areaMaskMode != GaiaConstants.ImageFitnessFilterMode.None)
|
|
{
|
|
if (m_areaMaskMode == GaiaConstants.ImageFitnessFilterMode.PerlinNoise || m_areaMaskMode == GaiaConstants.ImageFitnessFilterMode.BillowNoise || m_areaMaskMode == GaiaConstants.ImageFitnessFilterMode.RidgedNoise)
|
|
{
|
|
if (!m_noiseInvert)
|
|
{
|
|
spawnInfo.m_fitness *= m_noiseGenerator.GetNormalisedValue(100000f + spawnInfo.m_hitLocationWU.x * (1f / m_noiseZoom), 100000f + spawnInfo.m_hitLocationWU.z * (1f / m_noiseZoom));
|
|
}
|
|
else
|
|
{
|
|
spawnInfo.m_fitness *= 1f - m_noiseGenerator.GetNormalisedValue(100000f + spawnInfo.m_hitLocationWU.x * (1f / m_noiseZoom), 100000f + spawnInfo.m_hitLocationWU.z * (1f / m_noiseZoom));
|
|
}
|
|
}
|
|
else if (m_imageMaskHM.HasData())
|
|
{
|
|
float x = (spawnInfo.m_hitLocationWU.x - (base.transform.position.x - m_spawnRange)) / (m_spawnRange * 2f);
|
|
float z = (spawnInfo.m_hitLocationWU.z - (base.transform.position.z - m_spawnRange)) / (m_spawnRange * 2f);
|
|
spawnInfo.m_fitness *= m_imageMaskHM[x, z];
|
|
}
|
|
}
|
|
if (spawnInfo.m_fitness > rule.m_minViableFitness && GetRandomFloat(0f, 1f) > rule.m_failureRate)
|
|
{
|
|
rule.Spawn(ref spawnInfo);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public bool CheckLocation(Vector3 locationWU, ref SpawnInfo spawnInfo)
|
|
{
|
|
spawnInfo.m_spawner = this;
|
|
spawnInfo.m_outOfBounds = true;
|
|
spawnInfo.m_wasVirginTerrain = false;
|
|
spawnInfo.m_spawnRotationY = 0f;
|
|
spawnInfo.m_hitDistanceWU = Vector3.Distance(base.transform.position, locationWU);
|
|
spawnInfo.m_hitLocationWU = locationWU;
|
|
spawnInfo.m_hitNormal = Vector3.zero;
|
|
spawnInfo.m_hitObject = null;
|
|
spawnInfo.m_hitTerrain = null;
|
|
spawnInfo.m_terrainNormalWU = Vector3.one;
|
|
spawnInfo.m_terrainHeightWU = 0f;
|
|
spawnInfo.m_terrainSlopeWU = 0f;
|
|
spawnInfo.m_areaHitSlopeWU = 0f;
|
|
spawnInfo.m_areaMinSlopeWU = 0f;
|
|
spawnInfo.m_areaAvgSlopeWU = 0f;
|
|
spawnInfo.m_areaMaxSlopeWU = 0f;
|
|
locationWU.y = m_terrainHeight + 1000f;
|
|
if (Physics.Raycast(locationWU, Vector3.down, out m_checkHitInfo, float.PositiveInfinity, m_spawnCollisionLayers))
|
|
{
|
|
if (spawnInfo.m_spawner.IsDetailSpawner() && (m_checkHitInfo.collider is SphereCollider || m_checkHitInfo.collider is CapsuleCollider) && m_checkHitInfo.collider.name == "_GaiaCollider_Grass")
|
|
{
|
|
locationWU.y = m_checkHitInfo.point.y - 0.01f;
|
|
if (!Physics.Raycast(locationWU, Vector3.down, out m_checkHitInfo, float.PositiveInfinity, m_spawnCollisionLayers))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
spawnInfo.m_hitLocationWU = m_checkHitInfo.point;
|
|
spawnInfo.m_hitDistanceWU = Vector3.Distance(base.transform.position, spawnInfo.m_hitLocationWU);
|
|
spawnInfo.m_hitNormal = m_checkHitInfo.normal;
|
|
spawnInfo.m_hitObject = m_checkHitInfo.transform;
|
|
if (m_spawnerShape == GaiaConstants.SpawnerShape.Box)
|
|
{
|
|
if (!m_spawnerBounds.Contains(spawnInfo.m_hitLocationWU))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else if (spawnInfo.m_hitDistanceWU > m_spawnRange)
|
|
{
|
|
return false;
|
|
}
|
|
spawnInfo.m_outOfBounds = false;
|
|
Terrain terrain;
|
|
if (m_checkHitInfo.collider is TerrainCollider)
|
|
{
|
|
terrain = m_checkHitInfo.transform.GetComponent<Terrain>();
|
|
spawnInfo.m_wasVirginTerrain = true;
|
|
}
|
|
else
|
|
{
|
|
terrain = TerrainHelper.GetTerrain(m_checkHitInfo.point);
|
|
}
|
|
if (terrain != null)
|
|
{
|
|
spawnInfo.m_hitTerrain = terrain;
|
|
spawnInfo.m_terrainHeightWU = terrain.SampleHeight(m_checkHitInfo.point);
|
|
Vector3 vector = terrain.transform.InverseTransformPoint(m_checkHitInfo.point);
|
|
Vector3 hitLocationNU = new Vector3(Mathf.InverseLerp(0f, terrain.terrainData.size.x, vector.x), Mathf.InverseLerp(0f, terrain.terrainData.size.y, vector.y), Mathf.InverseLerp(0f, terrain.terrainData.size.z, vector.z));
|
|
spawnInfo.m_hitLocationNU = hitLocationNU;
|
|
spawnInfo.m_terrainSlopeWU = terrain.terrainData.GetSteepness(hitLocationNU.x, hitLocationNU.z);
|
|
spawnInfo.m_areaHitSlopeWU = (spawnInfo.m_areaMinSlopeWU = (spawnInfo.m_areaAvgSlopeWU = (spawnInfo.m_areaMaxSlopeWU = spawnInfo.m_terrainSlopeWU)));
|
|
spawnInfo.m_terrainNormalWU = terrain.terrainData.GetInterpolatedNormal(hitLocationNU.x, hitLocationNU.z);
|
|
if (spawnInfo.m_wasVirginTerrain && spawnInfo.m_spawner.m_treeCache.Count(spawnInfo.m_hitLocationWU, 0.5f) > 0)
|
|
{
|
|
spawnInfo.m_wasVirginTerrain = false;
|
|
}
|
|
if (m_textureMapCache != null && m_textureMapCache.Count > 0)
|
|
{
|
|
List<HeightMap> list = m_textureMapCache[terrain.GetInstanceID()];
|
|
for (int i = 0; i < spawnInfo.m_textureStrengths.Length; i++)
|
|
{
|
|
spawnInfo.m_textureStrengths[i] = list[i][hitLocationNU.z, hitLocationNU.x];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
float[,,] alphamaps = terrain.terrainData.GetAlphamaps((int)(hitLocationNU.x * (float)(terrain.terrainData.alphamapWidth - 1)), (int)(hitLocationNU.z * (float)(terrain.terrainData.alphamapHeight - 1)), 1, 1);
|
|
for (int j = 0; j < spawnInfo.m_textureStrengths.Length; j++)
|
|
{
|
|
spawnInfo.m_textureStrengths[j] = alphamaps[0, 0, j];
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public bool CheckLocationBounds(ref SpawnInfo spawnInfo, float distance)
|
|
{
|
|
spawnInfo.m_areaHitSlopeWU = (spawnInfo.m_areaMinSlopeWU = (spawnInfo.m_areaAvgSlopeWU = (spawnInfo.m_areaMaxSlopeWU = spawnInfo.m_terrainSlopeWU)));
|
|
if (spawnInfo.m_areaHitsWU == null)
|
|
{
|
|
spawnInfo.m_areaHitsWU = new Vector3[4];
|
|
}
|
|
spawnInfo.m_areaHitsWU[0] = new Vector3(spawnInfo.m_hitLocationWU.x + distance, spawnInfo.m_hitLocationWU.y + 3000f, spawnInfo.m_hitLocationWU.z);
|
|
spawnInfo.m_areaHitsWU[1] = new Vector3(spawnInfo.m_hitLocationWU.x - distance, spawnInfo.m_hitLocationWU.y + 3000f, spawnInfo.m_hitLocationWU.z);
|
|
spawnInfo.m_areaHitsWU[2] = new Vector3(spawnInfo.m_hitLocationWU.x, spawnInfo.m_hitLocationWU.y + 3000f, spawnInfo.m_hitLocationWU.z + distance);
|
|
spawnInfo.m_areaHitsWU[3] = new Vector3(spawnInfo.m_hitLocationWU.x, spawnInfo.m_hitLocationWU.y + 3000f, spawnInfo.m_hitLocationWU.z - distance);
|
|
if (!Physics.BoxCast(halfExtents: new Vector3(distance, 0.1f, distance), center: new Vector3(spawnInfo.m_hitLocationWU.x, spawnInfo.m_hitLocationWU.y + 3000f, spawnInfo.m_hitLocationWU.z), direction: Vector3.down, hitInfo: out var hitInfo, orientation: Quaternion.identity, maxDistance: float.PositiveInfinity, layerMask: m_spawnCollisionLayers))
|
|
{
|
|
return false;
|
|
}
|
|
if (spawnInfo.m_wasVirginTerrain)
|
|
{
|
|
if (hitInfo.collider is TerrainCollider)
|
|
{
|
|
if (spawnInfo.m_spawner.m_treeCache.Count(hitInfo.point, 0.5f) > 0)
|
|
{
|
|
spawnInfo.m_wasVirginTerrain = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
spawnInfo.m_wasVirginTerrain = false;
|
|
}
|
|
}
|
|
if (!Physics.Raycast(spawnInfo.m_areaHitsWU[0], Vector3.down, out hitInfo, float.PositiveInfinity, m_spawnCollisionLayers))
|
|
{
|
|
return false;
|
|
}
|
|
spawnInfo.m_areaHitsWU[0] = hitInfo.point;
|
|
Terrain terrain = hitInfo.transform.GetComponent<Terrain>();
|
|
if (terrain == null)
|
|
{
|
|
terrain = TerrainHelper.GetTerrain(hitInfo.point);
|
|
}
|
|
Vector3 zero = Vector3.zero;
|
|
Vector3 zero2 = Vector3.zero;
|
|
float num = 0f;
|
|
if (terrain != null)
|
|
{
|
|
zero = terrain.transform.InverseTransformPoint(hitInfo.point);
|
|
zero2 = new Vector3(Mathf.InverseLerp(0f, terrain.terrainData.size.x, zero.x), Mathf.InverseLerp(0f, terrain.terrainData.size.y, zero.y), Mathf.InverseLerp(0f, terrain.terrainData.size.z, zero.z));
|
|
num = terrain.terrainData.GetSteepness(zero2.x, zero2.z);
|
|
spawnInfo.m_areaAvgSlopeWU += num;
|
|
if (num > spawnInfo.m_areaMaxSlopeWU)
|
|
{
|
|
spawnInfo.m_areaMaxSlopeWU = num;
|
|
}
|
|
if (num < spawnInfo.m_areaMinSlopeWU)
|
|
{
|
|
spawnInfo.m_areaMinSlopeWU = num;
|
|
}
|
|
if (spawnInfo.m_wasVirginTerrain)
|
|
{
|
|
if (hitInfo.collider is TerrainCollider)
|
|
{
|
|
if (spawnInfo.m_spawner.m_treeCache.Count(hitInfo.point, 0.5f) > 0)
|
|
{
|
|
spawnInfo.m_wasVirginTerrain = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
spawnInfo.m_wasVirginTerrain = false;
|
|
}
|
|
}
|
|
}
|
|
if (!Physics.Raycast(spawnInfo.m_areaHitsWU[1], Vector3.down, out hitInfo, float.PositiveInfinity, m_spawnCollisionLayers))
|
|
{
|
|
return false;
|
|
}
|
|
spawnInfo.m_areaHitsWU[1] = hitInfo.point;
|
|
terrain = hitInfo.transform.GetComponent<Terrain>();
|
|
if (terrain == null)
|
|
{
|
|
terrain = TerrainHelper.GetTerrain(hitInfo.point);
|
|
}
|
|
if (terrain != null)
|
|
{
|
|
zero = terrain.transform.InverseTransformPoint(hitInfo.point);
|
|
zero2 = new Vector3(Mathf.InverseLerp(0f, terrain.terrainData.size.x, zero.x), Mathf.InverseLerp(0f, terrain.terrainData.size.y, zero.y), Mathf.InverseLerp(0f, terrain.terrainData.size.z, zero.z));
|
|
num = terrain.terrainData.GetSteepness(zero2.x, zero2.z);
|
|
spawnInfo.m_areaAvgSlopeWU += num;
|
|
if (num > spawnInfo.m_areaMaxSlopeWU)
|
|
{
|
|
spawnInfo.m_areaMaxSlopeWU = num;
|
|
}
|
|
if (num < spawnInfo.m_areaMinSlopeWU)
|
|
{
|
|
spawnInfo.m_areaMinSlopeWU = num;
|
|
}
|
|
if (spawnInfo.m_wasVirginTerrain)
|
|
{
|
|
if (hitInfo.collider is TerrainCollider)
|
|
{
|
|
if (spawnInfo.m_spawner.m_treeCache.Count(hitInfo.point, 0.5f) > 0)
|
|
{
|
|
spawnInfo.m_wasVirginTerrain = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
spawnInfo.m_wasVirginTerrain = false;
|
|
}
|
|
}
|
|
}
|
|
if (!Physics.Raycast(spawnInfo.m_areaHitsWU[2], Vector3.down, out hitInfo, float.PositiveInfinity, m_spawnCollisionLayers))
|
|
{
|
|
return false;
|
|
}
|
|
spawnInfo.m_areaHitsWU[2] = hitInfo.point;
|
|
terrain = hitInfo.transform.GetComponent<Terrain>();
|
|
if (terrain == null)
|
|
{
|
|
terrain = TerrainHelper.GetTerrain(hitInfo.point);
|
|
}
|
|
if (terrain != null)
|
|
{
|
|
zero = terrain.transform.InverseTransformPoint(hitInfo.point);
|
|
zero2 = new Vector3(Mathf.InverseLerp(0f, terrain.terrainData.size.x, zero.x), Mathf.InverseLerp(0f, terrain.terrainData.size.y, zero.y), Mathf.InverseLerp(0f, terrain.terrainData.size.z, zero.z));
|
|
num = terrain.terrainData.GetSteepness(zero2.x, zero2.z);
|
|
spawnInfo.m_areaAvgSlopeWU += num;
|
|
if (num > spawnInfo.m_areaMaxSlopeWU)
|
|
{
|
|
spawnInfo.m_areaMaxSlopeWU = num;
|
|
}
|
|
if (num < spawnInfo.m_areaMinSlopeWU)
|
|
{
|
|
spawnInfo.m_areaMinSlopeWU = num;
|
|
}
|
|
if (spawnInfo.m_wasVirginTerrain)
|
|
{
|
|
if (hitInfo.collider is TerrainCollider)
|
|
{
|
|
if (spawnInfo.m_spawner.m_treeCache.Count(hitInfo.point, 0.5f) > 0)
|
|
{
|
|
spawnInfo.m_wasVirginTerrain = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
spawnInfo.m_wasVirginTerrain = false;
|
|
}
|
|
}
|
|
}
|
|
if (!Physics.Raycast(spawnInfo.m_areaHitsWU[3], Vector3.down, out hitInfo, float.PositiveInfinity, m_spawnCollisionLayers))
|
|
{
|
|
return false;
|
|
}
|
|
spawnInfo.m_areaHitsWU[3] = hitInfo.point;
|
|
terrain = hitInfo.transform.GetComponent<Terrain>();
|
|
if (terrain == null)
|
|
{
|
|
terrain = TerrainHelper.GetTerrain(hitInfo.point);
|
|
}
|
|
if (terrain != null)
|
|
{
|
|
zero = terrain.transform.InverseTransformPoint(hitInfo.point);
|
|
zero2 = new Vector3(Mathf.InverseLerp(0f, terrain.terrainData.size.x, zero.x), Mathf.InverseLerp(0f, terrain.terrainData.size.y, zero.y), Mathf.InverseLerp(0f, terrain.terrainData.size.z, zero.z));
|
|
num = terrain.terrainData.GetSteepness(zero2.x, zero2.z);
|
|
spawnInfo.m_areaAvgSlopeWU += num;
|
|
if (num > spawnInfo.m_areaMaxSlopeWU)
|
|
{
|
|
spawnInfo.m_areaMaxSlopeWU = num;
|
|
}
|
|
if (num < spawnInfo.m_areaMinSlopeWU)
|
|
{
|
|
spawnInfo.m_areaMinSlopeWU = num;
|
|
}
|
|
if (spawnInfo.m_wasVirginTerrain)
|
|
{
|
|
if (hitInfo.collider is TerrainCollider)
|
|
{
|
|
if (spawnInfo.m_spawner.m_treeCache.Count(hitInfo.point, 0.5f) > 0)
|
|
{
|
|
spawnInfo.m_wasVirginTerrain = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
spawnInfo.m_wasVirginTerrain = false;
|
|
}
|
|
}
|
|
}
|
|
spawnInfo.m_areaAvgSlopeWU /= 5f;
|
|
float num2 = spawnInfo.m_areaHitsWU[0].y - spawnInfo.m_areaHitsWU[1].y;
|
|
float num3 = spawnInfo.m_areaHitsWU[2].y - spawnInfo.m_areaHitsWU[3].y;
|
|
spawnInfo.m_areaHitSlopeWU = GaiaUtils.Math_Clamp(0f, 90f, (float)Math.Sqrt(num2 * num2 + num3 * num3));
|
|
return true;
|
|
}
|
|
|
|
public void UpdateCounters()
|
|
{
|
|
m_totalRuleCnt = 0;
|
|
m_activeRuleCnt = 0;
|
|
m_inactiveRuleCnt = 0;
|
|
m_maxInstanceCnt = 0uL;
|
|
m_activeInstanceCnt = 0uL;
|
|
m_inactiveInstanceCnt = 0uL;
|
|
m_totalInstanceCnt = 0uL;
|
|
foreach (SpawnRule spawnerRule in m_spawnerRules)
|
|
{
|
|
m_totalRuleCnt++;
|
|
if (spawnerRule.m_isActive)
|
|
{
|
|
m_activeRuleCnt++;
|
|
m_maxInstanceCnt += spawnerRule.m_maxInstances;
|
|
m_activeInstanceCnt += spawnerRule.m_activeInstanceCnt;
|
|
m_inactiveInstanceCnt += spawnerRule.m_inactiveInstanceCnt;
|
|
m_totalInstanceCnt += spawnerRule.m_activeInstanceCnt + spawnerRule.m_inactiveInstanceCnt;
|
|
}
|
|
else
|
|
{
|
|
m_inactiveRuleCnt++;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnDrawGizmosSelected()
|
|
{
|
|
if (m_showGizmos)
|
|
{
|
|
if (m_spawnerShape == GaiaConstants.SpawnerShape.Sphere)
|
|
{
|
|
if (m_mode == GaiaConstants.OperationMode.RuntimeTriggeredInterval)
|
|
{
|
|
Gizmos.color = Color.yellow;
|
|
Gizmos.DrawWireSphere(base.transform.position, m_triggerRange);
|
|
}
|
|
Gizmos.color = Color.red;
|
|
Gizmos.DrawWireSphere(base.transform.position, m_spawnRange);
|
|
}
|
|
else
|
|
{
|
|
if (m_mode == GaiaConstants.OperationMode.RuntimeTriggeredInterval)
|
|
{
|
|
Gizmos.color = Color.yellow;
|
|
Gizmos.DrawWireCube(base.transform.position, new Vector3(m_triggerRange * 2f, m_triggerRange * 2f, m_triggerRange * 2f));
|
|
}
|
|
Gizmos.color = Color.red;
|
|
Gizmos.DrawWireCube(base.transform.position, new Vector3(m_spawnRange * 2f, m_spawnRange * 2f, m_spawnRange * 2f));
|
|
}
|
|
if (m_resources != null)
|
|
{
|
|
Bounds bounds = default(Bounds);
|
|
if (TerrainHelper.GetTerrainBounds(base.transform.position, ref bounds))
|
|
{
|
|
bounds.center = new Vector3(bounds.center.x, m_resources.m_seaLevel, bounds.center.z);
|
|
bounds.size = new Vector3(bounds.size.x, 0.05f, bounds.size.z);
|
|
Gizmos.color = new Color(Color.blue.r, Color.blue.g, Color.blue.b, Color.blue.a / 4f);
|
|
Gizmos.DrawCube(bounds.center, bounds.size);
|
|
}
|
|
}
|
|
}
|
|
UpdateCounters();
|
|
}
|
|
|
|
public void CacheTextureMapsFromTerrain(int terrainID)
|
|
{
|
|
if (m_textureMapCache == null)
|
|
{
|
|
m_textureMapCache = new Dictionary<int, List<HeightMap>>();
|
|
}
|
|
for (int i = 0; i < Terrain.activeTerrains.Length; i++)
|
|
{
|
|
Terrain terrain = Terrain.activeTerrains[i];
|
|
if (terrain.GetInstanceID() == terrainID)
|
|
{
|
|
float[,,] alphamaps = terrain.terrainData.GetAlphamaps(0, 0, terrain.terrainData.alphamapWidth, terrain.terrainData.alphamapHeight);
|
|
List<HeightMap> list = new List<HeightMap>();
|
|
for (int j = 0; j < terrain.terrainData.alphamapLayers; j++)
|
|
{
|
|
HeightMap item = new HeightMap(alphamaps, j);
|
|
list.Add(item);
|
|
}
|
|
m_textureMapCache[terrainID] = list;
|
|
return;
|
|
}
|
|
}
|
|
Debug.LogError("Attempted to get textures on terrain that does not exist!");
|
|
}
|
|
|
|
public List<HeightMap> GetTextureMaps(int terrainID)
|
|
{
|
|
if (!m_textureMapCache.TryGetValue(terrainID, out var value))
|
|
{
|
|
return null;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
public void SaveTextureMapsToTerrain(int terrainID)
|
|
{
|
|
if (!m_textureMapCache.TryGetValue(terrainID, out var value))
|
|
{
|
|
Debug.LogError("Texture map list was not found for terrain ID : " + terrainID + " !");
|
|
return;
|
|
}
|
|
if (value.Count <= 0)
|
|
{
|
|
Debug.LogError("Texture map list was empty for terrain ID : " + terrainID + " !");
|
|
return;
|
|
}
|
|
for (int i = 0; i < Terrain.activeTerrains.Length; i++)
|
|
{
|
|
Terrain terrain = Terrain.activeTerrains[i];
|
|
if (terrain.GetInstanceID() != terrainID)
|
|
{
|
|
continue;
|
|
}
|
|
if (value.Count != terrain.terrainData.alphamapLayers)
|
|
{
|
|
Debug.LogError("Texture map prototype list does not match terrain prototype list for terrain ID : " + terrainID + " !");
|
|
return;
|
|
}
|
|
float[,,] array = new float[terrain.terrainData.alphamapWidth, terrain.terrainData.alphamapHeight, terrain.terrainData.alphamapLayers];
|
|
for (int j = 0; j < terrain.terrainData.alphamapLayers; j++)
|
|
{
|
|
HeightMap heightMap = value[j];
|
|
for (int k = 0; k < heightMap.Width(); k++)
|
|
{
|
|
for (int l = 0; l < heightMap.Depth(); l++)
|
|
{
|
|
array[k, l, j] = heightMap[k, l];
|
|
}
|
|
}
|
|
}
|
|
terrain.terrainData.SetAlphamaps(0, 0, array);
|
|
return;
|
|
}
|
|
Debug.LogError("Attempted to locate a terrain that does not exist!");
|
|
}
|
|
|
|
public void DeleteTextureMapCache()
|
|
{
|
|
m_textureMapCache = new Dictionary<int, List<HeightMap>>();
|
|
}
|
|
|
|
public void SetTextureMapsDirty()
|
|
{
|
|
m_textureMapsDirty = true;
|
|
}
|
|
|
|
public void CacheDetailMapsFromTerrain(int terrainID)
|
|
{
|
|
if (m_detailMapCache == null)
|
|
{
|
|
m_detailMapCache = new Dictionary<int, List<HeightMap>>();
|
|
}
|
|
for (int i = 0; i < Terrain.activeTerrains.Length; i++)
|
|
{
|
|
Terrain terrain = Terrain.activeTerrains[i];
|
|
if (terrain.GetInstanceID() == terrainID)
|
|
{
|
|
List<HeightMap> list = new List<HeightMap>();
|
|
for (int j = 0; j < terrain.terrainData.detailPrototypes.Length; j++)
|
|
{
|
|
HeightMap item = new HeightMap(terrain.terrainData.GetDetailLayer(0, 0, terrain.terrainData.detailWidth, terrain.terrainData.detailHeight, j));
|
|
list.Add(item);
|
|
}
|
|
m_detailMapCache[terrainID] = list;
|
|
return;
|
|
}
|
|
}
|
|
Debug.LogError("Attempted to get details on terrain that does not exist!");
|
|
}
|
|
|
|
public void SaveDetailMapsToTerrain(int terrainID)
|
|
{
|
|
if (!m_detailMapCache.TryGetValue(terrainID, out var value))
|
|
{
|
|
Debug.LogWarning(base.gameObject.name + "Detail map list was not found for terrain ID : " + terrainID + " !");
|
|
return;
|
|
}
|
|
if (value.Count <= 0)
|
|
{
|
|
Debug.LogWarning(base.gameObject.name + ": Detail map list was empty for terrain ID : " + terrainID + " !");
|
|
return;
|
|
}
|
|
for (int i = 0; i < Terrain.activeTerrains.Length; i++)
|
|
{
|
|
Terrain terrain = Terrain.activeTerrains[i];
|
|
if (terrain.GetInstanceID() != terrainID)
|
|
{
|
|
continue;
|
|
}
|
|
if (value.Count != terrain.terrainData.detailPrototypes.Length)
|
|
{
|
|
Debug.LogError("Detail map protoype list does not match terrain prototype list for terrain ID : " + terrainID + " !");
|
|
return;
|
|
}
|
|
int[,] array = new int[value[0].Width(), value[0].Depth()];
|
|
for (int j = 0; j < terrain.terrainData.detailPrototypes.Length; j++)
|
|
{
|
|
HeightMap heightMap = value[j];
|
|
for (int k = 0; k < heightMap.Width(); k++)
|
|
{
|
|
for (int l = 0; l < heightMap.Depth(); l++)
|
|
{
|
|
array[k, l] = (int)heightMap[k, l];
|
|
}
|
|
}
|
|
terrain.terrainData.SetDetailLayer(0, 0, j, array);
|
|
}
|
|
terrain.Flush();
|
|
return;
|
|
}
|
|
Debug.LogError("Attempted to locate a terrain that does not exist!");
|
|
}
|
|
|
|
public List<HeightMap> GetDetailMaps(int terrainID)
|
|
{
|
|
if (!m_detailMapCache.TryGetValue(terrainID, out var value))
|
|
{
|
|
return null;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
public HeightMap GetDetailMap(int terrainID, int detailIndex)
|
|
{
|
|
if (!m_detailMapCache.TryGetValue(terrainID, out var value))
|
|
{
|
|
return null;
|
|
}
|
|
if (detailIndex >= 0 && detailIndex < value.Count)
|
|
{
|
|
return value[detailIndex];
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public void DeleteDetailMapCache()
|
|
{
|
|
m_detailMapCache = new Dictionary<int, List<HeightMap>>();
|
|
}
|
|
|
|
public void CacheTreesFromTerrain()
|
|
{
|
|
m_treeCache.LoadTreesFromTerrain();
|
|
}
|
|
|
|
public void DeleteTreeCache()
|
|
{
|
|
m_treeCache = new TreeManager();
|
|
}
|
|
|
|
public void AddToSession(GaiaOperation.OperationType opType, string opName)
|
|
{
|
|
GaiaSessionManager sessionManager = GaiaSessionManager.GetSessionManager();
|
|
if (sessionManager != null && !sessionManager.IsLocked())
|
|
{
|
|
GaiaOperation gaiaOperation = new GaiaOperation();
|
|
gaiaOperation.m_description = opName;
|
|
gaiaOperation.m_generatedByID = m_spawnerID;
|
|
gaiaOperation.m_generatedByName = base.transform.name;
|
|
gaiaOperation.m_generatedByType = GetType().ToString();
|
|
gaiaOperation.m_isActive = true;
|
|
gaiaOperation.m_operationDateTime = DateTime.Now.ToString();
|
|
gaiaOperation.m_operationType = opType;
|
|
gaiaOperation.m_operationDataJson = new string[1];
|
|
gaiaOperation.m_operationDataJson[0] = SerialiseJson();
|
|
sessionManager.AddOperation(gaiaOperation);
|
|
sessionManager.AddResource(m_resources);
|
|
}
|
|
}
|
|
|
|
public string SerialiseJson()
|
|
{
|
|
new fsSerializer().TrySerialize(this, out var data);
|
|
return fsJsonPrinter.CompressedJson(data);
|
|
}
|
|
|
|
public void DeSerialiseJson(string json)
|
|
{
|
|
fsData data = fsJsonParser.Parse(json);
|
|
fsSerializer obj = new fsSerializer();
|
|
Spawner instance = this;
|
|
obj.TryDeserialize(data, ref instance);
|
|
instance.m_resources = GaiaUtils.GetAsset(m_resourcesPath, typeof(GaiaResource)) as GaiaResource;
|
|
}
|
|
|
|
public void FlattenTerrain()
|
|
{
|
|
AddToSession(GaiaOperation.OperationType.FlattenTerrain, "Flattening terrain");
|
|
new GaiaWorldManager(Terrain.activeTerrains).FlattenWorld();
|
|
}
|
|
|
|
public void SmoothTerrain()
|
|
{
|
|
AddToSession(GaiaOperation.OperationType.SmoothTerrain, "Smoothing terrain");
|
|
new GaiaWorldManager(Terrain.activeTerrains).SmoothWorld();
|
|
}
|
|
|
|
public void ClearTrees()
|
|
{
|
|
AddToSession(GaiaOperation.OperationType.ClearTrees, "Clearing terrain trees");
|
|
TerrainHelper.ClearTrees();
|
|
}
|
|
|
|
public void ClearDetails()
|
|
{
|
|
AddToSession(GaiaOperation.OperationType.ClearDetails, "Clearing terrain details");
|
|
TerrainHelper.ClearDetails();
|
|
}
|
|
|
|
public void CacheHeightMapFromTerrain(int terrainID)
|
|
{
|
|
if (m_heightMapCache == null)
|
|
{
|
|
m_heightMapCache = new Dictionary<int, UnityHeightMap>();
|
|
}
|
|
for (int i = 0; i < Terrain.activeTerrains.Length; i++)
|
|
{
|
|
Terrain terrain = Terrain.activeTerrains[i];
|
|
if (terrain.GetInstanceID() == terrainID)
|
|
{
|
|
m_heightMapCache[terrainID] = new UnityHeightMap(terrain);
|
|
return;
|
|
}
|
|
}
|
|
Debug.LogError("Attempted to get height maps on a terrain that does not exist!");
|
|
}
|
|
|
|
public UnityHeightMap GetHeightMap(int terrainID)
|
|
{
|
|
if (!m_heightMapCache.TryGetValue(terrainID, out var value))
|
|
{
|
|
return null;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
public void SaveHeightMapToTerrain(int terrainID)
|
|
{
|
|
if (!m_heightMapCache.TryGetValue(terrainID, out var value))
|
|
{
|
|
Debug.LogError("Heightmap was not found for terrain ID : " + terrainID + " !");
|
|
return;
|
|
}
|
|
for (int i = 0; i < Terrain.activeTerrains.Length; i++)
|
|
{
|
|
Terrain terrain = Terrain.activeTerrains[i];
|
|
if (terrain.GetInstanceID() == terrainID)
|
|
{
|
|
value.SaveToTerrain(terrain);
|
|
return;
|
|
}
|
|
}
|
|
Debug.LogError("Attempted to locate a terrain that does not exist!");
|
|
}
|
|
|
|
public void DeleteHeightMapCache()
|
|
{
|
|
m_heightMapCache = new Dictionary<int, UnityHeightMap>();
|
|
}
|
|
|
|
public void SetHeightMapsDirty()
|
|
{
|
|
m_heightMapDirty = true;
|
|
}
|
|
|
|
public void CacheStamps(List<string> stampList)
|
|
{
|
|
if (m_stampCache == null)
|
|
{
|
|
m_stampCache = new Dictionary<string, HeightMap>();
|
|
}
|
|
for (int i = 0; i < stampList.Count; i++)
|
|
{
|
|
}
|
|
}
|
|
|
|
private void CacheTaggedGameObjectsFromScene(List<string> tagList)
|
|
{
|
|
m_taggedGameObjectCache = new Dictionary<string, Quadtree<GameObject>>();
|
|
Rect boundaries = new Rect(Terrain.activeTerrain.transform.position.x, Terrain.activeTerrain.transform.position.z, Terrain.activeTerrain.terrainData.size.x, Terrain.activeTerrain.terrainData.size.z);
|
|
for (int i = 0; i < tagList.Count; i++)
|
|
{
|
|
string text = tagList[i].Trim();
|
|
bool flag = false;
|
|
if (!string.IsNullOrEmpty(text))
|
|
{
|
|
flag = true;
|
|
}
|
|
if (!flag)
|
|
{
|
|
continue;
|
|
}
|
|
Quadtree<GameObject> value = null;
|
|
if (!m_taggedGameObjectCache.TryGetValue(text, out value))
|
|
{
|
|
value = new Quadtree<GameObject>(boundaries);
|
|
m_taggedGameObjectCache.Add(text, value);
|
|
}
|
|
GameObject[] array = GameObject.FindGameObjectsWithTag(text);
|
|
foreach (GameObject gameObject in array)
|
|
{
|
|
Vector2 vector = new Vector2(gameObject.transform.position.x, gameObject.transform.position.z);
|
|
if (boundaries.Contains(vector))
|
|
{
|
|
value.Insert(vector, gameObject);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void DeleteTagCache()
|
|
{
|
|
m_taggedGameObjectCache = null;
|
|
}
|
|
|
|
public List<GameObject> GetNearbyObjects(List<string> tagList, Rect area)
|
|
{
|
|
List<GameObject> list = new List<GameObject>();
|
|
for (int i = 0; i < tagList.Count; i++)
|
|
{
|
|
Quadtree<GameObject> value = null;
|
|
string key = tagList[i];
|
|
if (!m_taggedGameObjectCache.TryGetValue(key, out value))
|
|
{
|
|
continue;
|
|
}
|
|
foreach (GameObject item in value.Find(area))
|
|
{
|
|
list.Add(item);
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
public GameObject GetClosestObject(List<string> tagList, Rect area)
|
|
{
|
|
float num = float.MaxValue;
|
|
GameObject result = null;
|
|
for (int i = 0; i < tagList.Count; i++)
|
|
{
|
|
Quadtree<GameObject> value = null;
|
|
string key = tagList[i];
|
|
if (!m_taggedGameObjectCache.TryGetValue(key, out value))
|
|
{
|
|
continue;
|
|
}
|
|
foreach (GameObject item in value.Find(area))
|
|
{
|
|
float num2 = Vector2.Distance(area.center, new Vector2(item.transform.position.x, item.transform.position.z));
|
|
if (num2 < num)
|
|
{
|
|
num = num2;
|
|
result = item;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public GameObject GetClosestObject(string tag, Rect area)
|
|
{
|
|
float num = float.MaxValue;
|
|
GameObject result = null;
|
|
Quadtree<GameObject> value = null;
|
|
if (m_taggedGameObjectCache.TryGetValue(tag, out value))
|
|
{
|
|
foreach (GameObject item in value.Find(area))
|
|
{
|
|
float num2 = Vector2.Distance(area.center, new Vector2(item.transform.position.x, item.transform.position.z));
|
|
if (num2 < num)
|
|
{
|
|
num = num2;
|
|
result = item;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public void ResetRandomGenertor()
|
|
{
|
|
m_rndGenerator = new XorshiftPlus(m_seed);
|
|
}
|
|
|
|
public int GetRandomInt(int min, int max)
|
|
{
|
|
return m_rndGenerator.Next(min, max);
|
|
}
|
|
|
|
public float GetRandomFloat(float min, float max)
|
|
{
|
|
return m_rndGenerator.Next(min, max);
|
|
}
|
|
|
|
public Vector3 GetRandomV3(float range)
|
|
{
|
|
return m_rndGenerator.NextVector(0f - range, range);
|
|
}
|
|
}
|
|
}
|