286 lines
6.1 KiB
C#
286 lines
6.1 KiB
C#
|
using System.Runtime.InteropServices;
|
||
|
using RoR2.ExpansionManagement;
|
||
|
using UnityEngine;
|
||
|
using UnityEngine.Networking;
|
||
|
|
||
|
namespace RoR2;
|
||
|
|
||
|
public class PortalSpawner : NetworkBehaviour
|
||
|
{
|
||
|
[SerializeField]
|
||
|
private InteractableSpawnCard portalSpawnCard;
|
||
|
|
||
|
[Range(0f, 1f)]
|
||
|
[SerializeField]
|
||
|
private float spawnChance;
|
||
|
|
||
|
[SerializeField]
|
||
|
[Tooltip("The portal is spawned relative to this transform. If null, it uses this object's transform for reference.")]
|
||
|
private Transform spawnReferenceLocation;
|
||
|
|
||
|
[SerializeField]
|
||
|
private float minSpawnDistance;
|
||
|
|
||
|
[Tooltip("The maximum spawn distance for the portal relative to the spawnReferenceLocation. If 0, it will be spawned at exactly the referenced location.")]
|
||
|
[SerializeField]
|
||
|
private float maxSpawnDistance;
|
||
|
|
||
|
[SerializeField]
|
||
|
private string spawnPreviewMessageToken;
|
||
|
|
||
|
[SerializeField]
|
||
|
private string spawnMessageToken;
|
||
|
|
||
|
[SerializeField]
|
||
|
private ChildLocator modelChildLocator;
|
||
|
|
||
|
[SerializeField]
|
||
|
private string previewChildName;
|
||
|
|
||
|
[SerializeField]
|
||
|
private ExpansionDef requiredExpansion;
|
||
|
|
||
|
[SerializeField]
|
||
|
private int minStagesCleared;
|
||
|
|
||
|
[SerializeField]
|
||
|
private string bannedEventFlag;
|
||
|
|
||
|
[SerializeField]
|
||
|
private string requiredEventFlag;
|
||
|
|
||
|
[SerializeField]
|
||
|
private string[] validStages;
|
||
|
|
||
|
[SerializeField]
|
||
|
private string[] invalidStages;
|
||
|
|
||
|
[SerializeField]
|
||
|
private int[] validStageTiers;
|
||
|
|
||
|
private Xoroshiro128Plus rng;
|
||
|
|
||
|
private GameObject previewChild;
|
||
|
|
||
|
[SyncVar(hook = "OnWillSpawnUpdated")]
|
||
|
private bool willSpawn;
|
||
|
|
||
|
public bool NetworkwillSpawn
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return willSpawn;
|
||
|
}
|
||
|
[param: In]
|
||
|
set
|
||
|
{
|
||
|
if (NetworkServer.localClientActive && !base.syncVarHookGuard)
|
||
|
{
|
||
|
base.syncVarHookGuard = true;
|
||
|
OnWillSpawnUpdated(value);
|
||
|
base.syncVarHookGuard = false;
|
||
|
}
|
||
|
SetSyncVar(value, ref willSpawn, 1u);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void Start()
|
||
|
{
|
||
|
GetPreviewChild();
|
||
|
if (!NetworkServer.active)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
rng = new Xoroshiro128Plus(Run.instance.stageRng.nextUlong);
|
||
|
bool flag = !requiredExpansion || Run.instance.IsExpansionEnabled(requiredExpansion);
|
||
|
bool flag2 = Run.instance.stageClearCount >= minStagesCleared;
|
||
|
bool flag3 = string.IsNullOrEmpty(bannedEventFlag) || !Run.instance.GetEventFlag(bannedEventFlag);
|
||
|
if ((string.IsNullOrEmpty(requiredEventFlag) || Run.instance.GetEventFlag(requiredEventFlag)) && flag3 && rng.nextNormalizedFloat <= spawnChance && flag && flag2 && isValidStage())
|
||
|
{
|
||
|
NetworkwillSpawn = true;
|
||
|
if (!string.IsNullOrEmpty(spawnPreviewMessageToken))
|
||
|
{
|
||
|
Chat.SendBroadcastChat(new Chat.SimpleChatMessage
|
||
|
{
|
||
|
baseToken = spawnPreviewMessageToken
|
||
|
});
|
||
|
}
|
||
|
if ((bool)previewChild)
|
||
|
{
|
||
|
previewChild.SetActive(value: true);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void GetPreviewChild()
|
||
|
{
|
||
|
if ((bool)modelChildLocator)
|
||
|
{
|
||
|
Transform transform = modelChildLocator.FindChild(previewChildName);
|
||
|
if ((bool)transform)
|
||
|
{
|
||
|
previewChild = transform.gameObject;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private bool isValidStage()
|
||
|
{
|
||
|
bool result = false;
|
||
|
bool flag = false;
|
||
|
if (validStages.Length != 0)
|
||
|
{
|
||
|
string baseSceneNameOverride = Stage.instance.sceneDef.baseSceneNameOverride;
|
||
|
for (int i = 0; i < validStages.Length; i++)
|
||
|
{
|
||
|
if (validStages[i] == baseSceneNameOverride)
|
||
|
{
|
||
|
flag = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (validStages.Length == 0)
|
||
|
{
|
||
|
flag = true;
|
||
|
}
|
||
|
bool flag2 = false;
|
||
|
if (invalidStages.Length != 0)
|
||
|
{
|
||
|
string baseSceneNameOverride2 = Stage.instance.sceneDef.baseSceneNameOverride;
|
||
|
for (int j = 0; j < invalidStages.Length; j++)
|
||
|
{
|
||
|
if (invalidStages[j] == baseSceneNameOverride2)
|
||
|
{
|
||
|
flag2 = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
bool flag3 = false;
|
||
|
if (validStageTiers.Length != 0)
|
||
|
{
|
||
|
int stageOrder = Stage.instance.sceneDef.stageOrder;
|
||
|
for (int k = 0; k < validStageTiers.Length; k++)
|
||
|
{
|
||
|
if (validStageTiers[k] == stageOrder)
|
||
|
{
|
||
|
flag3 = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (validStageTiers.Length == 0)
|
||
|
{
|
||
|
flag3 = true;
|
||
|
}
|
||
|
if (flag && !flag2 && flag3)
|
||
|
{
|
||
|
result = true;
|
||
|
}
|
||
|
_ = flag && flag2;
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
[Server]
|
||
|
public bool AttemptSpawnPortalServer()
|
||
|
{
|
||
|
if (!NetworkServer.active)
|
||
|
{
|
||
|
Debug.LogWarning("[Server] function 'System.Boolean RoR2.PortalSpawner::AttemptSpawnPortalServer()' called on client");
|
||
|
return false;
|
||
|
}
|
||
|
if (willSpawn)
|
||
|
{
|
||
|
if ((bool)previewChild)
|
||
|
{
|
||
|
previewChild.SetActive(value: false);
|
||
|
}
|
||
|
NetworkwillSpawn = false;
|
||
|
DirectorPlacementRule.PlacementMode placementMode = DirectorPlacementRule.PlacementMode.Approximate;
|
||
|
if (maxSpawnDistance <= 0f)
|
||
|
{
|
||
|
placementMode = DirectorPlacementRule.PlacementMode.Direct;
|
||
|
}
|
||
|
Transform transform = spawnReferenceLocation;
|
||
|
if (!transform)
|
||
|
{
|
||
|
transform = base.transform;
|
||
|
}
|
||
|
GameObject obj = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(portalSpawnCard, new DirectorPlacementRule
|
||
|
{
|
||
|
minDistance = minSpawnDistance,
|
||
|
maxDistance = maxSpawnDistance,
|
||
|
placementMode = placementMode,
|
||
|
position = base.transform.position,
|
||
|
spawnOnTarget = transform
|
||
|
}, rng));
|
||
|
if ((bool)obj && !string.IsNullOrEmpty(spawnMessageToken))
|
||
|
{
|
||
|
Chat.SendBroadcastChat(new Chat.SimpleChatMessage
|
||
|
{
|
||
|
baseToken = spawnMessageToken
|
||
|
});
|
||
|
}
|
||
|
return obj;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
private void OnWillSpawnUpdated(bool newValue)
|
||
|
{
|
||
|
NetworkwillSpawn = newValue;
|
||
|
if (previewChild == null)
|
||
|
{
|
||
|
GetPreviewChild();
|
||
|
}
|
||
|
if ((bool)previewChild)
|
||
|
{
|
||
|
previewChild.SetActive(newValue);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void UNetVersion()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
public override bool OnSerialize(NetworkWriter writer, bool forceAll)
|
||
|
{
|
||
|
if (forceAll)
|
||
|
{
|
||
|
writer.Write(willSpawn);
|
||
|
return true;
|
||
|
}
|
||
|
bool flag = false;
|
||
|
if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
|
||
|
{
|
||
|
if (!flag)
|
||
|
{
|
||
|
writer.WritePackedUInt32(base.syncVarDirtyBits);
|
||
|
flag = true;
|
||
|
}
|
||
|
writer.Write(willSpawn);
|
||
|
}
|
||
|
if (!flag)
|
||
|
{
|
||
|
writer.WritePackedUInt32(base.syncVarDirtyBits);
|
||
|
}
|
||
|
return flag;
|
||
|
}
|
||
|
|
||
|
public override void OnDeserialize(NetworkReader reader, bool initialState)
|
||
|
{
|
||
|
if (initialState)
|
||
|
{
|
||
|
willSpawn = reader.ReadBoolean();
|
||
|
return;
|
||
|
}
|
||
|
int num = (int)reader.ReadPackedUInt32();
|
||
|
if (((uint)num & (true ? 1u : 0u)) != 0)
|
||
|
{
|
||
|
OnWillSpawnUpdated(reader.ReadBoolean());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override void PreStartClient()
|
||
|
{
|
||
|
}
|
||
|
}
|