r2mods/ilspy_dump/ror2_csproj/RoR2/PreGameController.cs

766 lines
21 KiB
C#

using System;
using System.Collections.ObjectModel;
using System.Runtime.InteropServices;
using JetBrains.Annotations;
using RoR2.ConVar;
using RoR2.EntitlementManagement;
using RoR2.ExpansionManagement;
using UnityEngine;
using UnityEngine.Networking;
namespace RoR2;
[RequireComponent(typeof(NetworkRuleChoiceMask))]
[RequireComponent(typeof(NetworkRuleBook))]
public class PreGameController : NetworkBehaviour
{
private enum PregameState
{
Idle,
Launching,
Launched
}
public class GameModeConVar : BaseConVar
{
public static readonly GameModeConVar instance;
public Run runPrefabComponent;
public GameModeConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
: base(name, flags, defaultValue, helpText)
{
}
static GameModeConVar()
{
instance = new GameModeConVar("gamemode", ConVarFlags.None, "ClassicRun", "Sets the specified game mode as the one to use in the next run.");
GameModeCatalog.availability.CallWhenAvailable(delegate
{
instance.runPrefabComponent = GameModeCatalog.FindGameModePrefabComponent(instance.GetString());
});
}
public override void SetString(string newValue)
{
GameModeCatalog.availability.CallWhenAvailable(delegate
{
Run run = GameModeCatalog.FindGameModePrefabComponent(newValue);
if (!run)
{
Debug.LogFormat("GameMode \"{0}\" does not exist.", newValue);
}
else
{
runPrefabComponent = run;
}
});
}
public override string GetString()
{
if (!runPrefabComponent)
{
return "ClassicRun";
}
return runPrefabComponent.gameObject.name;
}
}
private NetworkRuleChoiceMask networkRuleChoiceMaskComponent;
private NetworkRuleBook networkRuleBookComponent;
private RuleChoiceMask serverAvailableChoiceMask;
public ulong runSeed;
public static readonly IntConVar overrideRunSeed;
[SyncVar(hook = "UpdateGameModeIndex")]
private int _gameModeIndex;
private GameObject lobbyBackground;
private int currentLobbyBackgroundGameModeIndex;
private float lobbyBackgroundTimeToRefresh;
private const float lobbyBackgroundTimeToRefreshInterval = 4f;
private RuleBook ruleBookBuffer;
[SyncVar]
private int pregameStateInternal;
private const float launchTransitionDuration = 0f;
private GameObject gameModePrefab;
[SyncVar]
private float launchStartTime = float.PositiveInfinity;
private RuleChoiceMask unlockedChoiceMask;
private RuleChoiceMask dependencyChoiceMask;
private RuleChoiceMask entitlementChoiceMask;
private RuleChoiceMask requiredExpansionEnabledChoiceMask;
private RuleChoiceMask choiceMaskBuffer;
public static readonly BoolConVar cvSvAllowRuleVoting;
public static readonly BoolConVar cvSvAllowMultiplayerPause;
private static int kRpcRpcUpdateGameModeIndex;
private static int kRpcRpcUpdateMultiplayerPause;
public static PreGameController instance { get; private set; }
public RuleChoiceMask resolvedRuleChoiceMask => networkRuleChoiceMaskComponent.ruleChoiceMask;
public RuleBook readOnlyRuleBook => networkRuleBookComponent.ruleBook;
public GameModeIndex gameModeIndex
{
get
{
return (GameModeIndex)_gameModeIndex;
}
set
{
Network_gameModeIndex = (int)value;
}
}
private PregameState pregameState
{
get
{
return (PregameState)pregameStateInternal;
}
set
{
NetworkpregameStateInternal = (int)value;
}
}
public int Network_gameModeIndex
{
get
{
return _gameModeIndex;
}
[param: In]
set
{
if (NetworkServer.localClientActive && !base.syncVarHookGuard)
{
base.syncVarHookGuard = true;
UpdateGameModeIndex(value);
base.syncVarHookGuard = false;
}
SetSyncVar(value, ref _gameModeIndex, 1u);
}
}
public int NetworkpregameStateInternal
{
get
{
return pregameStateInternal;
}
[param: In]
set
{
SetSyncVar(value, ref pregameStateInternal, 2u);
}
}
public float NetworklaunchStartTime
{
get
{
return launchStartTime;
}
[param: In]
set
{
SetSyncVar(value, ref launchStartTime, 4u);
}
}
public static event Action<PreGameController, RuleBook> onPreGameControllerSetRuleBookServerGlobal;
public static event Action<PreGameController, RuleBook> onPreGameControllerSetRuleBookGlobal;
public static event Action<PreGameController> onServerRecalculatedModifierAvailability;
private void Awake()
{
lobbyBackgroundTimeToRefresh = 0f;
networkRuleChoiceMaskComponent = GetComponent<NetworkRuleChoiceMask>();
networkRuleBookComponent = GetComponent<NetworkRuleBook>();
networkRuleBookComponent.onRuleBookUpdated += OnRuleBookUpdated;
ruleBookBuffer = new RuleBook();
serverAvailableChoiceMask = new RuleChoiceMask();
unlockedChoiceMask = new RuleChoiceMask();
dependencyChoiceMask = new RuleChoiceMask();
entitlementChoiceMask = new RuleChoiceMask();
choiceMaskBuffer = new RuleChoiceMask();
requiredExpansionEnabledChoiceMask = new RuleChoiceMask();
if (NetworkServer.active)
{
gameModeIndex = GameModeCatalog.FindGameModeIndex(GameModeConVar.instance.GetString());
runSeed = GameModeCatalog.GetGameModePrefabComponent(gameModeIndex).GenerateSeedForNewRun();
}
bool isInSinglePlayer = RoR2Application.isInSinglePlayer;
for (int i = 0; i < serverAvailableChoiceMask.length; i++)
{
RuleChoiceDef choiceDef = RuleCatalog.GetChoiceDef(i);
serverAvailableChoiceMask[i] = (isInSinglePlayer ? choiceDef.availableInSinglePlayer : choiceDef.availableInMultiPlayer);
}
NetworkUser.OnPostNetworkUserStart += GenerateRuleVoteController;
RefreshLobbyBackground();
}
private void OnDestroy()
{
NetworkUser.OnPostNetworkUserStart -= GenerateRuleVoteController;
}
private void GenerateRuleVoteController(NetworkUser networkUser)
{
if (NetworkServer.active && !PreGameRuleVoteController.FindForUser(networkUser) && (networkUser.isLocalPlayer || cvSvAllowRuleVoting.value))
{
PreGameRuleVoteController.CreateForNetworkUserServer(networkUser);
}
}
private void Start()
{
if (!NetworkServer.active)
{
return;
}
ResolveChoiceMask();
Console.instance.SubmitCmd(null, "exec server_pregame");
foreach (NetworkUser readOnlyInstances in NetworkUser.readOnlyInstancesList)
{
Debug.LogFormat("Attempting to generate PreGameVoteController for {0}", readOnlyInstances.userName);
GenerateRuleVoteController(readOnlyInstances);
readOnlyInstances.BumpDLCChecker();
}
}
[Server]
public bool ApplyChoice(int ruleChoiceIndex)
{
if (!NetworkServer.active)
{
Debug.LogWarning("[Server] function 'System.Boolean RoR2.PreGameController::ApplyChoice(System.Int32)' called on client");
return false;
}
if (!resolvedRuleChoiceMask[ruleChoiceIndex])
{
return false;
}
RuleChoiceDef choiceDef = RuleCatalog.GetChoiceDef(ruleChoiceIndex);
if (readOnlyRuleBook.GetRuleChoice(choiceDef.ruleDef.globalIndex) == choiceDef)
{
return false;
}
ruleBookBuffer.Copy(readOnlyRuleBook);
ruleBookBuffer.ApplyChoice(choiceDef);
SetRuleBook(ruleBookBuffer);
return true;
}
private void SetRuleBook(RuleBook newRuleBook)
{
networkRuleBookComponent.SetRuleBook(newRuleBook);
PreGameController.onPreGameControllerSetRuleBookServerGlobal?.Invoke(this, readOnlyRuleBook);
}
private void OnRuleBookUpdated(NetworkRuleBook networkRuleBookComponent)
{
PreGameController.onPreGameControllerSetRuleBookGlobal?.Invoke(this, networkRuleBookComponent.ruleBook);
}
[Server]
public void EnforceValidRuleChoices()
{
if (!NetworkServer.active)
{
Debug.LogWarning("[Server] function 'System.Void RoR2.PreGameController::EnforceValidRuleChoices()' called on client");
return;
}
ruleBookBuffer.Copy(readOnlyRuleBook);
for (int i = 0; i < RuleCatalog.ruleCount; i++)
{
RuleChoiceDef ruleChoice = ruleBookBuffer.GetRuleChoice(i);
if (resolvedRuleChoiceMask[ruleChoice])
{
continue;
}
RuleDef ruleDef = RuleCatalog.GetRuleDef(i);
RuleChoiceDef choiceDef = ruleDef.choices[ruleDef.defaultChoiceIndex];
int num = 0;
int j = 0;
for (int count = ruleDef.choices.Count; j < count; j++)
{
if (resolvedRuleChoiceMask[ruleDef.choices[j]])
{
num++;
}
}
if (resolvedRuleChoiceMask[choiceDef] || num == 0)
{
ruleBookBuffer.ApplyChoice(choiceDef);
continue;
}
int k = 0;
for (int count2 = ruleDef.choices.Count; k < count2; k++)
{
if (resolvedRuleChoiceMask[ruleDef.choices[k]])
{
ruleBookBuffer.ApplyChoice(ruleDef.choices[k]);
break;
}
}
}
SetRuleBook(ruleBookBuffer);
}
private void TestRuleValues()
{
RuleBook ruleBook = new RuleBook();
ruleBook.Copy(networkRuleBookComponent.ruleBook);
RuleDef ruleDef = RuleCatalog.GetRuleDef(UnityEngine.Random.Range(0, RuleCatalog.ruleCount));
RuleChoiceDef choiceDef = ruleDef.choices[UnityEngine.Random.Range(0, ruleDef.choices.Count)];
ruleBook.ApplyChoice(choiceDef);
SetRuleBook(ruleBook);
Invoke("TestRuleValues", 0.5f);
}
public override void OnStartClient()
{
base.OnStartClient();
PauseManager.isPaused = false;
PauseStopController.instance?.ForceClientUnpause();
}
private void OnEnable()
{
instance = SingletonHelper.Assign(instance, this);
if (NetworkServer.active)
{
RecalculateModifierAvailability();
}
NetworkUser.OnNetworkUserUnlockablesUpdated += OnNetworkUserUnlockablesUpdatedCallback;
NetworkUser.OnPostNetworkUserStart += OnPostNetworkUserStartCallback;
NetworkUser.onNetworkUserBodyPreferenceChanged += OnNetworkUserBodyPreferenceChanged;
NetworkUser.onNetworkUserLost += OnNetworkUserLost;
if (NetworkClient.active)
{
foreach (NetworkUser readOnlyLocalPlayers in NetworkUser.readOnlyLocalPlayersList)
{
readOnlyLocalPlayers.SendServerUnlockables();
}
}
if (!NetworkServer.active)
{
return;
}
foreach (NetworkUser readOnlyInstances in NetworkUser.readOnlyInstancesList)
{
readOnlyInstances.ServerRequestUnlockables();
}
}
private void OnDisable()
{
instance = SingletonHelper.Unassign(instance, this);
NetworkUser.OnPostNetworkUserStart -= OnPostNetworkUserStartCallback;
NetworkUser.OnNetworkUserUnlockablesUpdated -= OnNetworkUserUnlockablesUpdatedCallback;
NetworkUser.onNetworkUserBodyPreferenceChanged -= OnNetworkUserBodyPreferenceChanged;
NetworkUser.onNetworkUserLost -= OnNetworkUserLost;
}
public bool IsCharacterSwitchingCurrentlyAllowed()
{
return pregameState == PregameState.Idle;
}
private void Update()
{
if (pregameState == PregameState.Launching)
{
if (PlatformSystems.networkManager.unpredictedServerFixedTime - launchStartTime >= 0.5f && NetworkServer.active)
{
StartRun();
}
}
else
{
_ = pregameState;
_ = 2;
}
if (NetworkServer.active)
{
lobbyBackgroundTimeToRefresh -= Time.deltaTime;
if (lobbyBackgroundTimeToRefresh <= 0f)
{
lobbyBackgroundTimeToRefresh = 4f;
CallRpcUpdateGameModeIndex(_gameModeIndex);
CallRpcUpdateMultiplayerPause(cvSvAllowMultiplayerPause.value);
}
}
}
[Server]
public void StartLaunch()
{
if (!NetworkServer.active)
{
Debug.LogWarning("[Server] function 'System.Void RoR2.PreGameController::StartLaunch()' called on client");
}
else if (pregameState == PregameState.Idle)
{
pregameState = PregameState.Launching;
NetworklaunchStartTime = PlatformSystems.networkManager.unpredictedServerFixedTime;
}
}
[Server]
private void StartRun()
{
if (!NetworkServer.active)
{
Debug.LogWarning("[Server] function 'System.Void RoR2.PreGameController::StartRun()' called on client");
return;
}
ExpansionRequirementComponent component = GameModeConVar.instance.runPrefabComponent.GetComponent<ExpansionRequirementComponent>();
if (!component || !component.requiredExpansion || EntitlementManager.networkUserEntitlementTracker.AnyUserHasEntitlement(component.requiredExpansion.requiredEntitlement))
{
pregameState = PregameState.Launched;
NetworkSession.instance.BeginRun(GameModeConVar.instance.runPrefabComponent, readOnlyRuleBook, runSeed);
}
}
[ConCommand(commandName = "pregame_start_run", flags = ConVarFlags.SenderMustBeServer, helpText = "Begins a run out of pregame.")]
private static void CCPregameStartRun(ConCommandArgs args)
{
if ((bool)instance)
{
instance.StartRun();
}
}
private static bool AnyUserHasUnlockable([NotNull] UnlockableDef unlockableDef)
{
ReadOnlyCollection<NetworkUser> readOnlyInstancesList = NetworkUser.readOnlyInstancesList;
for (int i = 0; i < readOnlyInstancesList.Count; i++)
{
if (readOnlyInstancesList[i].unlockables.Contains(unlockableDef))
{
return true;
}
}
return false;
}
[ContextMenu("RecalculateModifierAvailability")]
[Server]
public void RecalculateModifierAvailability()
{
if (!NetworkServer.active)
{
Debug.LogWarning("[Server] function 'System.Void RoR2.PreGameController::RecalculateModifierAvailability()' called on client");
return;
}
for (int i = 0; i < RuleCatalog.choiceCount; i++)
{
RuleChoiceDef choiceDef = RuleCatalog.GetChoiceDef(i);
unlockedChoiceMask[i] = !choiceDef.requiredUnlockable || AnyUserHasUnlockable(choiceDef.requiredUnlockable);
dependencyChoiceMask[i] = choiceDef.requiredChoiceDef == null || readOnlyRuleBook.IsChoiceActive(choiceDef.requiredChoiceDef);
entitlementChoiceMask[i] = !choiceDef.requiredEntitlementDef || EntitlementManager.networkUserEntitlementTracker.AnyUserHasEntitlement(choiceDef.requiredEntitlementDef) || EntitlementManager.localUserEntitlementTracker.AnyUserHasEntitlement(choiceDef.requiredEntitlementDef);
requiredExpansionEnabledChoiceMask[i] = !choiceDef.requiredExpansionDef || readOnlyRuleBook.IsChoiceActive(choiceDef.requiredExpansionDef.enabledChoice);
}
ResolveChoiceMask();
PreGameController.onServerRecalculatedModifierAvailability?.Invoke(this);
}
[Server]
private void ResolveChoiceMask()
{
if (!NetworkServer.active)
{
Debug.LogWarning("[Server] function 'System.Void RoR2.PreGameController::ResolveChoiceMask()' called on client");
return;
}
RuleChoiceMask ruleChoiceMask = new RuleChoiceMask();
RuleChoiceMask ruleChoiceMask2 = new RuleChoiceMask();
Run gameModePrefabComponent = GameModeCatalog.GetGameModePrefabComponent(gameModeIndex);
if ((bool)gameModePrefabComponent)
{
if (overrideRunSeed.value != -1)
{
runSeed = (ulong)overrideRunSeed.value;
}
gameModePrefabComponent.OverrideRuleChoices(ruleChoiceMask, ruleChoiceMask2, runSeed);
}
for (int i = 0; i < choiceMaskBuffer.length; i++)
{
RuleChoiceDef choiceDef = RuleCatalog.GetChoiceDef(i);
bool flag = ruleChoiceMask[i];
bool flag2 = ruleChoiceMask2[i];
bool flag3 = serverAvailableChoiceMask[i];
bool flag4 = unlockedChoiceMask[i];
bool flag5 = dependencyChoiceMask[i];
bool flag6 = entitlementChoiceMask[i];
bool flag7 = requiredExpansionEnabledChoiceMask[i];
choiceMaskBuffer[i] = flag || (!flag2 && flag3 && flag4 && flag5 && flag6 && flag7 && !choiceDef.excludeByDefault);
}
networkRuleChoiceMaskComponent.SetRuleChoiceMask(choiceMaskBuffer);
EnforceValidRuleChoices();
}
private void OnNetworkUserUnlockablesUpdatedCallback(NetworkUser networkUser)
{
if (NetworkServer.active)
{
RecalculateModifierAvailability();
}
}
private void OnPostNetworkUserStartCallback(NetworkUser networkUser)
{
if (NetworkServer.active)
{
networkUser.ServerRequestUnlockables();
}
}
private void OnNetworkUserBodyPreferenceChanged(NetworkUser networkUser)
{
if (NetworkServer.active)
{
RecalculateModifierAvailability();
}
}
private void OnNetworkUserLost(NetworkUser networkUser)
{
if (NetworkServer.active)
{
RecalculateModifierAvailability();
}
}
private void UpdateGameModeIndex(int newIndex)
{
if (newIndex != currentLobbyBackgroundGameModeIndex)
{
Network_gameModeIndex = newIndex;
RefreshLobbyBackground();
}
}
private void UpdateMultiplayerPause(bool newBool)
{
if ((bool)PauseStopController.instance)
{
PauseStopController.instance.allowMultiplayerPause = newBool;
}
}
[ClientRpc]
private void RpcUpdateGameModeIndex(int newIndex)
{
UpdateGameModeIndex(newIndex);
}
[ClientRpc]
private void RpcUpdateMultiplayerPause(bool newBool)
{
UpdateMultiplayerPause(newBool);
}
private void RefreshLobbyBackground()
{
if ((bool)lobbyBackground)
{
UnityEngine.Object.Destroy(lobbyBackground);
}
currentLobbyBackgroundGameModeIndex = _gameModeIndex;
lobbyBackground = UnityEngine.Object.Instantiate(GameModeCatalog.GetGameModePrefabComponent(gameModeIndex).lobbyBackgroundPrefab);
}
[ConCommand(commandName = "pregame_set_rule_choice", flags = ConVarFlags.SenderMustBeServer, helpText = "Sets the specified choice during pregame. See the command \"rule_list_choices\" for possible options.")]
public static void CCPregameSetRuleChoice(ConCommandArgs args)
{
string argString = args.GetArgString(0);
RuleChoiceDef ruleChoiceDef = RuleCatalog.FindChoiceDef(argString);
if (ruleChoiceDef == null)
{
throw new ConCommandException($"'{argString}' is not a recognized rule choice name.");
}
if (!instance)
{
throw new ConCommandException("This command cannot be issued outside the character select screen.");
}
if (instance.ApplyChoice(ruleChoiceDef.globalIndex))
{
instance.RecalculateModifierAvailability();
}
}
static PreGameController()
{
overrideRunSeed = new IntConVar("override_run_seed", ConVarFlags.None, "-1", "Forces a default seed for benchmarking.");
cvSvAllowRuleVoting = new BoolConVar("sv_allow_rule_voting", ConVarFlags.None, "1", "Whether or not players are allowed to vote on rules.");
cvSvAllowMultiplayerPause = new BoolConVar("sv_allow_multiplayer_pause", ConVarFlags.None, "0", "Whether or not players are allowed to pause the multiplayer game.");
kRpcRpcUpdateGameModeIndex = -600953683;
NetworkBehaviour.RegisterRpcDelegate(typeof(PreGameController), kRpcRpcUpdateGameModeIndex, InvokeRpcRpcUpdateGameModeIndex);
kRpcRpcUpdateMultiplayerPause = 2048931628;
NetworkBehaviour.RegisterRpcDelegate(typeof(PreGameController), kRpcRpcUpdateMultiplayerPause, InvokeRpcRpcUpdateMultiplayerPause);
NetworkCRC.RegisterBehaviour("PreGameController", 0);
}
private void UNetVersion()
{
}
protected static void InvokeRpcRpcUpdateGameModeIndex(NetworkBehaviour obj, NetworkReader reader)
{
if (!NetworkClient.active)
{
Debug.LogError("RPC RpcUpdateGameModeIndex called on server.");
}
else
{
((PreGameController)obj).RpcUpdateGameModeIndex((int)reader.ReadPackedUInt32());
}
}
protected static void InvokeRpcRpcUpdateMultiplayerPause(NetworkBehaviour obj, NetworkReader reader)
{
if (!NetworkClient.active)
{
Debug.LogError("RPC RpcUpdateMultiplayerPause called on server.");
}
else
{
((PreGameController)obj).RpcUpdateMultiplayerPause(reader.ReadBoolean());
}
}
public void CallRpcUpdateGameModeIndex(int newIndex)
{
if (!NetworkServer.active)
{
Debug.LogError("RPC Function RpcUpdateGameModeIndex called on client.");
return;
}
NetworkWriter networkWriter = new NetworkWriter();
networkWriter.Write((short)0);
networkWriter.Write((short)2);
networkWriter.WritePackedUInt32((uint)kRpcRpcUpdateGameModeIndex);
networkWriter.Write(GetComponent<NetworkIdentity>().netId);
networkWriter.WritePackedUInt32((uint)newIndex);
SendRPCInternal(networkWriter, 0, "RpcUpdateGameModeIndex");
}
public void CallRpcUpdateMultiplayerPause(bool newBool)
{
if (!NetworkServer.active)
{
Debug.LogError("RPC Function RpcUpdateMultiplayerPause called on client.");
return;
}
NetworkWriter networkWriter = new NetworkWriter();
networkWriter.Write((short)0);
networkWriter.Write((short)2);
networkWriter.WritePackedUInt32((uint)kRpcRpcUpdateMultiplayerPause);
networkWriter.Write(GetComponent<NetworkIdentity>().netId);
networkWriter.Write(newBool);
SendRPCInternal(networkWriter, 0, "RpcUpdateMultiplayerPause");
}
public override bool OnSerialize(NetworkWriter writer, bool forceAll)
{
if (forceAll)
{
writer.WritePackedUInt32((uint)_gameModeIndex);
writer.WritePackedUInt32((uint)pregameStateInternal);
writer.Write(launchStartTime);
return true;
}
bool flag = false;
if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
{
if (!flag)
{
writer.WritePackedUInt32(base.syncVarDirtyBits);
flag = true;
}
writer.WritePackedUInt32((uint)_gameModeIndex);
}
if ((base.syncVarDirtyBits & 2u) != 0)
{
if (!flag)
{
writer.WritePackedUInt32(base.syncVarDirtyBits);
flag = true;
}
writer.WritePackedUInt32((uint)pregameStateInternal);
}
if ((base.syncVarDirtyBits & 4u) != 0)
{
if (!flag)
{
writer.WritePackedUInt32(base.syncVarDirtyBits);
flag = true;
}
writer.Write(launchStartTime);
}
if (!flag)
{
writer.WritePackedUInt32(base.syncVarDirtyBits);
}
return flag;
}
public override void OnDeserialize(NetworkReader reader, bool initialState)
{
if (initialState)
{
_gameModeIndex = (int)reader.ReadPackedUInt32();
pregameStateInternal = (int)reader.ReadPackedUInt32();
launchStartTime = reader.ReadSingle();
return;
}
int num = (int)reader.ReadPackedUInt32();
if (((uint)num & (true ? 1u : 0u)) != 0)
{
UpdateGameModeIndex((int)reader.ReadPackedUInt32());
}
if (((uint)num & 2u) != 0)
{
pregameStateInternal = (int)reader.ReadPackedUInt32();
}
if (((uint)num & 4u) != 0)
{
launchStartTime = reader.ReadSingle();
}
}
public override void PreStartClient()
{
}
}