summaryrefslogtreecommitdiff
path: root/Valheim_v202102/Valheim/assembly_valheim/SpawnSystem.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Valheim_v202102/Valheim/assembly_valheim/SpawnSystem.cs')
-rw-r--r--Valheim_v202102/Valheim/assembly_valheim/SpawnSystem.cs510
1 files changed, 510 insertions, 0 deletions
diff --git a/Valheim_v202102/Valheim/assembly_valheim/SpawnSystem.cs b/Valheim_v202102/Valheim/assembly_valheim/SpawnSystem.cs
new file mode 100644
index 0000000..8b5fa4a
--- /dev/null
+++ b/Valheim_v202102/Valheim/assembly_valheim/SpawnSystem.cs
@@ -0,0 +1,510 @@
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+
+public class SpawnSystem : MonoBehaviour
+{
+ [Serializable]
+ public class SpawnData
+ {
+ public string m_name = "";
+
+ public bool m_enabled = true;
+
+ public GameObject m_prefab;
+
+ [BitMask(typeof(Heightmap.Biome))]
+ public Heightmap.Biome m_biome;
+
+ [BitMask(typeof(Heightmap.BiomeArea))]
+ public Heightmap.BiomeArea m_biomeArea = Heightmap.BiomeArea.Everything;
+
+ [Header("Total nr of instances (if near player is set, only instances within the max spawn radius is counted)")]
+ public int m_maxSpawned = 1;
+
+ [Header("How often do we spawn")]
+ public float m_spawnInterval = 4f;
+
+ [Header("Chanse to spawn each spawn interval")]
+ [Range(0f, 100f)]
+ public float m_spawnChance = 100f;
+
+ [Header("Minimum distance to another instance")]
+ public float m_spawnDistance = 10f;
+
+ [Header("Spawn range ( 0 = use global setting )")]
+ public float m_spawnRadiusMin;
+
+ public float m_spawnRadiusMax;
+
+ [Header("Only spawn if this key is set")]
+ public string m_requiredGlobalKey = "";
+
+ [Header("Only spawn if this environment is active")]
+ public List<string> m_requiredEnvironments = new List<string>();
+
+ [Header("Group spawning")]
+ public int m_groupSizeMin = 1;
+
+ public int m_groupSizeMax = 1;
+
+ public float m_groupRadius = 3f;
+
+ [Header("Time of day")]
+ public bool m_spawnAtNight = true;
+
+ public bool m_spawnAtDay = true;
+
+ [Header("Altitude")]
+ public float m_minAltitude = -1000f;
+
+ public float m_maxAltitude = 1000f;
+
+ [Header("Terrain tilt")]
+ public float m_minTilt;
+
+ public float m_maxTilt = 35f;
+
+ [Header("Forest")]
+ public bool m_inForest = true;
+
+ public bool m_outsideForest = true;
+
+ [Header("Ocean depth ")]
+ public float m_minOceanDepth;
+
+ public float m_maxOceanDepth;
+
+ [Header("States")]
+ public bool m_huntPlayer;
+
+ public float m_groundOffset = 0.5f;
+
+ [Header("Level")]
+ public int m_maxLevel = 1;
+
+ public int m_minLevel = 1;
+
+ public float m_levelUpMinCenterDistance;
+
+ [HideInInspector]
+ public bool m_foldout;
+
+ public SpawnData Clone()
+ {
+ SpawnData obj = MemberwiseClone() as SpawnData;
+ obj.m_requiredEnvironments = new List<string>(m_requiredEnvironments);
+ return obj;
+ }
+ }
+
+ private static List<SpawnSystem> m_instances = new List<SpawnSystem>();
+
+ private const float m_spawnDistanceMin = 40f;
+
+ private const float m_spawnDistanceMax = 80f;
+
+ public List<SpawnData> m_spawners = new List<SpawnData>();
+
+ public float m_levelupChance = 10f;
+
+ [HideInInspector]
+ public List<Heightmap.Biome> m_biomeFolded = new List<Heightmap.Biome>();
+
+ private List<Player> m_nearPlayers = new List<Player>();
+
+ private ZNetView m_nview;
+
+ private Heightmap m_heightmap;
+
+ private void Awake()
+ {
+ m_instances.Add(this);
+ m_nview = GetComponent<ZNetView>();
+ m_heightmap = Heightmap.FindHeightmap(base.transform.position);
+ InvokeRepeating("UpdateSpawning", 4f, 4f);
+ }
+
+ private void OnDestroy()
+ {
+ m_instances.Remove(this);
+ }
+
+ private void UpdateSpawning()
+ {
+ if (!m_nview.IsValid() || !m_nview.IsOwner() || Player.m_localPlayer == null)
+ {
+ return;
+ }
+ m_nearPlayers.Clear();
+ GetPlayersInZone(m_nearPlayers);
+ if (m_nearPlayers.Count != 0)
+ {
+ DateTime time = ZNet.instance.GetTime();
+ UpdateSpawnList(m_spawners, time, eventSpawners: false);
+ List<SpawnData> currentSpawners = RandEventSystem.instance.GetCurrentSpawners();
+ if (currentSpawners != null)
+ {
+ UpdateSpawnList(currentSpawners, time, eventSpawners: true);
+ }
+ }
+ }
+
+ private void UpdateSpawnList(List<SpawnData> spawners, DateTime currentTime, bool eventSpawners)
+ {
+ string text = (eventSpawners ? "e_" : "b_");
+ int num = 0;
+ foreach (SpawnData spawner in spawners)
+ {
+ num++;
+ if (!spawner.m_enabled || !m_heightmap.HaveBiome(spawner.m_biome))
+ {
+ continue;
+ }
+ int stableHashCode = (text + spawner.m_prefab.name + num).GetStableHashCode();
+ DateTime dateTime = new DateTime(m_nview.GetZDO().GetLong(stableHashCode, 0L));
+ TimeSpan timeSpan = currentTime - dateTime;
+ int num2 = Mathf.Min(spawner.m_maxSpawned, (int)(timeSpan.TotalSeconds / (double)spawner.m_spawnInterval));
+ if (num2 > 0)
+ {
+ m_nview.GetZDO().Set(stableHashCode, currentTime.Ticks);
+ }
+ for (int i = 0; i < num2; i++)
+ {
+ if (UnityEngine.Random.Range(0f, 100f) > spawner.m_spawnChance)
+ {
+ continue;
+ }
+ if ((!string.IsNullOrEmpty(spawner.m_requiredGlobalKey) && !ZoneSystem.instance.GetGlobalKey(spawner.m_requiredGlobalKey)) || (spawner.m_requiredEnvironments.Count > 0 && !EnvMan.instance.IsEnvironment(spawner.m_requiredEnvironments)) || (!spawner.m_spawnAtDay && EnvMan.instance.IsDay()) || (!spawner.m_spawnAtNight && EnvMan.instance.IsNight()) || GetNrOfInstances(spawner.m_prefab, Vector3.zero, 0f, eventSpawners) >= spawner.m_maxSpawned)
+ {
+ break;
+ }
+ if (!FindBaseSpawnPoint(spawner, m_nearPlayers, out var spawnCenter, out var _) || (spawner.m_spawnDistance > 0f && HaveInstanceInRange(spawner.m_prefab, spawnCenter, spawner.m_spawnDistance)))
+ {
+ continue;
+ }
+ int num3 = UnityEngine.Random.Range(spawner.m_groupSizeMin, spawner.m_groupSizeMax + 1);
+ float num4 = ((num3 > 1) ? spawner.m_groupRadius : 0f);
+ int num5 = 0;
+ for (int j = 0; j < num3 * 2; j++)
+ {
+ Vector2 insideUnitCircle = UnityEngine.Random.insideUnitCircle;
+ Vector3 spawnPoint = spawnCenter + new Vector3(insideUnitCircle.x, 0f, insideUnitCircle.y) * num4;
+ if (IsSpawnPointGood(spawner, ref spawnPoint))
+ {
+ Spawn(spawner, spawnPoint + Vector3.up * spawner.m_groundOffset, eventSpawners);
+ num5++;
+ if (num5 >= num3)
+ {
+ break;
+ }
+ }
+ }
+ ZLog.Log("Spawned " + spawner.m_prefab.name + " x " + num5);
+ }
+ }
+ }
+
+ private void Spawn(SpawnData critter, Vector3 spawnPoint, bool eventSpawner)
+ {
+ GameObject gameObject = UnityEngine.Object.Instantiate(critter.m_prefab, spawnPoint, Quaternion.identity);
+ BaseAI component = gameObject.GetComponent<BaseAI>();
+ if (!(component != null))
+ {
+ return;
+ }
+ if (critter.m_huntPlayer)
+ {
+ component.SetHuntPlayer(hunt: true);
+ }
+ if (critter.m_maxLevel > 1 && (critter.m_levelUpMinCenterDistance <= 0f || spawnPoint.magnitude > critter.m_levelUpMinCenterDistance))
+ {
+ Character component2 = gameObject.GetComponent<Character>();
+ if ((bool)component2)
+ {
+ int i;
+ for (i = critter.m_minLevel; i < critter.m_maxLevel; i++)
+ {
+ if (!(UnityEngine.Random.Range(0f, 100f) <= m_levelupChance))
+ {
+ break;
+ }
+ }
+ if (i > 1)
+ {
+ component2.SetLevel(i);
+ }
+ }
+ }
+ MonsterAI monsterAI = component as MonsterAI;
+ if ((bool)monsterAI)
+ {
+ if (!critter.m_spawnAtDay)
+ {
+ monsterAI.SetDespawnInDay(despawn: true);
+ }
+ if (eventSpawner)
+ {
+ monsterAI.SetEventCreature(despawn: true);
+ }
+ }
+ }
+
+ private bool IsSpawnPointGood(SpawnData spawn, ref Vector3 spawnPoint)
+ {
+ ZoneSystem.instance.GetGroundData(ref spawnPoint, out var normal, out var biome, out var biomeArea, out var hmap);
+ if ((spawn.m_biome & biome) == 0)
+ {
+ return false;
+ }
+ if ((spawn.m_biomeArea & biomeArea) == 0)
+ {
+ return false;
+ }
+ if (ZoneSystem.instance.IsBlocked(spawnPoint))
+ {
+ return false;
+ }
+ float num = spawnPoint.y - ZoneSystem.instance.m_waterLevel;
+ if (num < spawn.m_minAltitude || num > spawn.m_maxAltitude)
+ {
+ return false;
+ }
+ float num2 = Mathf.Cos((float)Math.PI / 180f * spawn.m_maxTilt);
+ float num3 = Mathf.Cos((float)Math.PI / 180f * spawn.m_minTilt);
+ if (normal.y < num2 || normal.y > num3)
+ {
+ return false;
+ }
+ float range = ((spawn.m_spawnRadiusMin > 0f) ? spawn.m_spawnRadiusMin : 40f);
+ if (Player.IsPlayerInRange(spawnPoint, range))
+ {
+ return false;
+ }
+ if ((bool)EffectArea.IsPointInsideArea(spawnPoint, EffectArea.Type.PlayerBase))
+ {
+ return false;
+ }
+ if (!spawn.m_inForest || !spawn.m_outsideForest)
+ {
+ bool flag = WorldGenerator.InForest(spawnPoint);
+ if (!spawn.m_inForest && flag)
+ {
+ return false;
+ }
+ if (!spawn.m_outsideForest && !flag)
+ {
+ return false;
+ }
+ }
+ if (spawn.m_minOceanDepth != spawn.m_maxOceanDepth && hmap != null)
+ {
+ float oceanDepth = hmap.GetOceanDepth(spawnPoint);
+ if (oceanDepth < spawn.m_minOceanDepth || oceanDepth > spawn.m_maxOceanDepth)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private bool FindBaseSpawnPoint(SpawnData spawn, List<Player> allPlayers, out Vector3 spawnCenter, out Player targetPlayer)
+ {
+ float min = ((spawn.m_spawnRadiusMin > 0f) ? spawn.m_spawnRadiusMin : 40f);
+ float max = ((spawn.m_spawnRadiusMax > 0f) ? spawn.m_spawnRadiusMax : 80f);
+ for (int i = 0; i < 20; i++)
+ {
+ Player player = allPlayers[UnityEngine.Random.Range(0, allPlayers.Count)];
+ Vector3 vector = Quaternion.Euler(0f, UnityEngine.Random.Range(0, 360), 0f) * Vector3.forward;
+ Vector3 spawnPoint = player.transform.position + vector * UnityEngine.Random.Range(min, max);
+ if (IsSpawnPointGood(spawn, ref spawnPoint))
+ {
+ spawnCenter = spawnPoint;
+ targetPlayer = player;
+ return true;
+ }
+ }
+ spawnCenter = Vector3.zero;
+ targetPlayer = null;
+ return false;
+ }
+
+ private int GetNrOfInstances(string prefabName)
+ {
+ List<Character> allCharacters = Character.GetAllCharacters();
+ int num = 0;
+ foreach (Character item in allCharacters)
+ {
+ if (item.gameObject.name.StartsWith(prefabName) && InsideZone(item.transform.position))
+ {
+ num++;
+ }
+ }
+ return num;
+ }
+
+ private void GetPlayersInZone(List<Player> players)
+ {
+ foreach (Player allPlayer in Player.GetAllPlayers())
+ {
+ if (InsideZone(allPlayer.transform.position))
+ {
+ players.Add(allPlayer);
+ }
+ }
+ }
+
+ private void GetPlayersNearZone(List<Player> players, float marginDistance)
+ {
+ foreach (Player allPlayer in Player.GetAllPlayers())
+ {
+ if (InsideZone(allPlayer.transform.position, marginDistance))
+ {
+ players.Add(allPlayer);
+ }
+ }
+ }
+
+ private bool IsPlayerTooClose(List<Player> players, Vector3 point, float minDistance)
+ {
+ foreach (Player player in players)
+ {
+ if (Vector3.Distance(player.transform.position, point) < minDistance)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private bool InPlayerRange(List<Player> players, Vector3 point, float minDistance, float maxDistance)
+ {
+ bool result = false;
+ foreach (Player player in players)
+ {
+ float num = Utils.DistanceXZ(player.transform.position, point);
+ if (num < minDistance)
+ {
+ return false;
+ }
+ if (num < maxDistance)
+ {
+ result = true;
+ }
+ }
+ return result;
+ }
+
+ private static bool HaveInstanceInRange(GameObject prefab, Vector3 centerPoint, float minDistance)
+ {
+ string value = prefab.name;
+ if (prefab.GetComponent<BaseAI>() != null)
+ {
+ foreach (BaseAI allInstance in BaseAI.GetAllInstances())
+ {
+ if (allInstance.gameObject.name.StartsWith(value) && Utils.DistanceXZ(allInstance.transform.position, centerPoint) < minDistance)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+ GameObject[] array = GameObject.FindGameObjectsWithTag("spawned");
+ foreach (GameObject gameObject in array)
+ {
+ if (gameObject.gameObject.name.StartsWith(value) && Utils.DistanceXZ(gameObject.transform.position, centerPoint) < minDistance)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static int GetNrOfInstances(GameObject prefab)
+ {
+ return GetNrOfInstances(prefab, Vector3.zero, 0f);
+ }
+
+ public static int GetNrOfInstances(GameObject prefab, Vector3 center, float maxRange, bool eventCreaturesOnly = false, bool procreationOnly = false)
+ {
+ string text = prefab.name + "(Clone)";
+ if (prefab.GetComponent<BaseAI>() != null)
+ {
+ List<BaseAI> allInstances = BaseAI.GetAllInstances();
+ int num = 0;
+ {
+ foreach (BaseAI item in allInstances)
+ {
+ if (item.gameObject.name != text || (maxRange > 0f && Vector3.Distance(center, item.transform.position) > maxRange))
+ {
+ continue;
+ }
+ if (eventCreaturesOnly)
+ {
+ MonsterAI monsterAI = item as MonsterAI;
+ if ((bool)monsterAI && !monsterAI.IsEventCreature())
+ {
+ continue;
+ }
+ }
+ if (procreationOnly)
+ {
+ Procreation component = item.GetComponent<Procreation>();
+ if ((bool)component && !component.ReadyForProcreation())
+ {
+ continue;
+ }
+ }
+ num++;
+ }
+ return num;
+ }
+ }
+ GameObject[] array = GameObject.FindGameObjectsWithTag("spawned");
+ int num2 = 0;
+ GameObject[] array2 = array;
+ foreach (GameObject gameObject in array2)
+ {
+ if (gameObject.name.StartsWith(text) && (!(maxRange > 0f) || !(Vector3.Distance(center, gameObject.transform.position) > maxRange)))
+ {
+ num2++;
+ }
+ }
+ return num2;
+ }
+
+ public void GetSpawners(Heightmap.Biome biome, List<SpawnData> spawners)
+ {
+ foreach (SpawnData spawner in m_spawners)
+ {
+ if ((spawner.m_biome & biome) != 0 || spawner.m_biome == biome)
+ {
+ spawners.Add(spawner);
+ }
+ }
+ }
+
+ private bool InsideZone(Vector3 point, float extra = 0f)
+ {
+ float num = ZoneSystem.instance.m_zoneSize * 0.5f + extra;
+ Vector3 position = base.transform.position;
+ if (point.x < position.x - num || point.x > position.x + num)
+ {
+ return false;
+ }
+ if (point.z < position.z - num || point.z > position.z + num)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ private bool HaveGlobalKeys(SpawnData ev)
+ {
+ if (!string.IsNullOrEmpty(ev.m_requiredGlobalKey))
+ {
+ return ZoneSystem.instance.GetGlobalKey(ev.m_requiredGlobalKey);
+ }
+ return true;
+ }
+}