Decompiled source of Open Cierzo v1.3.0
plugins/OpenCierzo/OpenCierzoPrototype.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Security.Cryptography; using System.Text; using System.Xml; using System.Xml.Serialization; using BepInEx; using HarmonyLib; using NodeCanvas.BehaviourTrees; using NodeCanvas.DialogueTrees; using NodeCanvas.Framework; using NodeCanvas.Tasks.Actions; using Photon; using UnityEngine; using UnityEngine.AI; using UnityEngine.Events; using UnityEngine.Rendering; using UnityEngine.SceneManagement; using UnityEngine.UI; using uNature.Core.FoliageClasses; using uNature.Core.Utility; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyFileVersion("1.2.0.0")] [assembly: AssemblyVersion("1.2.0.0")] namespace OpenCierzo; [BepInPlugin("Outwardz.OpenCierzoPrototype", "Open Cierzo", "1.2.0")] public sealed class Plugin : BaseUnityPlugin { public const string Id = "Outwardz.OpenCierzoPrototype"; internal const string City = "CierzoNewTerrain"; internal const string Region = "ChersoneseNewTerrain"; internal static Plugin Instance; internal static volatile bool Armed; internal static volatile bool Loading; private Vector3 regionOffset; private Vector3 seam; private Vector3 outward; private HingedGate physicalGate; private CoopSession coop; private readonly Dictionary<int, GatePressLatch> localGatePresses = new Dictionary<int, GatePressLatch>(); private LoadingNotice loadingNotice; private bool starting; private ImportedBoundaryScope importedBoundary; private WorldResources resources = new WorldResources(); private WorldFixtures fixtures = new WorldFixtures(); private WorldActors actors = new WorldActors(); private OutdoorNavigation navigation = new OutdoorNavigation(); private TownNavigation townNavigation = new TownNavigation(); private CityDefense cityDefense = new CityDefense(); private DroppedItemRecovery droppedItems = new DroppedItemRecovery(); private OutdoorDetails outdoorDetails = new OutdoorDetails(); private ResourceEffects resourceEffects = new ResourceEffects(); private OutdoorEnvironment outdoorEnvironment = new OutdoorEnvironment(); private RegionalEnvironment regionalEnvironment = new RegionalEnvironment(); private OutdoorTerrain outdoorTerrain = new OutdoorTerrain(); private WorldCoverage coverage = new WorldCoverage(); private RegionalMapMarkers mapMarkers = new RegionalMapMarkers(); private SceneNetworkViews networkViews = new SceneNetworkViews(); private GatePressLatch gatePress = new GatePressLatch(); private bool travelPending; private bool hooksReady; private bool menuAfterItemRecovery; private readonly SessionExit sessionExit = new SessionExit(); private Harmony patches; private bool ready; private bool failed; private bool outside; private Scene cityScene; private Scene regionScene; private Character player; private Vector3 cityGate; private Vector3 regionGate; private Vector3 cityArrival; private Vector3 regionArrival; private Quaternion cityRotation; private Quaternion regionRotation; private float started; private float nextAutoStartCheck; private float presentationStarted; private string presentationPhase; private string status = "Waiting for Cierzo."; private readonly HashSet<int> blockedInstances = new HashSet<int>(); private readonly HashSet<CharacterAI> waitingAgentBindings = new HashSet<CharacterAI>(); private readonly Dictionary<Camera, bool> originalOcclusion = new Dictionary<Camera, bool>(); private readonly VerifiedBuild verifiedBuild = new VerifiedBuild(); private readonly HashSet<int> removedTravelTriggers = new HashSet<int>(); private readonly Dictionary<string, KeyValuePair<Vector3, Quaternion>> travelPoses = new Dictionary<string, KeyValuePair<Vector3, Quaternion>>(); private bool bringLocalsOutside; private bool unloading => sessionExit.Unloading; internal bool GateIsOpen { get { if (physicalGate != null) { return physicalGate.IsOpen; } return false; } } internal static bool SessionEligible { get { if (Object.op_Implicit((Object)(object)SplitScreenManager.Instance)) { return SplitScreenManager.Instance.LocalPlayerCount <= 2; } return true; } } internal static bool PersistenceEligible => CoopSession.Authority; internal string GateText { get { if (!GatePermission.Allowed) { return "Gate Locked"; } return physicalGate.Prompt; } } internal bool GateFocus => GateFocusFor(player); internal static bool HasMultipleLocalPlayers { get { if (Object.op_Implicit((Object)(object)SplitScreenManager.Instance)) { return SplitScreenManager.Instance.LocalPlayerCount > 1; } return false; } } internal Dictionary<string, int> NetworkMap => networkViews.Export(); internal IEnumerable<string> ResourceIDs => resources.IDs; internal IEnumerable<string> FixtureIDs => fixtures.IDs; internal IEnumerable<string> LooseIDs => resources.LooseIDs; internal IEnumerable<string> ActorIDs => actors.IDs.Concat(cityDefense.IDs); internal bool ActorsReady { get { if (actors.Ready) { return cityDefense.Ready; } return false; } } internal bool WorldReady { get { if (ready && !failed) { return !unloading; } return false; } } internal bool ItemRecoveryActive { get { if (WorldReady && !travelPending && !sessionExit.MenuPending && !Loading && CoopSession.Authority && CoopSession.Supported && Object.op_Implicit((Object)(object)NetworkLevelLoader.Instance) && NetworkLevelLoader.Instance.IsOverallLoadingDone && !NetworkLevelLoader.Instance.IsGameplayPaused && !NetworkLevelLoader.Instance.IsSaveInProgress && SaveManager.Instance != null && !SaveManager.Instance.SaveInProgress && Object.op_Implicit((Object)(object)player) && player.Alive && actors.Ready) { return cityDefense.Ready; } return false; } } internal bool ItemsSafeToSave => droppedItems.SavingSafe; internal bool CanTravel { get { if (ready && !failed && !Loading && !unloading && !travelPending) { return WorldPersistence.AllowSave(); } return false; } } internal bool SuppressRegionUnload { get { if (!Armed) { return unloading; } return true; } } internal bool UseOutdoorMap { get { //IL_0031: Unknown result type (might be due to invalid IL or missing references) if (Armed && ready && !failed && Object.op_Implicit((Object)(object)player)) { return WorldPersistence.IsOutside(((Component)player).transform.position); } return false; } } internal Vector3 RegionTranslation => regionOffset; private void Awake() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown Instance = this; coop = new CoopSession(this); try { WorldPersistence.Install(new Harmony("Outwardz.OpenCierzoPrototype.persistence")); LoadingPresentation.Install(new Harmony("Outwardz.OpenCierzoPrototype.loading")); ActorEvents.Install(new Harmony("Outwardz.OpenCierzoPrototype.actors")); CoopItemSync.Install(new Harmony("Outwardz.OpenCierzoPrototype.coopitems")); CoopInboundSync.Install(new Harmony("Outwardz.OpenCierzoPrototype.coopreceive")); Guards.InstallSessionHooks(new Harmony("Outwardz.OpenCierzoPrototype.session")); hooksReady = true; } catch (Exception error) { WorldPersistence.Stop("Save hooks could not be installed. Close the game before loading a character.", error); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"Open Cierzo 1.2.0 loaded. Experimental online and split-screen co-op; same mod version required on every peer."); } internal void SetStatus(string text) { if (!(status == text)) { status = text; ((BaseUnityPlugin)this).Logger.LogInfo((object)text); } } internal void LogEvent(string text) { ((BaseUnityPlugin)this).Logger.LogInfo((object)text); } private void Update() { //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_02ec: Unknown result type (might be due to invalid IL or missing references) try { coop.Tick(); if (sessionExit.MenuPending || unloading) { return; } if (!Armed && !failed && !starting && Time.realtimeSinceStartup >= nextAutoStartCheck) { nextAutoStartCheck = Time.realtimeSinceStartup + (LoadingPresentation.Holding ? 0.05f : 0.5f); Begin(); } if (!Armed) { return; } if (Loading && Time.realtimeSinceStartup - started > 180f && !failed) { Fail("Preload exceeded three minutes. Restart the game; do not keep waiting indefinitely.", null); } if (!failed && !unloading && !travelPending) { outdoorTerrain.Tick(); } if (!ready || failed || !Object.op_Implicit((Object)(object)player) || travelPending) { cityDefense.ResetRecovery(); return; } if (menuAfterItemRecovery) { droppedItems.FinishPending(SetStatus, Time.realtimeSinceStartup); if (droppedItems.SavingSafe) { menuAfterItemRecovery = false; NetworkLevelLoader.Instance.GoMainMenu(); } return; } if (ItemRecoveryActive) { droppedItems.Tick(SetStatus); } if (!CoopSession.Supported) { Fail("Open Cierzo requires one or two local players.", null); return; } Vector3 position = ((Component)player).transform.position; float num = Vector3.Dot(position - seam, outward); outside = num > 0f; if (outside) { RegionReset.Visit(); } regionalEnvironment.Update(num); if (importedBoundary != null) { importedBoundary.Update(PlayerGateDistances(num).Min()); } if (physicalGate != null) { physicalGate.Update(from c in CharacterManager.Instance.Characters.Values where Object.op_Implicit((Object)(object)c) && (Object)(object)c.OwnerPlayerSys != (Object)null && c.Alive select ((Component)c).transform.position); } navigation.Update(GateIsOpen); townNavigation.Update(GateIsOpen); if (CoopSession.Authority && Object.op_Implicit((Object)(object)NetworkLevelLoader.Instance) && !NetworkLevelLoader.Instance.IsGameplayPaused) { cityDefense.Tick(); } else { cityDefense.ResetRecovery(); if (!CoopSession.Authority) { cityDefense.RemoteTick(); } } Character val = (CoopSession.Authority ? CharacterManager.Instance.GetWorldHostCharacter() : player); ActorEvents.Update(Object.op_Implicit((Object)(object)val) && WorldPersistence.IsOutside(((Component)val).transform.position)); CampingNotice.Tick(); actors.Tick(PlayerGateDistances(num).Any((float d) => d > 0f), SetStatus); foreach (SplitPlayer localPlayer in SplitScreenManager.Instance.LocalPlayers) { Character assignedCharacter = localPlayer.AssignedCharacter; if (!Object.op_Implicit((Object)(object)assignedCharacter) || (Object)(object)assignedCharacter.OwnerPlayerSys == (Object)null) { continue; } int playerID = assignedCharacter.OwnerPlayerSys.PlayerID; if (!localGatePresses.TryGetValue(playerID, out var value)) { value = new GatePressLatch(); localGatePresses.Add(playerID, value); } if (value.Sample(ControlsInput.InteractHold(playerID), Time.frameCount, Time.unscaledTime) && GateFocusFor(assignedCharacter) && !ControlsInput.QuickSlotToggled(playerID)) { if (GatePermission.Allowed) { coop.Toggle(assignedCharacter); } else { assignedCharacter.CharacterUI.ShowInfoNotification("Speak to Burac Carillon and complete his preparation check before opening the gate."); } } } } catch (Exception e) { Fail("Open Cierzo stopped after an error. Restart the game.", e); } } private void Begin() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) try { if (!LoadingPresentation.NativeReady) { return; } cityScene = SceneManager.GetActiveScene(); if (((Scene)(ref cityScene)).name != "CierzoNewTerrain" || !Object.op_Implicit((Object)(object)SplitScreenManager.Instance) || SaveManager.Instance == null || !Object.op_Implicit((Object)(object)CharacterManager.Instance)) { return; } player = CharacterManager.Instance.GetFirstLocalCharacter(); if (!Object.op_Implicit((Object)(object)player) || (Object)(object)player.OwnerPlayerSys == (Object)null || !Object.op_Implicit((Object)(object)player.CharacterUI) || !CoopSession.Supported) { return; } if (!coop.SnapshotReady) { SetStatus("Waiting for the host to send the Open Cierzo world. Both players need version 1.2.0."); return; } if (SaveManager.Instance.SaveInProgress || NetworkLevelLoader.Instance.IsSaveInProgress) { SetStatus("Waiting for the current save to finish before loading Open Cierzo."); return; } Scene sceneByName = SceneManager.GetSceneByName("ChersoneseNewTerrain"); if (((Scene)(ref sceneByName)).isLoaded) { LoadingPresentation.Cancel(); SetStatus("Chersonese is already loaded unexpectedly. Restart the game before continuing."); return; } if (!ActorEvents.CanInitialize(player)) { LoadingPresentation.Cancel(); SetStatus("Open Cierzo is waiting for a character without an active summon."); return; } if (player.IsDead) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Native defeat recovery pending: rebuilding event containers before the game's resurrection callbacks."); } starting = true; presentationStarted = Time.realtimeSinceStartup; presentationPhase = null; LoadingPresentation.Ensure((WorldPersistence.ResumingOutside || NativeTravel.ResumingOutside) ? "ChersoneseNewTerrain" : "CierzoNewTerrain"); loadingNotice = new LoadingNotice(player.CharacterUI, ((Component)this).transform); ((MonoBehaviour)this).StartCoroutine(StartAfterNotice()); } catch (Exception e) { Fail("Open Cierzo could not start. Restart before retrying.", e); } } private IEnumerator StartAfterNotice() { yield return null; yield return (object)new WaitForEndOfFrame(); if (failed) { yield break; } if (LoadingPresentation.NativeReady) { Scene activeScene = SceneManager.GetActiveScene(); if (!(((Scene)(ref activeScene)).name != "CierzoNewTerrain") && SaveManager.Instance != null && !SaveManager.Instance.SaveInProgress && !NetworkLevelLoader.Instance.IsSaveInProgress && CoopSession.Supported && ActorEvents.CanInitialize(player)) { StartPreload(); yield break; } } HideLoadingNotice(); LoadingPresentation.Cancel(); starting = false; } private void StartPreload() { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Expected O, but got Unknown try { Notice("Preparing the world...", 0.08f); coop.PrepareGuest(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Game build verification: " + verifiedBuild.Verify(Application.dataPath, KnownBuild.Files) + " file hashes; unchanged verified files reused within this session.")); StaticBatchRelocator.ValidateAccessor(); Transform val = Find(cityScene, "Environment/AreaSwitchChersonese"); cityRotation = Quaternion.LookRotation(Flat(val.forward)); outward = -Flat(Find(cityScene, "Environment/Assets/Buildings/Deck/Walls/mdl_env_cierzoWallAssets/mdl_env_buildingWoodWallGateA").forward); seam = Find(cityScene, "Environment/Assets/Buildings/Deck/Walls/mdl_env_cierzoWallAssets/mdl_env_buildingWoodWallGateA").position; cityGate = val.position + Flat(val.forward) * 1.5f; cityArrival = Find(cityScene, "Environment/Spawn1").position + Flat(val.forward) * 5f; if (patches == null) { patches = new Harmony("Outwardz.OpenCierzoPrototype"); Guards.Install(patches); DroppedItemRecovery.Install(patches); } Armed = true; Loading = true; started = Time.realtimeSinceStartup; WorldPersistence.Waiting = true; regionalEnvironment.CaptureHost(cityScene); SetStatus("Preloading Chersonese. A pause or hitch is expected. Saving resumes after the world is ready."); navigation.BeforeLoad(); townNavigation.BeforeLoad(); AsyncOperation val2 = SceneManager.LoadSceneAsync("ChersoneseNewTerrain", (LoadSceneMode)1); if (val2 == null) { throw new InvalidOperationException("Unity returned no scene-loading operation."); } ((MonoBehaviour)this).StartCoroutine(FinishPreload(val2)); } catch (Exception e) { if (!Armed && patches != null) { patches.UnpatchSelf(); } Fail(Armed ? "Preload failed. Restart the game; saving remains blocked." : "Test could not start. No area was loaded. Restart before retrying.", e); } } private IEnumerator FinishPreload(AsyncOperation op) { while (!op.isDone) { Notice("Loading landscape...", 0.12f + 0.48f * Mathf.Clamp01(op.progress / 0.9f)); yield return null; } if (failed) { yield break; } try { if (!((Scene)(ref regionScene)).IsValid() || !((Scene)(ref regionScene)).isLoaded) { throw new InvalidOperationException("The donor scene did not pass the scene-loaded guard."); } Notice("Preparing paths, resources and actors...", 0.64f); Physics.SyncTransforms(); cityArrival = Ground(cityArrival, cityScene); regionArrival = Ground(regionArrival, regionScene); Camera[] allCameras = Camera.allCameras; foreach (Camera val in allCameras) { if (!originalOcclusion.ContainsKey(val)) { originalOcclusion.Add(val, val.useOcclusionCulling); } val.useOcclusionCulling = false; } DisableCityExit("Environment/AreaSwitchChersonese"); DisableCityExit("Environment/AreaSwitchChersonese (NoCondition)"); player.ClearMostRelevantInteractableIndex(); physicalGate = WorldJoin.Build(cityScene, regionScene, seam, outward, Quarantine, SetStatus); importedBoundary = new ImportedBoundaryScope(((Component)Find(regionScene, "Environment/MapBounds/Cube (41)")).GetComponent<BoxCollider>(), delegate(string s) { ((BaseUnityPlugin)this).Logger.LogInfo((object)s); }); importedBoundary.Update(Vector3.Dot(((Component)player).transform.position - seam, outward)); Loading = false; WorldPersistence.PrepareInteractionStates(); navigation.Activate(regionOffset, seam, outward, SetStatus); townNavigation.Begin(cityScene, regionScene, seam, outward, navigation.JoinedApproach, SetStatus); navigation.JoinedApproach = default(NavMeshTriangulation); cityDefense.Prepare(cityScene, actors, townNavigation, networkViews, seam, outward, WorldPersistence.SavedCharacters, SetStatus); resources.Activate(cityScene, seam, outward, ReleaseResourceScript, SetStatus, WorldPersistence.SavedResourceIDs, WorldPersistence.SavedLooseIDs); fixtures.Activate(cityScene, seam, outward, regionOffset, ReleaseResourceScript, SetStatus, WorldPersistence.SavedFixtureIDs, WorldPersistence.SavedSoulSpots); ActorEvents.Prepare(actors, WorldPersistence.SavedEventStates); actors.Activate(cityScene, ReleaseResourceScript, WorldPersistence.SavedCharacters, SetStatus, WorldPersistence.SavedSoulSpots, WorldPersistence.SavedItems); CoopInboundSync.Release(); WorldPersistence.DiscardRepeatedEquipment(actors.DiscardedEquipment); OutdoorFoliage.Join(regionScene, seam, outward, SetStatus); coverage.RememberOwnership(CoverageOwner); } catch (Exception ex) { Fail("Gate setup stopped: " + (string.IsNullOrEmpty(ex.Message) ? ex.GetType().Name : ex.Message) + ". Close the game; saving remains blocked.", ex); } if (failed) { yield break; } yield return null; yield return null; float resourceStarted = Time.realtimeSinceStartup; Notice("Preparing interactions...", 0.76f); bool resourcesReady = false; while (!resourcesReady && !failed) { try { resources.Validate(WorldPersistence.SavedResourceIDs); resourcesReady = resources.Initialized(); if (!resourcesReady && Time.realtimeSinceStartup - resourceStarted > 30f) { Fail("Outdoor resource initialization timed out: " + resources.WaitingFor + ". Close the game; saving remains blocked.", null); } } catch (Exception e) { Fail("Outdoor resource initialization failed. Close the game; saving remains blocked.", e); } if (!resourcesReady) { yield return null; } } if (failed) { yield break; } try { WorldPersistence.BeginRestore(player, physicalGate); } catch (Exception e2) { Fail("Outdoor resource setup failed. Close the game; saving remains blocked.", e2); } if (failed) { yield break; } float restoreStarted = Time.realtimeSinceStartup; Notice("Restoring your world...", 0.84f); bool restored = false; while (!restored && !failed) { try { restored = WorldPersistence.PollRestore(player); if (!restored && Time.realtimeSinceStartup - restoreStarted > 60f) { Fail("Saved world objects did not finish loading (" + WorldPersistence.RestoreWaitReason + "). Close the game; the previous save has not been overwritten.", null); } } catch (Exception e3) { Fail("World restore failed. Close the game; saving remains blocked.", e3); } if (!restored) { yield return null; } } if (failed) { yield break; } float townPathsStarted = Time.realtimeSinceStartup; bool townPathsReady = false; while (!townPathsReady && !failed) { try { townPathsReady = townNavigation.Poll(); if (!townPathsReady && Time.realtimeSinceStartup - townPathsStarted > 90f) { Fail("Town enemy paths did not finish loading; saving remains blocked.", null); } } catch (Exception e4) { Fail("Town enemy navigation setup failed; saving remains blocked.", e4); } if (!townPathsReady) { Notice("Preparing town paths...", 0.91f); yield return null; } } if (failed) { yield break; } Notice("Finishing the environment...", 0.93f); try { networkViews.ValidateHost(); outdoorDetails.Activate(cityScene, seam, outward, ReleaseResourceScript, SetStatus); resourceEffects.Activate(resources.Contains, SetStatus); outdoorEnvironment.Activate(cityScene, seam, outward, ReleaseResourceScript, SetStatus); regionalEnvironment.Activate(cityScene, Vector3.Dot(((Component)player).transform.position - seam, outward), ReleaseResourceScript, SetStatus); outdoorTerrain.Activate(ReleaseResourceScript, SetStatus); mapMarkers.Activate(ReleaseResourceScript, SetStatus); } catch (Exception e5) { Fail("Outdoor details setup failed. Close the game; saving remains blocked.", e5); } if (failed) { yield break; } bool? nativeDefeatOutside = null; try { nativeDefeatOutside = NativeTravel.RestoreArrival(player, regionScene); RestoreLocalTravel(); fixtures.BeginQuestChecks(); actors.Complete(SetStatus); cityDefense.Complete(); networkViews.ValidateRuntime(); navigation.ValidateSpawns(actors.SpawnPositions, SetStatus); navigation.Update(GateIsOpen); townNavigation.Update(GateIsOpen); regionalEnvironment.Update(Vector3.Dot(((Component)player).transform.position - seam, outward)); if (nativeDefeatOutside != false && WorldPersistence.IsOutside(((Component)player).transform.position)) { RegionReset.Visit(); } } catch (Exception e6) { Fail("World arrival or quest initialization failed; saving remains blocked.", e6); } if (failed) { yield break; } importedBoundary.Update(Vector3.Dot(((Component)player).transform.position - seam, outward)); Physics.SyncTransforms(); try { coverage.Report(Path.Combine(Paths.BepInExRootPath, "OpenCierzo-world-coverage.tsv"), CoverageOwner, delegate(string s) { ((BaseUnityPlugin)this).Logger.LogInfo((object)s); }, delegate(string s) { ((BaseUnityPlugin)this).Logger.LogWarning((object)s); }); } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("World coverage report could not be written: " + ex2.Message)); } Notice("Ready", 1f); yield return null; yield return (object)new WaitForEndOfFrame(); if (!failed) { ready = true; try { ActorEvents.Complete(nativeDefeatOutside ?? WorldPersistence.IsOutside(((Component)player).transform.position)); } catch (Exception e7) { Fail("Regional actor event startup failed; saving remains blocked.", e7); yield break; } HideLoadingNotice(); LoadingPresentation.Complete(); try { actors.Tick(WorldPersistence.IsOutside(((Component)player).transform.position), SetStatus); } catch (Exception e8) { Fail("Outdoor encounter startup failed; saving remains blocked.", e8); yield break; } ((BaseUnityPlugin)this).Logger.LogInfo((object)string.Concat("Joined-world setup completed in ", (Time.realtimeSinceStartup - presentationStarted).ToString("F2"), " seconds; restored position=", ((Component)player).transform.position, ".")); if (CoopSession.Authority) { SaveManager.Instance.SetSaveRequired(); } SetStatus("Open Cierzo ready. Saving and native area travel enabled."); } } internal void PrepareRegion(Scene scene) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_03b6: Unknown result type (might be due to invalid IL or missing references) //IL_03c3: Unknown result type (might be due to invalid IL or missing references) //IL_03c6: Unknown result type (might be due to invalid IL or missing references) //IL_03d3: Unknown result type (might be due to invalid IL or missing references) //IL_03d9: Unknown result type (might be due to invalid IL or missing references) //IL_03f3: Unknown result type (might be due to invalid IL or missing references) //IL_0410: Unknown result type (might be due to invalid IL or missing references) //IL_041b: Unknown result type (might be due to invalid IL or missing references) //IL_0420: Unknown result type (might be due to invalid IL or missing references) //IL_0425: Unknown result type (might be due to invalid IL or missing references) //IL_0429: Unknown result type (might be due to invalid IL or missing references) //IL_0435: Unknown result type (might be due to invalid IL or missing references) //IL_0445: Unknown result type (might be due to invalid IL or missing references) //IL_044c: Unknown result type (might be due to invalid IL or missing references) //IL_0451: Unknown result type (might be due to invalid IL or missing references) //IL_045b: Unknown result type (might be due to invalid IL or missing references) //IL_0460: Unknown result type (might be due to invalid IL or missing references) //IL_0465: Unknown result type (might be due to invalid IL or missing references) //IL_046b: Unknown result type (might be due to invalid IL or missing references) //IL_0476: Unknown result type (might be due to invalid IL or missing references) //IL_047b: Unknown result type (might be due to invalid IL or missing references) //IL_0483: Unknown result type (might be due to invalid IL or missing references) //IL_0488: Unknown result type (might be due to invalid IL or missing references) //IL_048d: Unknown result type (might be due to invalid IL or missing references) //IL_0492: Unknown result type (might be due to invalid IL or missing references) //IL_0501: Unknown result type (might be due to invalid IL or missing references) //IL_051b: Unknown result type (might be due to invalid IL or missing references) //IL_0535: Unknown result type (might be due to invalid IL or missing references) if (failed) { GameObject[] rootGameObjects = ((Scene)(ref scene)).GetRootGameObjects(); foreach (GameObject val in rootGameObjects) { val.SetActive(false); } return; } try { regionScene = scene; int num = 0; int num2 = 0; int num3 = 0; GameObject[] rootGameObjects2 = ((Scene)(ref scene)).GetRootGameObjects(); coverage.Capture(scene); networkViews.Prepare(cityScene, scene, SetStatus); resources.Capture(scene); actors.Capture(scene); NativeTravel.Capture(scene); fixtures.Capture(scene); mapMarkers.Capture(scene); outdoorDetails.Capture(scene); resourceEffects.Capture(scene); outdoorEnvironment.Capture(scene); regionalEnvironment.Capture(scene); outdoorTerrain.Capture(scene); GameObject[] array = rootGameObjects2; foreach (GameObject val2 in array) { MonoBehaviour[] componentsInChildren = val2.GetComponentsInChildren<MonoBehaviour>(true); foreach (MonoBehaviour val3 in componentsInChildren) { if (Object.op_Implicit((Object)(object)val3)) { blockedInstances.Add(((Object)val3).GetInstanceID()); ((Behaviour)val3).enabled = false; num++; } } Camera[] componentsInChildren2 = val2.GetComponentsInChildren<Camera>(true); foreach (Camera val4 in componentsInChildren2) { ((Behaviour)val4).enabled = false; } AudioListener[] componentsInChildren3 = val2.GetComponentsInChildren<AudioListener>(true); foreach (AudioListener val5 in componentsInChildren3) { ((Behaviour)val5).enabled = false; } AudioSource[] componentsInChildren4 = val2.GetComponentsInChildren<AudioSource>(true); foreach (AudioSource val6 in componentsInChildren4) { val6.Stop(); ((Behaviour)val6).enabled = false; } Light[] componentsInChildren5 = val2.GetComponentsInChildren<Light>(true); foreach (Light val7 in componentsInChildren5) { ((Behaviour)val7).enabled = false; } Animator[] componentsInChildren6 = val2.GetComponentsInChildren<Animator>(true); foreach (Animator val8 in componentsInChildren6) { ((Behaviour)val8).enabled = false; } Animation[] componentsInChildren7 = val2.GetComponentsInChildren<Animation>(true); foreach (Animation val9 in componentsInChildren7) { ((Behaviour)val9).enabled = false; } NavMeshAgent[] componentsInChildren8 = val2.GetComponentsInChildren<NavMeshAgent>(true); foreach (NavMeshAgent val10 in componentsInChildren8) { ((Behaviour)val10).enabled = false; } ParticleSystem[] componentsInChildren9 = val2.GetComponentsInChildren<ParticleSystem>(true); foreach (ParticleSystem val11 in componentsInChildren9) { val11.Stop(true, (ParticleSystemStopBehavior)0); } Rigidbody[] componentsInChildren10 = val2.GetComponentsInChildren<Rigidbody>(true); foreach (Rigidbody val12 in componentsInChildren10) { val12.isKinematic = true; val12.detectCollisions = false; } Character[] componentsInChildren11 = val2.GetComponentsInChildren<Character>(true); foreach (Character val13 in componentsInChildren11) { ((Component)val13).gameObject.SetActive(false); } Collider[] componentsInChildren12 = val2.GetComponentsInChildren<Collider>(true); foreach (Collider val14 in componentsInChildren12) { if (val14.isTrigger) { val14.enabled = false; } else if (val14.enabled) { num2++; } } Renderer[] componentsInChildren13 = val2.GetComponentsInChildren<Renderer>(true); foreach (Renderer val15 in componentsInChildren13) { if (val15.enabled) { num3++; } } if (((Object)val2).name != "Environment") { val2.SetActive(false); } } Physics.SyncTransforms(); Transform val16 = Find(scene, "Interactions/NormalCierzo/mdl_env_buildingWoodWallGateA (2)"); float num13 = GroundJoin.AtGate(scene, val16.position); float num14 = GroundJoin.AtGate(cityScene, seam); regionOffset = new Vector3(seam.x - val16.position.x, num14 - num13, seam.z - val16.position.z); int num15 = StaticBatchRelocator.Relocate(scene, rootGameObjects2, regionOffset); Transform val17 = Find(scene, "Environment/AreaSwitches/0_AreaSwitchCierzo"); regionGate = val17.position + Flat(val17.forward) * 2.5f; regionArrival = Find(scene, "Environment/Spawn1").position; regionRotation = Quaternion.LookRotation(Flat(val17.forward)); ((BaseUnityPlugin)this).Logger.LogInfo((object)string.Concat("Donor scenery prepared: ", num, " disabled scripts; ", num2, " solid colliders; ", num3, " renderers; ", num15, " batched renderers relocated. Join offset=", regionOffset, "; region gate=", regionGate, "; arrival=", regionArrival)); } catch (Exception ex) { GameObject[] rootGameObjects3 = ((Scene)(ref scene)).GetRootGameObjects(); foreach (GameObject val18 in rootGameObjects3) { val18.SetActive(false); } Fail("Chersonese setup stopped: " + ex.Message + " Close the game before retrying.", ex); } } private void DisableCityExit(string path) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) Transform val = Find(cityScene, path); InteractionTriggerBase[] componentsInChildren = ((Component)val).GetComponentsInChildren<InteractionTriggerBase>(true); foreach (InteractionTriggerBase val2 in componentsInChildren) { removedTravelTriggers.Add(((Object)val2).GetInstanceID()); val2.CanBeTriggered = false; if (Object.op_Implicit((Object)(object)val2.InteractionCollider)) { val2.InteractionCollider.enabled = false; } ((Behaviour)val2).enabled = false; } ((Component)val).gameObject.SetActive(false); } internal bool IsRemovedTravel(InteractionTriggerBase trigger) { if (Armed && Object.op_Implicit((Object)(object)trigger)) { return removedTravelTriggers.Contains(((Object)trigger).GetInstanceID()); } return false; } internal bool IsTestPlayer(Character character) { if (Object.op_Implicit((Object)(object)character) && Object.op_Implicit((Object)(object)SplitScreenManager.Instance)) { return SplitScreenManager.Instance.LocalPlayers.Any((SplitPlayer p) => (Object)(object)p.AssignedCharacter == (Object)(object)character); } return false; } internal bool GateFocusFor(Character user) { //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) if (!ready || failed || !Object.op_Implicit((Object)(object)user) || physicalGate == null || user.IsDead) { return false; } CharacterUI characterUI = user.CharacterUI; if (!Object.op_Implicit((Object)(object)characterUI) || characterUI.IsMenuFocused || characterUI.IsDialogueInProgress || characterUI.IsChatPanelFocused || characterUI.IsInputFieldFocused) { return false; } InteractionTriggerBase interactable = user.Interactable; if (Object.op_Implicit((Object)(object)interactable) && !IsRemovedTravel(interactable)) { return false; } if (!string.IsNullOrEmpty(user.PressText) || !string.IsNullOrEmpty(user.HoldText)) { return false; } Vector3 val = physicalGate.Position - ((Component)user).transform.position; Vector3 val2 = val; val2.y = 0f; if (((Vector3)(ref val2)).sqrMagnitude > 100f || Mathf.Abs(val.y) > 5f) { return false; } if (((Vector3)(ref val2)).sqrMagnitude <= 16f) { return true; } Camera componentInChildren = ((Component)user).GetComponentInChildren<Camera>(); Vector3 v = (Object.op_Implicit((Object)(object)componentInChildren) ? ((Component)componentInChildren).transform.forward : ((Component)user).transform.forward); return Vector3.Dot(Flat(v), Flat(val)) > -0.1f; } internal static Character FindLocalPlayer(string uid) { if (!Object.op_Implicit((Object)(object)SplitScreenManager.Instance)) { return null; } return SplitScreenManager.Instance.LocalPlayers.Select((SplitPlayer p) => p.AssignedCharacter).FirstOrDefault((Func<Character, bool>)((Character c) => Object.op_Implicit((Object)(object)c) && UID.op_Implicit(c.UID) == uid)); } internal void RecordLocalTravel(string area, int spawn, bool defeat = false) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) travelPoses.Clear(); bringLocalsOutside = area == "ChersoneseNewTerrain" && !defeat; if (defeat || !Armed || !(area == "CierzoNewTerrain") || spawn >= 0) { return; } foreach (SplitPlayer localPlayer in SplitScreenManager.Instance.LocalPlayers) { Character assignedCharacter = localPlayer.AssignedCharacter; if (Object.op_Implicit((Object)(object)assignedCharacter)) { travelPoses[UID.op_Implicit(assignedCharacter.UID)] = new KeyValuePair<Vector3, Quaternion>(((Component)assignedCharacter).transform.position, ((Component)assignedCharacter).transform.rotation); } } } private void RestoreLocalTravel() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) int num = 0; foreach (SplitPlayer localPlayer in SplitScreenManager.Instance.LocalPlayers) { Character assignedCharacter = localPlayer.AssignedCharacter; if (Object.op_Implicit((Object)(object)assignedCharacter)) { if (travelPoses.TryGetValue(UID.op_Implicit(assignedCharacter.UID), out var value)) { assignedCharacter.Teleport(value.Key, value.Value); } else if (bringLocalsOutside && (Object)(object)assignedCharacter != (Object)(object)player) { assignedCharacter.Teleport(Ground(((Component)player).transform.position + Vector3.right * (1.25f * (float)(++num)), regionScene), ((Component)player).transform.rotation); } } } travelPoses.Clear(); bringLocalsOutside = false; } private IEnumerable<float> PlayerGateDistances(float fallback) { return (from c in CharacterManager.Instance.Characters.Values where Object.op_Implicit((Object)(object)c) && (Object)(object)c.OwnerPlayerSys != (Object)null && c.Alive select Vector3.Dot(((Component)c).transform.position - seam, outward)).DefaultIfEmpty(fallback); } internal bool NearGate(Character user) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)user) && physicalGate != null) { Vector3 val = ((Component)user).transform.position - physicalGate.Position; return ((Vector3)(ref val)).sqrMagnitude <= 100f; } return false; } internal void ToggleGate() { if (physicalGate != null) { physicalGate.Toggle(); } } internal void SetGateState(bool value) { if (physicalGate != null && physicalGate.IsOpen != value) { physicalGate.SetOpen(value); } } internal bool CoopPeerReady(int id) { return coop.PeerReady(id); } internal bool DeferCoopItem(Item item) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) HashSet<string> hashSet = new HashSet<string>(); while (Object.op_Implicit((Object)(object)item) && hashSet.Add(item.UID)) { Character ownerCharacter = ((EffectSynchronizer)item).OwnerCharacter; if (Object.op_Implicit((Object)(object)ownerCharacter) && (Object)(object)ownerCharacter.OwnerPlayerSys != (Object)null) { return false; } if (resources.Contains((Component)(object)item) || actors.Contains((Component)(object)item) || (Object.op_Implicit((Object)(object)ownerCharacter) && (actors.Contains((Component)(object)ownerCharacter) || cityDefense.Owns(ownerCharacter)))) { return true; } if (item.IsInWorld && WorldPersistence.IsOutside(((Component)item).transform.position)) { return true; } item = (Item)(object)item.ParentContainer; } return false; } internal void SetNetworkMap(Dictionary<string, int> map) { networkViews.Expect(map); } private static Vector3 Flat(Vector3 v) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) v.y = 0f; return ((Vector3)(ref v)).normalized; } internal static Transform Find(Scene scene, string path) { int num = path.IndexOf('/'); string rootName = ((num < 0) ? path : path.Substring(0, num)); GameObject val = ((IEnumerable<GameObject>)((Scene)(ref scene)).GetRootGameObjects()).FirstOrDefault((Func<GameObject, bool>)((GameObject g) => ((Object)g).name == rootName)); Transform val2 = (((Object)(object)val == (Object)null) ? null : ((num < 0) ? val.transform : val.transform.Find(path.Substring(num + 1)))); if (!Object.op_Implicit((Object)(object)val2)) { throw new InvalidOperationException("Missing scene anchor: " + ((Scene)(ref scene)).name + "/" + path); } return val2; } internal static Vector3 Ground(Vector3 intended, Scene scene) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) RaycastHit[] source = Physics.RaycastAll(intended + Vector3.up * 3f, Vector3.down, 8f, -1, (QueryTriggerInteraction)1); foreach (RaycastHit item in source.OrderBy((RaycastHit h) => ((RaycastHit)(ref h)).distance)) { RaycastHit current = item; if (Object.op_Implicit((Object)(object)((RaycastHit)(ref current)).collider) && ((Component)((RaycastHit)(ref current)).collider).gameObject.scene == scene && ((RaycastHit)(ref current)).normal.y > 0.6f) { return ((RaycastHit)(ref current)).point + Vector3.up * 0.2f; } } throw new InvalidOperationException("No walkable ground found at " + ((Scene)(ref scene)).name + " " + intended); } internal void Quarantine(MonoBehaviour component) { if (Object.op_Implicit((Object)(object)component)) { blockedInstances.Add(((Object)component).GetInstanceID()); ((Behaviour)component).enabled = false; } } private void ReleaseResourceScript(MonoBehaviour component) { blockedInstances.Remove(((Object)component).GetInstanceID()); } private string CoverageOwner(Component c) { //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) if (resources.RetiredSource(c)) { return "saved loose-item source retired; native item save is authoritative"; } if (actors.Contains(c)) { return "native actor, quest or event hierarchy"; } MonoBehaviour val = (MonoBehaviour)(object)((c is MonoBehaviour) ? c : null); if (resources.Contains(c) && (!Object.op_Implicit((Object)(object)val) || !IsDonor((Component)(object)val))) { return "native resource and item helpers"; } if (fixtures.Contains(c) && (!Object.op_Implicit((Object)(object)val) || fixtures.Owns(val))) { return "native independent fixture"; } if (Object.op_Implicit((Object)(object)val) && (outdoorEnvironment.Owns(val) || regionalEnvironment.Owns(val))) { return "regional environment adapter"; } if (Object.op_Implicit((Object)(object)val) && mapMarkers.Owns(val)) { return "regional native map markers and UI"; } if (Object.op_Implicit((Object)(object)val) && outdoorTerrain.Discarded(val)) { return "non-rendering imported terrain tile; streaming intentionally disabled"; } if (Object.op_Implicit((Object)(object)val) && outdoorTerrain.Owns(val)) { return "native terrain streaming adapter"; } CentralGatherableAccessPoint val2 = (CentralGatherableAccessPoint)(object)((c is CentralGatherableAccessPoint) ? c : null); if (Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)val2.InteractionCollider)) { return "native shared wood interaction"; } if (Vector3.Dot(c.transform.position - seam, outward) <= 5f) { return "town-side join overlap"; } return null; } internal bool AllowEnvironmentSoundStart(SoundPlayer component) { if (outdoorEnvironment.AllowSoundStart(component)) { return regionalEnvironment.AllowStart((MonoBehaviour)(object)component); } return false; } internal bool AllowEnvironmentStart(MonoBehaviour component) { if (regionalEnvironment.AllowStart(component)) { return outdoorEnvironment.AllowStart(component); } return false; } internal bool AllowRegionalAmbience(AmbienceSound component) { return regionalEnvironment.AllowAmbience(component); } internal bool AllowRegionalAmbiencePlay(AmbienceSound component) { return regionalEnvironment.AllowAmbiencePlay(component); } internal bool AllowResourceLootStart(MonoBehaviour component) { return resources.AllowLootStart(component); } internal bool ActorsSettled(out string reason) { if (actors.Settled(out reason)) { return cityDefense.Settled(out reason); } return false; } internal bool OwnsCampingSquad(AISquad squad) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) if (CoopSession.Authority && Armed && WorldReady && !travelPending && !sessionExit.MenuPending && !Loading && actors.Ready && Object.op_Implicit((Object)(object)squad) && actors.Contains((Component)(object)squad) && Object.op_Implicit((Object)(object)player)) { return WorldPersistence.IsOutside(((Component)player).transform.position); } return false; } internal bool CampingQueryFilter(Vector3 center, out NavMeshQueryFilter filter) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return townNavigation.CampingFilter(center, out filter); } internal void BindCampingActor(CharacterAI ai, NavMeshQueryFilter filter) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) if (!townNavigation.BindCamping(ai, filter)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Native camping actor could not bind at its selected position: " + ((Object.op_Implicit((Object)(object)ai) && Object.op_Implicit((Object)(object)((CharacterControl)ai).Character)) ? UID.op_Implicit(((CharacterControl)ai).Character.UID) : "missing actor") + ".")); } } internal void RecordFallenItem(Item item) { try { droppedItems.BeforeDestroy(item); } catch (Exception error) { WorldPersistence.Stop("Fallen item state could not be preserved; saving remains blocked.", error); } } internal void CancelItemRecovery(string id, bool collateral = false) { droppedItems.Cancel(id, collateral); } internal void SelectMapMarkers(bool outsideMap) { mapMarkers.Select(outsideMap); } internal bool AllowFixtureLifecycle(MonoBehaviour c, MethodBase method) { if (mapMarkers.AllowLifecycle(c, method) && actors.AllowLifecycle(c, method) && fixtures.AllowLifecycle(c, method)) { return resources.AllowInteractionStart(c, method); } return false; } internal bool AllowActorMessage(Component c, string name) { return actors.AllowMessage(c, name); } internal void RouteTownActor(CharacterAI ai, bool destinationChanged) { if (CoopSession.Authority && WorldReady && !travelPending && !sessionExit.MenuPending && !Loading && Object.op_Implicit((Object)(object)NetworkLevelLoader.Instance) && !NetworkLevelLoader.Instance.IsGameplayPaused && ((actors.Contains((Component)(object)ai) && Object.op_Implicit((Object)(object)((CharacterControl)ai).Character) && ((CharacterControl)ai).Character.IsAI) || cityDefense.Owns(ai))) { townNavigation.Route(ai, destinationChanged); } } internal bool TownQueryFilter(CharacterAI ai, out NavMeshQueryFilter filter) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) filter = default(NavMeshQueryFilter); if (WorldReady && !travelPending && !sessionExit.MenuPending && !Loading && ((actors.Contains((Component)(object)ai) && Object.op_Implicit((Object)(object)((CharacterControl)ai).Character) && ((CharacterControl)ai).Character.IsAI) || cityDefense.Owns(ai))) { return townNavigation.Filter(ai, out filter); } return false; } internal bool TownRecovering(CharacterAI ai) { if (TownQueryFilter(ai, out var _)) { return townNavigation.Recovering(ai); } return false; } internal bool EnableOwnedAgent(CharacterAI ai, NavMeshAgent agent) { //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)ai) || !Object.op_Implicit((Object)(object)agent) || (Object)(object)ai.NavMeshAgent != (Object)(object)agent || ((!actors.Contains((Component)(object)ai) || !Object.op_Implicit((Object)(object)((CharacterControl)ai).Character) || !((CharacterControl)ai).Character.IsAI) && !cityDefense.Owns(ai))) { return false; } if (!WorldReady || travelPending || sessionExit.MenuPending || Loading || !Object.op_Implicit((Object)(object)((CharacterControl)ai).Character) || !((CharacterControl)ai).Character.Alive || !Object.op_Implicit((Object)(object)NetworkLevelLoader.Instance) || NetworkLevelLoader.Instance.IsGameplayPaused || NetworkLevelLoader.Instance.IsGameplayLoading || TownRecovering(ai)) { ((Behaviour)agent).enabled = false; return true; } NavMeshQueryFilter filter; bool town = TownQueryFilter(ai, out filter); if (!town) { NavMeshQueryFilter val = default(NavMeshQueryFilter); ((NavMeshQueryFilter)(ref val)).agentTypeID = agent.agentTypeID; ((NavMeshQueryFilter)(ref val)).areaMask = agent.areaMask; filter = val; } if (AgentActivation.Enable(agent, delegate(Vector3 point, out NavMeshHit hit) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) return (!town) ? NavMesh.SamplePosition(point, ref hit, 1.5f, filter) : townNavigation.Sample(point, out hit, 1.5f, filter); })) { waitingAgentBindings.Remove(ai); } else if (waitingAgentBindings.Add(ai)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)string.Concat("Native navigation activation deferred: ", UID.op_Implicit(((CharacterControl)ai).Character.UID), "; body=", ((Component)ai).transform.position, "; agent type=", agent.agentTypeID, "; no valid nearby binding floor; physical body and native destination retained.")); } return true; } internal Vector3 TownMovementTarget(CharacterAI ai, Vector3 requested) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) if (!TownQueryFilter(ai, out var _)) { return requested; } return townNavigation.MovementTarget(ai, requested); } internal bool TownDestinationAgentValid(CharacterAI ai, bool nativeValid) { if (!TownQueryFilter(ai, out var _)) { return nativeValid; } return townNavigation.DestinationAgentValid(ai, nativeValid); } internal bool TownRequestDestination(CharacterAI ai, NavMeshAgent agent, Vector3 position) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (!TownQueryFilter(ai, out var _)) { return agent.SetDestination(position); } return townNavigation.RequestDestination(ai, agent, position); } internal void TownMotionObserved(CharacterAI ai) { } internal bool TownSample(Vector3 point, out NavMeshHit hit, float distance, NavMeshQueryFilter filter) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) return townNavigation.Sample(point, out hit, distance, filter); } internal bool GuardAIUpdate(CharacterAI ai) { if (cityDefense.Owns(ai) || actors.Contains((Component)(object)ai)) { if (CoopSession.Authority && WorldReady && !travelPending && !sessionExit.MenuPending && !Loading && Object.op_Implicit((Object)(object)NetworkLevelLoader.Instance) && !NetworkLevelLoader.Instance.IsGameplayPaused) { return !NetworkLevelLoader.Instance.IsGameplayLoading; } return false; } return true; } internal void GuardFacing(CharacterAI ai) { if (CoopSession.Authority && Object.op_Implicit((Object)(object)NetworkLevelLoader.Instance) && !NetworkLevelLoader.Instance.IsGameplayPaused) { cityDefense.FaceReturnPath(ai); } } internal void GuardAnimationState(Character body) { if (cityDefense.Owns(body)) { CityGuardAnimation.KeepAnimating(body); } } internal bool GuardTargetAllowed(TargetingSystem source, Character target) { return cityDefense.TargetAllowed(source, target); } internal void GuardDestination(CharacterAI ai, ref Vector3 position) { cityDefense.Destination(ai, ref position); } internal Vector3 GuardMovement(CharacterController controller, Vector3 move) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) return cityDefense.Clamp(controller, move); } internal bool AllowRegionEntry(NodeTreeWaitForLoading waiter) { if (actors.AllowRegionEntry(waiter)) { return fixtures.AllowQuestStart(waiter); } return false; } internal bool SuppressQuestActivation(GameObject target) { if (!actors.Contains(target)) { return fixtures.SuppressActivation(target); } return false; } internal void MarkTravel() { travelPending = true; } internal void BeginMenuReturn() { if (Armed || starting || WorldPersistence.Waiting) { sessionExit.RequestMenu(delegate { ((MonoBehaviour)this).StopAllCoroutines(); starting = false; LoadingPresentation.ReleaseForMenu(); SetStatus("Returning to the main menu; waiting for the native save before releasing the joined world."); }); } } internal bool TryBeginMenuReturn() { if (Armed && ready && !failed && !droppedItems.SavingSafe) { menuAfterItemRecovery = true; SetStatus("Recovering fallen items before the native quit save; menu return will continue when item synchronization finishes."); return false; } BeginMenuReturn(); return true; } internal void BeforeMenuReset() { if (sessionExit.MenuPending) { BeforeNativeUnload(); } } internal void BeforeNativeUnload() { sessionExit.BeforeUnload(travelPending, ReleaseWorldForUnload); } private void ReleaseWorldForUnload() { ready = false; Armed = (Loading = false); waitingAgentBindings.Clear(); coop.Reset(); CoopInboundSync.Reset(); droppedItems.Clear(); fixtures.Dispose(); mapMarkers.Dispose(); ActorEvents.Dispose(); cityDefense.Dispose(); actors.Dispose(); townNavigation.Dispose(); navigation.Dispose(); foreach (KeyValuePair<Camera, bool> item in originalOcclusion) { if (Object.op_Implicit((Object)(object)item.Key)) { item.Key.useOcclusionCulling = item.Value; } } originalOcclusion.Clear(); WorldPersistence.EndSession(); OutdoorFoliage.Clear(); WaterSeam.Clear(); HideLoadingNotice(); if (sessionExit.MenuPending) { SetStatus("Native quit save finished; joined-world systems released for the main menu."); } } internal void NativeSceneLoaded(bool mainMenu) { sessionExit.Arrived(mainMenu, ResetWorldSession, delegate { WorldPersistence.EndSession(); ActorEvents.ClearPending(); if (hooksReady) { failed = false; WorldPersistence.Faulted = false; } LoadingPresentation.ReleaseForMenu(); SetStatus("Main menu ready; Open Cities will initialize on the next Cierzo load."); }); } private void ResetWorldSession() { LiveTerrainSeam.Clear(); mapMarkers.Dispose(); mapMarkers = new RegionalMapMarkers(); outdoorTerrain.Dispose(); outdoorTerrain = new OutdoorTerrain(); OwnedAssets.Release(); resources = new WorldResources(); fixtures = new WorldFixtures(); outdoorDetails = new OutdoorDetails(); actors = new WorldActors(); navigation = new OutdoorNavigation(); townNavigation = new TownNavigation(); cityDefense = new CityDefense(); droppedItems = new DroppedItemRecovery(); resourceEffects = new ResourceEffects(); outdoorEnvironment = new OutdoorEnvironment(); regionalEnvironment = new RegionalEnvironment(); coverage = new WorldCoverage(); networkViews = new SceneNetworkViews(); localGatePresses.Clear(); gatePress = new GatePressLatch(); physicalGate = null; importedBoundary = null; blockedInstances.Clear(); removedTravelTriggers.Clear(); waitingAgentBindings.Clear(); ready = (starting = (travelPending = (outside = (Loading = (menuAfterItemRecovery = false))))); player = null; nextAutoStartCheck = 0f; SetStatus("Waiting for Cierzo; the joined outdoor world rebuilds automatically on return."); } internal bool ResourceInteractionBlocked(Component component) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) if (!Armed) { return false; } if ((!ready || !WorldPersistence.Ready) && (resources.Contains(component) || fixtures.Contains(component) || actors.Contains(component))) { return true; } if (fixtures.IsWaterTrigger(component)) { if (Object.op_Implicit((Object)(object)player) && !(Vector3.Dot(((Component)player).transform.position - seam, outward) < 0f)) { return !WaterSeam.NearWater(((Component)player).transform.position); } return true; } return false; } internal bool AllowNetworkRegistration(PhotonView view) { if (!Armed) { return true; } if (Loading && IsDonor((Component)(object)view)) { return false; } try { networkViews.ValidateRegistration(view); return true; } catch (Exception e) { Fail("Outdoor network registration failed; saving remains blocked.", e); return false; } } internal bool IsDonor(Component c) { //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) if ((!Armed && !unloading) || object.ReferenceEquals(c, null)) { return false; } MonoBehaviour val = (MonoBehaviour)(object)((c is MonoBehaviour) ? c : null); if (Object.op_Implicit((Object)(object)val) && (actors.Owns(val) || mapMarkers.Owns(val) || outdoorEnvironment.Owns(val) || regionalEnvironment.Owns(val) || fixtures.Owns(val) || outdoorTerrain.Owns(val))) { return false; } if (blockedInstances.Contains(((Object)c).GetInstanceID())) { return true; } if (!Object.op_Implicit((Object)(object)c)) { return false; } Scene scene = c.gameObject.scene; bool flag = ((Scene)(ref scene)).name == "ChersoneseNewTerrain"; if (flag) { blockedInstances.Add(((Object)c).GetInstanceID()); } return flag; } internal void Fail(string message, Exception e) { if (failed) { return; } failed = true; ready = false; actors.Suspend(); cityDefense.Suspend(); WorldPersistence.Faulted = true; WorldPersistence.Ready = false; HideLoadingNotice(); LoadingPresentation.Cancel(); SetStatus(message); ((BaseUnityPlugin)this).Logger.LogError((object)message); try { if (Object.op_Implicit((Object)(object)player) && Object.op_Implicit((Object)(object)player.CharacterUI)) { player.CharacterUI.ShowInfoNotification("Open Cierzo: " + message); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)ex); } if (e != null) { ((BaseUnityPlugin)this).Logger.LogError((object)e); } } private void HideLoadingNotice() { if (loadingNotice != null) { loadingNotice.Hide(); loadingNotice = null; } } internal void ClearLoadingNotice() { HideLoadingNotice(); } private void Notice(string phase, float progress) { if (loadingNotice != null) { loadingNotice.SetPhase(phase, progress); } if (presentationPhase != phase) { presentationPhase = phase; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Joined load phase at " + (Time.realtimeSinceStartup - presentationStarted).ToString("F2") + "s: " + phase)); } } private void OnDestroy() { if (coop != null) { coop.Dispose(); } HideLoadingNotice(); LoadingPresentation.Cancel(); } } internal static class WorldPersistence { private sealed class LocalPose { internal PlayerSaveData Data; internal Vector3 Position; internal Vector3 Forward; } internal sealed class WorldRecords { internal readonly List<BasicSaveData> Items; internal readonly List<BasicSaveData> Activators; internal readonly List<BasicSaveData> DropTables; internal readonly List<CharacterSaveData> Characters; internal List<BasicSaveData> DeferredItems; internal List<CharacterSaveData> DeferredCharacters; internal readonly bool GateOpen; internal readonly HashSet<string> ResourceIDs; internal readonly HashSet<string> FixtureIDs; internal readonly HashSet<string> LooseIDs; internal readonly HashSet<string> ActorIDs; internal readonly List<string> UsedSoulSpots; internal WorldRecords Original; internal bool ReplayStates; internal readonly bool HasRegionalClock; internal WorldRecords(EnvironmentSave save, bool? gate = null) { Items = save.ItemList; Characters = save.CharList; Activators = save.InteractionActivatorList; DropTables = save.DropTablesList; GateOpen = gate ?? Activators.Any((BasicSaveData r) => object.Equals(r.Identifier, "Outwardz.OpenCierzo.Gate.v1") && r.SyncData == "open"); ResourceIDs = ResourceCatalog.Read(Activators); FixtureIDs = ResourceCatalog.Read(Activators, "Outwardz.OpenCierzo.Fixtures.v1"); LooseIDs = ResourceCatalog.Read(Activators, "Outwardz.OpenCierzo.LooseSources.v1"); ActorIDs = ActorCatalog.Read(Activators); UsedSoulSpots = new List<string>(save.UsedSoulSpots ?? new List<string>()); HasRegionalClock = RegionReset.HasClock(Activators); } internal void RestoreLists(EnvironmentSave save) { WorldRecords worldRecords = Original ?? this; save.ItemList = worldRecords.Items; save.CharList = worldRecords.Characters; save.InteractionActivatorList = worldRecords.Activators; save.DropTablesList = worldRecords.DropTables; save.UsedSoulSpots = worldRecords.UsedSoulSpots; } internal WorldRecords OutdoorSnapshot(bool? gate = null) { //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown HashSet<string> outdoor = SavedItemPlacement.OutdoorItems(Items, new HashSet<string>(ResourceIDs.Concat(LooseIDs)), ActorIDs); HashSet<string> ids = new HashSet<string>(ResourceIDs.Concat(LooseIDs).Concat(FixtureIDs).Concat(ActorIDs)); EnvironmentSave val = new EnvironmentSave(); val.ItemList = Items.Where((BasicSaveData r) => outdoor.Contains(r.Identifier.ToString())).ToList(); val.CharList = Characters.Where((CharacterSaveData c) => ActorCatalog.Outdoor(c, ActorIDs)).ToList(); val.InteractionActivatorList = Activators.Where((BasicSaveData r) => ids.Contains(r.Identifier.ToString()) || ResourceCatalog.IsRecord(r) || object.Equals(r.Identifier, "Outwardz.OpenCierzo.Fixtures.v1") || object.Equals(r.Identifier, "Outwardz.OpenCierzo.LooseSources.v1") || object.Equals(r.Identifier, "Outwardz.OpenCierzo.Actors.v1") || ActorEvents.IsRecord(r) || object.Equals(r.Identifier, "Outwardz.OpenCierzo.RegionVisit.v1")).ToList(); val.DropTablesList = DropTables.Where((BasicSaveData r) => RegionReset.BelongsTo(r, ids)).ToList(); val.UsedSoulSpots = UsedSoulSpots.Where((string id) => RegionReset.Owned(id, ids)).ToList(); WorldRecords worldRecords = new WorldRecords(val, gate); worldRecords.DeferredItems = worldRecords.Items; worldRecords.DeferredCharacters = worldRecords.Characters; return worldRecords; } internal WorldRecords Snapshot() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown EnvironmentSave val = new EnvironmentSave(); val.ItemList = new List<BasicSaveData>(Items); val.CharList = new List<CharacterSaveData>(Characters); val.InteractionActivatorList = new List<BasicSaveData>(Activators); val.DropTablesList = new List<BasicSaveData>(DropTables); val.UsedSoulSpots = new List<string>(UsedSoulSpots); return new WorldRecords(val); } internal void KeepUnloadedRecords(EnvironmentSave save) { HashSet<string> hashSet = new HashSet<string>(save.CharList.Select((CharacterSaveData c) => c.UID)); foreach (CharacterSaveData character in Characters) { if (!CharacterManager.Instance.Characters.ContainsKey(character.UID) && hashSet.Add(character.UID)) { save.CharList.Add(character); } } MergeMissing(save.InteractionActivatorList, Activators); MergeMissing(save.DropTablesList, DropTables); if (save.UsedSoulSpots == null) { save.UsedSoulSpots = new List<string>(); } foreach (string usedSoulSpot in UsedSoulSpots) { if (!save.UsedSoulSpots.Contains(usedSoulSpot)) { save.UsedSoulSpots.Add(usedSoulSpot); } } } private static void MergeMissing(List<BasicSaveData> current, List<BasicSaveData> old) { HashSet<string> hashSet = new HashSet<string>(current.Select((BasicSaveData r) => r.Identifier.ToString())); foreach (BasicSaveData item in old) { if (!object.Equals(item.Identifier, "Outwardz.OpenCierzo.Gate.v1") && !object.Equals(item.Identifier, "Outwardz.OpenCierzo.Fixtures.v1") && !object.Equals(item.Identifier, "Outwardz.OpenCierzo.LooseSources.v1") && !object.Equals(item.Identifier, "Outwardz.OpenCierzo.Actors.v1") && !ActorEvents.IsRecord(item) && !object.Equals(item.Identifier, "Outwardz.OpenCierzo.RegionVisit.v1") && !RecoveryLedger.IsLedger(item) && !ResourceCatalog.IsRecord(item) && hashSet.Add(item.Identifier.ToString())) { current.Add(item); } } } } internal const string GateRecord = "Outwardz.OpenCierzo.Gate.v1"; internal const string FixtureRecord = "Outwardz.OpenCierzo.Fixtures.v1"; internal const string LooseRecord = "Outwardz.OpenCierzo.LooseSources.v1"; internal static readonly bool RecoveryEnabled = true; internal static volatile bool Waiting; internal static volatile bool Ready; internal static volatile bool Faulted; private static PlayerSaveData selectedPlayer; private static readonly Dictionary<string, LocalPose> localPoses = new Dictionary<string, LocalPose>(); private static Vector3 savedPosition; private static Vector3 savedForward; private static bool resumeOutside; private static WorldRecords pending; private static WorldRecords retained; private static bool itemsSubmitted; private static bool charactersApplied; private static ItemRecovery recovery; internal static string RestoreWaitReason = "native item synchronization"; private static readonly BindingFlags All = BindingFlags.Static | BindingFlags.NonPublic; internal static bool ResumingOutside => resumeOutside; internal static IEnumerable<string> SavedResourceIDs { get { if (pending != null) { return pending.ResourceIDs; } return new HashSet<string>(); } } internal static IEnumerable<string> SavedFixtureIDs { get { if (pending != null) { return pending.FixtureIDs; } return new HashSet<string>(); } } internal static IEnumerable<string> SavedLooseIDs { get { if (pending != null) { return pending.LooseIDs; } return new HashSet<string>(); } } internal static IEnumerable<string> SavedSoulSpots { get { if (pending != null) { return pending.UsedSoulSpots; } return new List<string>(); } } internal static IEnumerable<CharacterSaveData> SavedCharacters { get { List<CharacterSaveData> list; if (pending != null) { list = pending.DeferredCharacters; if (list == null) { return pending.Characters; } } else { list = new List<CharacterSaveData>(); } return list; } } internal static IEnumerable<BasicSaveData> SavedItems { get { List<BasicSaveData> list; if (pending != null) { list = pending.DeferredItems; if (list == null) { return pending.Items; } } else { list = new List<BasicSaveData>(); } return list; } } internal static IEnumerable<BasicSaveData> SavedEventStates { get { if (pending != null) { return pending.Activators; } return new List<BasicSaveData>(); } } internal static bool AllowSave() { if (!Faulted && !Waiting) { if (Plugin.Armed) { if (Ready && Plugin.Instance.WorldReady && Plugin.Instance.ActorsReady) { return Plugin.Instance.ItemsSafeToSave; } return false; } return true; } return false; } internal static void EndSession() { RestoreSelectedData(); pending = (retained = null); recovery = null; itemsSubmitted = (charactersApplied = (resumeOutside = false)); Waiting = (Ready = false); RegionReset.Clear(); } internal static void Install(Harmony harmony) { Type[] array = new Type[4] { typeof(SaveManager), typeof(SaveInstance), typeof(CharacterSaveInstanceHolder), typeof(NetworkLevelLoader) }; foreach (Type type in array) { string[] array2 = ((type == typeof(SaveManager)) ? new string[5] { "Save", "SaveSync", "Save_Internal", "ForceSaveEnvironment", "SetSaveRequired" } : ((type == typeof(SaveInstance)) ? new string[2] { "Save", "PrepareSave" } : ((type == typeof(NetworkLevelLoader)) ? new string[2] { "Save", "ForceSaveEnvironment" } : new string[1] { "Save" }))); string[] array3 = array2; foreach (string name in array3) { MethodInfo[] methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); Func<MethodInfo, bool> predicate = (MethodInfo m) => m.Name == name; MethodInfo[] array4 = methods.Where(predicate).ToArray(); if (array4.Length == 0) { throw new InvalidOperationException("Missing save hook: " + type.Name + "." + name); } MethodInfo[] array5 = array4; foreach (MethodInfo methodInfo in array5) { harmony.Patch((MethodBase)methodInfo, Hook("SaveAllowed"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } } Patch(harmony, typeof(CharacterSaveInstanceHolder), "ChooseCharacterSaveInstance", null, "Selected"); Patch(harmony, typeof(CharacterSave), "ApplyLoadedSaveToChar", "LoadingPlayer", null); Patch(harmony, typeof(EnvironmentSave), "ApplyData", "BeforeEnvironment", "AfterEnvironment", "EnvironmentFinally"); Patch(harmony, typeof(EnvironmentSave), "PrepareSave", null, "EnvironmentPrepared"); } private static HarmonyMethod Hook(string name) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown if (name != null) { return new HarmonyMethod(typeof(WorldPersistence).GetMethod(name, All)); } return null; } private static void Patch(Harmony harmony, Type type, string method, string before, string after, string final = null) { MethodInfo methodInfo = AccessTools.Method(type, method, (Type[])null, (Type[])null); if (methodInfo == null || methodInfo.GetMethodBody() == null) { throw new InvalidOperationException("Missing persistence hook: " + type.Name + "." + method); } harmony.Patch((MethodBase)methodInfo, Hook(before), Hook(after), (HarmonyMethod)null, Hook(final), (HarmonyMethod)null); } private static bool SaveAllowed() { return AllowSave(); } private static void Selected(CharacterSave __result) { if (!Plugin.Armed) { RestoreSelectedData(!Plugin.HasMultipleLocalPlayers); LoadingPresentation.RememberSave(__result?.PSave); pending = (retained = null); recovery = null; itemsSubmitted = (charactersApplied = false); RegionReset.Clear(); Waiting = (Ready = false); if (__result != null) { SelectPlayer(__result.PSave); } } } private static void LoadingPlayer(CharacterSave __instance) { if (!Plugin.Armed && selectedPlayer == null) { SelectPlayer(__instance.PSave); } } private static void SelectPlayer(PlayerSaveData data) { //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) if (data == null || ((CharacterSaveData)data).NewSave || data.AreaName != "CierzoNewTerrain" || !Plugin.PersistenceEligible) { return; } Waiting = true; if (Plugin.HasMultipleLocalPlayers && !localPoses.ContainsKey(((CharacterSaveData)data).UID)) { localPoses.Add(((CharacterSaveData)data).UID, new LocalPose { Data = data, Position = ((CharacterSaveData)data).Position, Forward = ((CharacterSaveData)data).Forward }); } selectedPlayer = data; savedPosition = ((CharacterSaveData)data).Position; savedForward = ((CharacterSaveData)data).Forward; if (!Finite(savedPosition) || !Finite(savedForward)) { Stop("The saved position is invalid.", null); return; } resumeOutside = IsOutside(savedPosition); if (resumeOutside) { ((CharacterSaveData)data).Position = new Vector3(1436.28f, 9f, 1662.37f); Plugin.Instance.SetStatus("Outdoor save selected. Restoring the joined world before returning to your saved position."); } } internal static bool IsOutside(Vector3 position) { return (position.x - 1443.9841f) * 0.96306515f - (position.z - 1660.2166f) * 0.26927066f > 0f; } private static bool Finite(Vector3 v) { if (!float.IsNaN(v.x) && !float.IsNaN(v.y) && !float.IsNaN(v.z) && !float.IsInfinity(v.x) && !float.IsInfinity(v.y)) { return !float.IsInfinity(v.z); } return false; } private static void BeforeEnvironment(EnvironmentSave __instance, out WorldRecords __state, double __0 = 0.0) { __state = null; if (Plugin.Armed || __instance.AreaName != "CierzoNewTerrain" || !Plugin.PersistenceEligible) { return; } Waiting = true; try { int num = (RecoveryEnabled ? RecoveryLedger.RepairRecords(__instance) : 0); if (num != 0) { Plugin.Instance.SetStatus("Recovery ledger restored " + num + " missing native save records."); } __state = new WorldRecords(__instance); WorldRecords original = __state; RegionReset.Prepare(__instance, __0); __state = new WorldRecords(__instance) { Original = original }; HashSet<string> actorIds = __state.ActorIDs; HashSet<string> outdoors = SavedItemPlacement.OutdoorItems(__state.Items, new HashSet<string>(__state.ResourceIDs.Concat(__state.LooseIDs)), __state.ActorIDs); __state.DeferredItems = __state.Items.Where((BasicSaveData r) => outdoors.Contains(r.Identifier.ToString())).ToList(); __state.DeferredCharacters = __state.Characters.Where((CharacterSaveData c) => ActorCatalog.Outdoor(c, actorIds)).ToList(); __instance.ItemList = __state.Items.Where((BasicSaveData r) => !outdoors.Contains(r.Identifier.ToString())).ToList(); __instance.CharList = __state.Characters.Where((CharacterSaveData c) => !ActorCatalog.Outdoor(c, actorIds)).ToList(); } catch (Exception error) { Stop("Saved world placement could not be read. Saving remains blocked.", error); throw; } } private static void AfterEnvironment(EnvironmentSave __instance, bool __result, WorldRecords __state) { if (__state != null) { __state.RestoreLists(__instance); pending = ((!__result) ? __state : (__state.HasRegionalClock ? __state.OutdoorSnapshot() : null)); if (pending != null) { pending.ReplayStates = __result; } retained = ((pending == null) ? null : pending.Snapshot()); } } private static Exception EnvironmentFinally(EnvironmentSave __instance, WorldRecords __state, Exception __exception) { __state?.RestoreLists(__instance); if (__exception != null && __state != null) { Stop("Native world loading failed; saving remains blocked.", __exception); } return __exception; } internal static void BeginRestore(Character player, HingedGate gate) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) if (Faulted) { throw new InvalidOperationException("A previous save-load error prevents world restoration."); } Waiting = true; Ready = false; if (selectedPlayer != null && ((CharacterSaveData)selectedPlayer).UID != UID.op_Implicit(player.UID) && (!Plugin.HasMultipleLocalPlayers || !((Object)(object)Plugin.FindLocalPlayer(((CharacterSaveData)selectedPlayer).UID) != (Object)null))) { throw new InvalidOperationException("The selected save belongs to a different character."); } if (pending != null) { recovery = new ItemRecovery(pending.Items, Time.realtimeSinceStartup, RecoveryEnabled); gate.Restore(pending.GateOpen && GatePermission.Allowed); Plugin.Instance.SetStatus("Restoring " + pending.DeferredItems.Count + " outdoor item records, including container contents."); if (pending.DeferredItems.Count != 0) { ItemManager.Instance.LoadItems(pending.DeferredItems, false); } } itemsSubmitted = true; } internal static void AcceptCoop(EnvironmentSave save) { if (!CoopSession.Guest || Plugin.Armed) { throw new InvalidOperationException("Co-op snapshot cannot replace a live or host world."); } WorldRecords worldRecords = new WorldRecords(save); WorldRecords worldRecords2 = worldRecords.OutdoorSnapshot(worldRecords.GateOpen); pending = worldRecords2; retained = null; pending.ReplayStates = true; pending.Activators.AddRange(save.InteractionActivatorList.Where((BasicSaveData r) => object.Equals(r.Identifier, "Outwardz.OpenCierzo.Gate.v1"))); recovery = null; itemsSubmitted = (charactersApplied = false); Waiting = true; Ready = false; } internal static void PrepareInteractionStates() { if (pending != null && pending.ReplayStates) { SceneInteractionManager.Instance.LoadInteractableStates(pending.Activators); SceneInteractionManager.Instance.LoadDropTableStates(pending.DropTables); pending.ReplayStates = false; } } internal static void DiscardRepeatedEquipment(HashSet<string> ids) { if (pending == null || ids.Count == 0) { return; } pending.Items.RemoveAll((BasicSaveData r) => ids.Contains(r.Identifier.ToString())); pending.DeferredItems.RemoveAll((BasicSaveData r) => ids.Contains(r.Identifier.ToString())); if (retained != null) { retained.Items.RemoveAll((BasicSaveData r) => ids.Contains(r.Identifier.ToString())); } } internal static bool PollRestore(Character player) { //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) RestoreWaitReason = "native item synchronization"; if (!itemsSubmitted) { return false; } if (recovery != null && !recovery.Reconcile(Time.realtimeSinceStartup, ProbeItem, (string id) => Object.op_Implicit((Object)(object)ItemManager.Instance.GetItem(id)), RetryItems, ItemManager.Instance.IsAllItemSynced)) { RestoreWaitReason = recovery.WaitingFor; return false; } if (!ItemManager.Instance.IsAllItemSynced) { return false; } if (!Plugin.Instance.ActorsSettled(out RestoreWaitReason)) { return false; } if (pending != null && !charactersApplied) { string[] array = (from c in pending.DeferredCharacters where pending.ActorIDs.Contains(c.UID) && !Object.op_Implicit((Object)(object)CharacterManager.Instance.GetCharacter(c.UID)) select c.UID).ToArray(); if (array.Length != 0) { throw new InvalidOperationException("Saved outdoor actors were not registered: " + string.Join(", ", array)); } charactersApplied = true; return false; } if (selectedPlayer != null && ((CharacterSaveData)selectedPlayer).UID == UID.op_Implicit(player.UID) && resumeOutside) { Vector3 forward = savedForward; forward.y = 0f; if (((Vector3)(ref forward)).sqrMagnitude < 0.001f) { forward = Vector3.forward; } player.Teleport(savedPosition, Quaternion.LookRotation(forward)); player.LastPosOwnWorld = savedPosition; } foreach (LocalPose value in localPoses.Values) { Character val = Plugin.FindLocalPlayer(((CharacterSaveData)value.Data).UID); if (Object.op_Implicit((Object)(object)val) && IsOutside(value.Position)) { Vector3 forward2 = value.Forward; forward2.y = 0f; if (((Vector3)(ref forward2)).sqrMagnitude < 0.001f) { forward2 = Vector3.forward; } val.Teleport(value.Position, Quaternion.LookRotation(forward2)); val.LastPosOwnWorld = value.Position; } } RestoreSelectedData(); Plugin.Instance.SetStatus("World restored: " + ((pending != null) ? pending.Items.Count : 0) + " native world-item records; " + ((pending != null) ? pending.Characters.Count : 0) + " actor records. Final world setup continues before saving is enabled."); pending = null; recovery = null; Waiting = false; Ready = true; return true; } private static RestorePresence ProbeItem(string id, string parent) { Item item = ItemManager.Instance.GetItem(id); if (!Object.op_Implicit((Object)(object)item)) { return RestorePresence.Missing; } if (!item.IsFirstSyncDone) { return RestorePresence.Initializing; } if (parent != null && (!Object.op_Implicit((Object)(object)item.ParentContainer) || ((Item)item.ParentContainer).UID != parent)) { return RestorePresence.WrongContainer; } return RestorePresence.Ready; } private static void RetryItems(List<BasicSaveData> records) { Plugin.Instance.SetStatus("Recovery retry for " + records.Count + " missing or detached world items, preserving original IDs and saved state."); ItemManager.Instance.LoadItems(records, false); } private static void RestoreSelectedData(bool clearLocals = true) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) if (selectedPlayer != null) { ((CharacterSaveData)selectedPlayer).Position = savedPosition; ((CharacterSaveData)selectedPlayer).Forward = savedForward; } selectedPlayer = null; resumeOutside = false; if (!clearLocals) { return; } foreach (LocalPose value in localPoses.Values) { ((CharacterSaveData)value.Data).Position = value.Position; ((CharacterSaveData)value.Data).Forward = value.Forward; } localPoses.Clear(); } private static void EnvironmentPrepared(EnvironmentSave __instance) { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Expected O, but got Unknown if (!Plugin.Armed || !Ready || __instance.AreaName != "CierzoNewTerrain" || !CoopSession.Authority) { return; } try { if (retained != null) { retained.KeepUnloadedRecords(__instance); } __instance.InteractionActivatorList.RemoveAll((BasicSaveData r) => object.Equals(r.Identifier, "Outwardz.OpenCierzo.Gate.v1")); __instance.InteractionActivatorList.Add(new BasicSaveData((object)"Outwardz.OpenCierzo.Gate.v1", Plugin.Instance.GateIsOpen ? "open" : "closed")); ResourceCatalog.Write(__instance.InteractionActivatorList, Plugin.Instance.ResourceIDs); ResourceCatalog.Write(__instance.InteractionActivatorList, Plugin.Instance.FixtureIDs, "Outwardz.OpenCierzo.Fixtures.v1"); ResourceCatalog.Write(__instance.InteractionActivatorList, Plugin.Instance.LooseIDs, "Outwardz.OpenCierzo.LooseSources.v1"); ResourceCatalog.Write(__instance.InteractionActivatorList, Plugin.Instance.ActorIDs, "Outwardz.OpenCierzo.Actors.v1"); ActorEvents.Save(__instance); RegionReset.Save(__instance); if (RecoveryEnabled) { RecoveryLedger.Capture(__instance); } else { __instance.InteractionActivatorList.RemoveAll(RecoveryLedger.IsLedger); } retained = new WorldRecords(__instance).Snapshot(); } catch (Exception error) { Stop("World save preparation failed; saving remains blocked.", error); throw; } } internal static void Stop(string message, Exception error) { Faulted = true; Ready = false; Plugin.Instance.Fail(message, error); } } internal static class RegionReset { internal const string Record = "Outwardz.OpenCierzo.RegionVisit.v1"; private static double lastVisit = double.NaN; internal static void Clear() { lastVisit = double.NaN; } internal static void Visit() { lastVisit = EnvironmentConditions.GameTime; } internal static bool HasClock(IEnumerable<BasicSaveData> records) { return records.Any((BasicSaveData r) => object.Equals(r.Identifier, "Outwardz.OpenCierzo.RegionVisit.v1")); } private static double Read(EnvironmentSave save) { BasicSaveData[] array = save.InteractionActivatorList.Where((BasicSaveData r) => object.Equals(r.Identifier, "Outwardz.OpenCierzo.RegionVisit.v1")).ToArray(); if (array.Length == 0) { return save.GameTime; } if (array.Length != 1 || !double.TryParse(array[0].SyncData, NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || double.IsNaN(result) || double.IsInfinity(result)) { throw new InvalidDataException("Invalid outdoor region visit clock."); } return result; } internal static void Prepare(EnvironmentSave save, double suppliedTime) { double num = ((suppliedTime != 0.0) ? suppliedTime : Math.Max(save.GameTime, EnvironmentConditions.GameTime)); lastVisit = Read(save); if (NativeTravel.ResumingOutside) { lastVisit = num; } else if (AreaManager.Instance.IsAreaExpired("ChersoneseNewTerrain", (float)(lastVisit - num))) { HashSet<string> first = ResourceCatalog.Read(save.InteractionActivatorList); HashSet<string> second = ResourceCatalog.Read(save.InteractionActivatorList, "Outwardz.OpenCierzo.LooseSources.v1"); HashSet<string> second2 = ResourceCatalog.Read(save.InteractionActivatorList, "Outwardz.OpenCierzo.Fixtures.v1"); HashSet<string> actors = ActorCatalog.Read(save.InteractionActivatorList); HashSet<string> ids = new HashSet<string>(first.Concat(second).Concat(second2).Concat(actors)); HashSet<string> outdoor = SavedItemPlacement.OutdoorItems(save.ItemList, new HashSet<string>(first.Concat(second)), actors); save.ItemList = save.ItemList.Where((BasicSaveData r) => !outdoor.Contains(r.Identifier.ToString())).ToList(); save.CharList = save.CharList.Where((CharacterSaveData c) => !ActorCatalog.Outdoor(c, actors)).ToList(); save.InteractionActivatorList = save.InteractionActivatorList.Where((BasicSaveData r) => !ids.Contains(r.Identifier.ToString()) && !ResourceCatalog.IsRecord(r) && !object.Equals(r.Identifier, "Outwardz.OpenCierzo.LooseSources.v1") && !object.Equals(r.Identifier, "Outwardz.OpenCierzo.Fixtures.v1") && !object.Equals(r.Identifier, "Outwardz.OpenCierzo.Actors.v1") && !ActorEvents.IsRecord(r) && !object.Equals(r.Identifier, "Outwardz.OpenCierzo.RegionVisit.v1") && !RecoveryLedger.IsLedger(r)).ToList(); save.DropTablesList = save.DropTablesList.Where((BasicSaveData r) => !BelongsTo(r, ids)).ToList(); save.UsedSoulSpots = (save.UsedSoulSpots ?? new List<string>()).Where((string id) => !Owned(id, ids)).ToList(); lastVisit = num; Write(save.InteractionActivatorList, num); Plugin.Instance.SetStatus("Chersonese reached its native reset interval; outdoor resources and ordinary world drops reset. Town records are preserved."); } } internal static bool BelongsTo(BasicSaveData row, HashSet<string> ids) { return Owned(row.Identifier.ToString(), ids); } internal static bool Owned(string id, HashSet<string> ids) { if (!ids.Contains(id)) { return ids.Any((string source) => id.StartsWith(source + "_", StringComparison.Ordinal) || (source.StartsWith("MerchantPouch_", StringComparison.Ordinal) && id.StartsWith("MerchantDrop_", StringComparison.Ordinal) && id.EndsWith("_" + source.Substring("MerchantPouch_".Length), StringComparison.Ordinal))); } return true; } internal static void Save(EnvironmentSave save) { if (double.IsNaN(lastVisit)) { lastVisit = save.GameTime; } Write(save.InteractionActivatorList, lastVisit); } private static void Write(List<BasicSaveData> rows, double value) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown rows.RemoveAll((BasicSaveData r) => object.Equals(r.Identifier, "Outwardz.OpenCierzo.RegionVisit.v1")); rows.Add(new BasicSaveData((object)"Outwardz.OpenCierzo.RegionVisit.v1", value.ToString("R", CultureInfo.InvariantCulture))); } } internal sealed class WorldResources { private sealed class Candidate { internal Item Item; internal bool Loose; internal string SourceUID; internal string SceneName; internal string SaveUID; internal MonoBehaviour[] Scripts; internal Dictionary<Behaviour, bool> Behaviours; internal Dictionary<Collider, bool> Colliders; internal HashSet<int> AwakeObjects; internal Dictionary<Rigidbody, bool[]> Bodies; } private readonly HashSet<Component> retiredSources = new HashSet<Component>(); private readonly List<Candidate> candidates = new List<Candidate>(); private readonly List<Item> active = new List<Item>(); private readonly HashSet<int> roots = new HashSet<int>(); private readonly HashSet<string> ids = new HashSet<string>(); private readonly HashSet<string> looseIDs = new HashSet<string>(); private readonly ResourceLootStartup lootStartup = new ResourceLootStartup(); private static readonly FieldInfo QuestOnGather = typeof(SelfFilledItemContainer).GetField("m_questEventOnGather", BindingFlags.Instance | BindingFlags.NonPublic); internal string WaitingFor = "resource initialization"; internal IEnumerable<string> IDs => ids; internal IEnumerable<string> LooseIDs => looseIDs; internal bool RetiredSource(Component c) { return retiredSources.Contains(c); } internal void Capture(Scene scene) { if (QuestOnGather == null) { throw new InvalidOperationException("Missing native resource quest-event field."); } GameObject[] rootGameObjects = ((Scene)(ref scene)).GetRootGameObjects(); foreach (GameObject val in rootGameObjects) { Item[] componentsInChildren = val.GetComponentsInChildren<Item>(true); foreach (Item item in componentsInChildren) { bool flag = ((object)item).GetType() == typeof(Item) && item.ItemID == 9200010 && ((Component)item).GetComponentsI