SanAndreasUnity/Assets/Scripts/Behaviours/SpawnManager.cs

195 lines
5.8 KiB
C#
Raw Normal View History

2019-04-24 14:58:13 +00:00
using System.Collections.Generic;
using UnityEngine;
2019-04-24 17:18:18 +00:00
using SanAndreasUnity.Net;
using SanAndreasUnity.Utilities;
using System.Linq;
2019-04-24 14:58:13 +00:00
namespace SanAndreasUnity.Behaviours
{
public class SpawnManager : MonoBehaviour
{
public static SpawnManager Instance { get; private set; }
2019-04-24 23:14:06 +00:00
public bool spawnPlayerWhenConnected = true;
public bool IsSpawningPaused { get; set; } = false;
public float spawnInterval = 4f;
float m_lastSpawnTime = 0f;
2021-02-21 01:35:26 +00:00
public bool addWeaponsToSpawnedPlayers = true;
public static SpawnHandler DefaultSpawnHandler { get; } = new SpawnHandler();
private SpawnHandler m_spawnHandler = DefaultSpawnHandler;
public SpawnHandler SpawnHandler
{
get => m_spawnHandler;
set
{
if (value == null)
value = DefaultSpawnHandler;
m_spawnHandler = value;
}
}
2019-04-24 14:58:13 +00:00
void Awake()
{
Instance = this;
}
2019-04-24 14:58:13 +00:00
void Start()
{
this.InvokeRepeating(nameof(RepeatedMethod), 1f, 1f);
2019-04-24 23:14:06 +00:00
Player.onStart += OnPlayerConnected;
2019-04-24 14:58:13 +00:00
}
void OnLoaderFinished()
{
if (!NetStatus.IsServer)
return;
// spawn players that were connected during loading process - this will always be the case for
// local player
SpawnPlayers();
}
public static Transform GetSpawnFocusPos()
2019-04-24 17:58:40 +00:00
{
if (Ped.Instance)
return Ped.Instance.transform;
if (Camera.main)
return Camera.main.transform;
return null;
}
void RepeatedMethod()
{
if (!NetStatus.IsServer)
return;
if (this.IsSpawningPaused)
return;
if (Time.time - m_lastSpawnTime >= this.spawnInterval)
{
// enough time passed
m_lastSpawnTime = Time.time;
2020-06-05 22:45:53 +00:00
F.RunExceptionSafe(() => this.SpawnPlayers());
}
}
public static bool GetSpawnPositionFromFocus(Transform focusPos, out TransformDataStruct transformData)
{
if (Player.AllPlayersList.Count <= 1)
// if there is only 1 player, always spawn him on the same place - no randomization
transformData = new TransformDataStruct(focusPos);
else
transformData = new TransformDataStruct(
focusPos.position + Random.insideUnitCircle.ToVector3XZ() * 15f,
Quaternion.Euler(0f, Random.Range(0f, 360f), 0f));
return true;
}
public static bool GetSpawnPositionFromFocus(out TransformDataStruct transformData)
2019-04-24 14:58:13 +00:00
{
2019-04-24 17:58:40 +00:00
Transform focusPos = GetSpawnFocusPos();
if (null == focusPos)
{
transformData = new TransformDataStruct();
return false;
2019-04-24 14:58:13 +00:00
}
return GetSpawnPositionFromFocus(focusPos, out transformData);
2019-04-24 14:58:13 +00:00
}
public static bool GetSpawnPositionFromInteriors(out TransformDataStruct transformData)
{
new world loading system (#110) * wip * much faster world creation * add StaticGeometryInspector * disable child/parent logic and fading * rename * (de)activate objects based on parent * set draw distance based on layers * ... * wip * wip * wip * remove unused param * prevent concurrent modification * ... * catch exceptions when notifying * ... * notify about area, not objects * limit public access to Area * ... * ... * allow public access * add public api * adapt code * pass callback to ctor * adapt focus points * fix * fix intersection check * support rectangles * adjust parameters in prefab * this should fix IsInsideOf() * ... * ... * fix getting area by index * create area if not exists * ... * ... * ... * wip for distance levels * remove constraint on generic parameter * add some validation * fix * fix draw distance per level * change time of day in which lights are visible * add todos * don't use id for UnRegisterFocusPoint() * use hash set for storing focus points * add 1 more level * mark area for update only if visibility changes * profile WorldSystem calls * add some profiling sections * limit time per frame for LoadingThread * switch custom concurrent queue * copy jobs to buffer * rename * change max draw distance setting * wait one more frame * try to remove 801 distance level to remove holes * attempt to hide interiors, but failed * delete no longer needed script * optimization * some error checking * add camera as focus point * dont add camera as focus point in headless mode * working on load priority * fix bug - load priority finished * ... * small optimizations * ... * ... * remove unneeded variable * add fading * dont do fading in headless mode * fadeRate available in inspector * change fade rate * take into account if geometry is loaded when checking if object should be visible, and if fading should be done * small optimization * cache IsInHeadlessMode * display Instance info in inspector * move interiors up in the sky * rename * adapt code to different y pos of interiors * refactor * fix finding matched enex for enexes that lead to the same interior level * display new world stats * rename * rename class * ... * ... * extract function * extract parameters into a struct * add focus point to dead body * add focus point to vehicle * add focus point to vehicle detached parts * remove OutOfRangeDestroyer from vehicle, and destroy vehicle if it falls below the map * dont use focus points on vehicle and vehicle detached parts, when not on server * add focus point for npc peds * add possibility to set timeout during which focus point keeps revealing after it's destroyed * adapt UnRegisterFocusPoint() to timeout * rename * adapt code * cleanup MapObject class * ... * converting to `lock()` * optimize method: use 1 lock instead of 3 * call OnObjectFinishedLoading() instead of AddToLoadedObjects() * ... * make sure it's main thread * AsyncLoader is no longer thread safe * convert static members to non-static in LoadingThread * fix * ... * store indexes for each area * impl GetAreaCenter() * calculate load priority based on distance to area, not objects ; limit time per frame ; sort area in Cell, not in concurrent SortedSet ; * add support for changing draw distance at runtime * delay setting the new value by 0.2 s * have a separate default max draw distance for mobile platforms * adjust y axis world params so that number of visible areas is reduced * remove "camera far clip plane" setting * rename * document flags * rename * disable shadow casting and receiving for some objects * allow casting shadows for LODs with large draw distance * remove "WorldSystem" layer * revert layer
2021-07-18 04:03:43 +00:00
transformData = World.Cell.Instance.GetEnexExitTransform(
World.Cell.Instance.GetEnexesFromLoadedInteriors()
.ToList()
.RandomElement());
return true;
}
bool GetSpawnPositionFromHandler(Player player, out TransformDataStruct transformData)
{
bool success = false;
TransformDataStruct t = new TransformDataStruct();
F.RunExceptionSafe(() =>
{
success = this.SpawnHandler.GetSpawnPosition(player, out t);
});
transformData = t;
return success;
}
2019-04-24 17:18:18 +00:00
void SpawnPlayers()
{
if (!NetStatus.IsServer)
return;
2019-04-24 17:39:38 +00:00
if (!Loader.HasLoaded)
return;
TransformDataStruct transformData;
2021-07-18 19:07:27 +00:00
foreach (var player in Player.AllPlayersCopy)
2019-04-24 17:18:18 +00:00
{
if (this.GetSpawnPositionFromHandler(player, out transformData))
SpawnPlayer(player, transformData);
else
break;
2019-04-24 23:14:06 +00:00
}
2019-04-24 17:18:18 +00:00
2019-04-24 23:14:06 +00:00
}
2019-04-24 17:18:18 +00:00
2021-02-21 01:35:26 +00:00
public Ped SpawnPlayer (Player player, TransformDataStruct spawnPlace)
2019-04-24 23:14:06 +00:00
{
if (player.OwnedPed != null)
return null;
2019-04-24 17:18:18 +00:00
var ped = Ped.SpawnPed(Ped.RandomPedId, spawnPlace.position, spawnPlace.rotation, false);
ped.NetPlayerOwnerGameObject = player.gameObject;
2021-02-21 01:35:26 +00:00
if (this.addWeaponsToSpawnedPlayers)
ped.WeaponHolder.autoAddWeapon = true;
// this ped should not be destroyed when he gets out of range
ped.gameObject.DestroyComponent<OutOfRangeDestroyer>();
2019-04-24 23:14:06 +00:00
NetManager.Spawn(ped.gameObject);
player.OwnedPed = ped;
2019-07-11 16:26:54 +00:00
Debug.LogFormat("Spawned ped {0} for player {1}, time: {2}", ped.DescriptionForLogging, player.DescriptionForLogging,
F.CurrentDateForLogging);
2019-04-24 23:14:06 +00:00
return ped;
}
void OnPlayerConnected(Player player)
{
if (!NetStatus.IsServer)
return;
if (!Loader.HasLoaded) // these players will be spawned when loading process finishes
return;
2019-04-24 23:14:06 +00:00
if (!this.spawnPlayerWhenConnected)
return;
2019-04-24 17:18:18 +00:00
if (this.GetSpawnPositionFromHandler(player, out TransformDataStruct transformData))
SpawnPlayer(player, transformData);
2019-04-24 17:18:18 +00:00
}
2019-04-24 14:58:13 +00:00
}
}