Decompiled source of CustomWorldAPI v1.0.0

plugins/LuckyShotCustomWorldAPI.dll

Decompiled 18 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using Microsoft.CodeAnalysis;
using Shooterlatro.Core;
using Shooterlatro.Game;
using Shooterlatro.Shaders.DynamicWorldChange;
using Shooterlatro.Worlds;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("LuckyShotCustomWorldAPI")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+4135dd1490a61fe647f2a0e54287f36471f5cf7f")]
[assembly: AssemblyProduct("LuckyShotCustomWorldAPI")]
[assembly: AssemblyTitle("LuckyShotCustomWorldAPI")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace LuckyShot.CustomWorldAPI
{
	public sealed class RunWorldRef
	{
		public WorldType? BuiltIn { get; set; }

		public string CustomId { get; set; }

		public static RunWorldRef BuiltIn_(WorldType t)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return new RunWorldRef
			{
				BuiltIn = t
			};
		}

		public static RunWorldRef Custom(string id)
		{
			return new RunWorldRef
			{
				CustomId = id
			};
		}

		public override string ToString()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			object obj = CustomId;
			if (obj == null)
			{
				WorldType? builtIn = BuiltIn;
				obj = (builtIn.HasValue ? ((object)builtIn.GetValueOrDefault()/*cast due to .constrained prefix*/).ToString() : null) ?? "?";
			}
			return (string)obj;
		}
	}
	public sealed class CustomRun
	{
		public string Id { get; set; }

		public string DisplayName { get; set; }

		public string Description { get; set; }

		public string OwnerModId { get; set; }

		public int SequencePolicy { get; set; } = 1;

		public List<RunWorldRef> Worlds { get; } = new List<RunWorldRef>();

		public bool IsRegistered { get; internal set; }

		public static CustomRun Create(string id, string displayName = null)
		{
			return new CustomRun
			{
				Id = id,
				DisplayName = (displayName ?? id)
			};
		}

		public CustomRun Described(string text)
		{
			Description = text;
			return this;
		}

		public CustomRun WithOwner(string owner)
		{
			OwnerModId = owner;
			return this;
		}

		public CustomRun Stable()
		{
			SequencePolicy = 1;
			return this;
		}

		public CustomRun Shuffled()
		{
			SequencePolicy = 0;
			return this;
		}

		public CustomRun AddBuiltIn(WorldType t)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			Worlds.Add(RunWorldRef.BuiltIn_(t));
			return this;
		}

		public CustomRun AddCustom(string id)
		{
			Worlds.Add(RunWorldRef.Custom(id));
			return this;
		}

		public CustomRun Register(string ownerModId = null)
		{
			return CustomRuns.Register(this, ownerModId);
		}

		public override string ToString()
		{
			return Id + " (" + Worlds.Count + " worlds)";
		}
	}
	public static class CustomRuns
	{
		private static readonly object Sync = new object();

		private static readonly Dictionary<string, CustomRun> Runs = new Dictionary<string, CustomRun>(StringComparer.OrdinalIgnoreCase);

		public static IReadOnlyCollection<CustomRun> All
		{
			get
			{
				lock (Sync)
				{
					return new List<CustomRun>(Runs.Values).AsReadOnly();
				}
			}
		}

		public static event Action<CustomRun> Registered;

		public static event Action<CustomRun> Started;

		public static event Action<CustomRun> Aborted;

		public static CustomRun Get(string id)
		{
			if (string.IsNullOrWhiteSpace(id))
			{
				return null;
			}
			lock (Sync)
			{
				CustomRun value;
				return Runs.TryGetValue(id, out value) ? value : null;
			}
		}

		public static bool IsActive(string id)
		{
			lock (Sync)
			{
				if (!Runs.TryGetValue(id, out var value))
				{
					return false;
				}
				return value.Worlds.Count > 0 && value.IsRegistered && value.Worlds.Exists((RunWorldRef w) => string.IsNullOrEmpty(w.CustomId) || CustomWorlds.IsRegistered(w.CustomId));
			}
		}

		public static bool Abort(string id)
		{
			CustomRun value;
			lock (Sync)
			{
				if (!Runs.TryGetValue(id, out value))
				{
					return false;
				}
				value.IsRegistered = false;
				Runs.Remove(id);
			}
			try
			{
				CustomRuns.Aborted?.Invoke(value);
			}
			catch
			{
			}
			return true;
		}

		public static CustomRun Register(CustomRun run, string ownerModId = null)
		{
			if (run == null)
			{
				throw new ArgumentNullException("run");
			}
			if (string.IsNullOrWhiteSpace(run.Id))
			{
				throw new ArgumentException("CustomRun.Id must be set.", "run");
			}
			if (string.IsNullOrWhiteSpace(run.DisplayName))
			{
				run.DisplayName = run.Id;
			}
			lock (Sync)
			{
				if (Runs.ContainsKey(run.Id))
				{
					return null;
				}
				run.OwnerModId = ownerModId ?? InferOwner();
				Runs[run.Id] = run;
				run.IsRegistered = true;
			}
			try
			{
				CustomRuns.Registered?.Invoke(run);
			}
			catch
			{
			}
			return run;
		}

		public static bool Unregister(string id)
		{
			lock (Sync)
			{
				if (!Runs.TryGetValue(id, out var value))
				{
					return false;
				}
				Runs.Remove(id);
				value.IsRegistered = false;
			}
			return true;
		}

		public static void Cleanup()
		{
			lock (Sync)
			{
				List<string> list = new List<string>();
				foreach (KeyValuePair<string, CustomRun> run in Runs)
				{
					CustomRun value = run.Value;
					value.IsRegistered = false;
					list.Add(run.Key);
					try
					{
						CustomRuns.Aborted?.Invoke(value);
					}
					catch
					{
					}
				}
				foreach (string item in list)
				{
					Runs.Remove(item);
				}
			}
		}

		public static bool Start(string id)
		{
			if (IsActive(id))
			{
				return false;
			}
			CustomRun customRun = Get(id);
			if (customRun == null)
			{
				return false;
			}
			ScenarioManager val = ScenarioInjector.ManagerPublic();
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			foreach (RunWorldRef world in customRun.Worlds)
			{
				if (!string.IsNullOrEmpty(world.CustomId))
				{
					CustomWorlds.Get(world.CustomId);
				}
			}
			List<ScenarioInstance> list = new List<ScenarioInstance>();
			List<ScenarioInstance> list2 = new List<ScenarioInstance>(val.scenarios);
			foreach (RunWorldRef w in customRun.Worlds)
			{
				ScenarioInstance val2 = null;
				if (!string.IsNullOrEmpty(w.CustomId))
				{
					val2 = CustomWorlds.Get(w.CustomId)?.Instance;
				}
				else if (w.BuiltIn.HasValue)
				{
					val2 = list2.Find((ScenarioInstance s) => (Object)(object)s != (Object)null && (Object)(object)s.asset != (Object)null && s.asset.worldType == w.BuiltIn.Value);
				}
				if ((Object)(object)val2 != (Object)null)
				{
					list.Add(val2);
				}
			}
			foreach (ScenarioInstance item in list2)
			{
				if ((Object)(object)item != (Object)null && !list.Contains(item))
				{
					list.Add(item);
				}
			}
			val.scenarios.Clear();
			val.scenarios.AddRange(list);
			val.SequencePolicy = customRun.SequencePolicy;
			val.ResetSequence();
			try
			{
				CustomRuns.Started?.Invoke(customRun);
			}
			catch
			{
			}
			return true;
		}

		public static string[] Names()
		{
			List<string> list = new List<string>();
			foreach (CustomRun item in All)
			{
				list.Add(item.Id + " - " + item.DisplayName + " [" + item.Worlds.Count + "]");
			}
			return list.ToArray();
		}

		private static string InferOwner()
		{
			try
			{
				string text = Assembly.GetCallingAssembly()?.GetName()?.Name;
				return string.IsNullOrEmpty(text) ? "unknown" : text;
			}
			catch
			{
				return "unknown";
			}
		}
	}
	public sealed class CustomWorld
	{
		public string Id { get; set; }

		public string DisplayName { get; set; }

		public string Description { get; set; }

		public WorldType Category { get; set; }

		public string OwnerModId { get; set; }

		public Texture SkyboxTexture { get; set; }

		public Color SkyboxTint { get; set; } = Color.white;

		public float SkyboxExposure { get; set; } = 1f;

		public float SkyboxRotation { get; set; }

		public bool OverrideLight { get; set; }

		public Color LightColor { get; set; } = Color.white;

		public float LightIntensity { get; set; } = 1f;

		public Vector3 LightRotation { get; set; } = new Vector3(50f, -30f, 0f);

		public float Radius { get; set; } = 100f;

		internal ScenarioInstance Instance { get; set; }

		public bool IsRegistered { get; internal set; }

		public static CustomWorld Create(string id, string displayName = null)
		{
			return new CustomWorld
			{
				Id = id,
				DisplayName = (displayName ?? id)
			};
		}

		public CustomWorld Described(string text)
		{
			Description = text;
			return this;
		}

		public CustomWorld WithCategory(WorldType c)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			Category = c;
			return this;
		}

		public CustomWorld WithOwner(string owner)
		{
			OwnerModId = owner;
			return this;
		}

		public CustomWorld WithSkybox(Texture tex)
		{
			SkyboxTexture = tex;
			return this;
		}

		public CustomWorld WithSkyboxTint(Color c)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			SkyboxTint = c;
			return this;
		}

		public CustomWorld WithSkyboxExposure(float e)
		{
			SkyboxExposure = e;
			return this;
		}

		public CustomWorld WithSkyboxRotation(float deg)
		{
			SkyboxRotation = deg;
			return this;
		}

		public CustomWorld WithLight(Color color, float intensity)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			OverrideLight = true;
			LightColor = color;
			LightIntensity = intensity;
			return this;
		}

		public CustomWorld WithLightRotation(Vector3 euler)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			LightRotation = euler;
			return this;
		}

		public CustomWorld WithRadius(float r)
		{
			Radius = r;
			return this;
		}

		public CustomWorld Register(string ownerModId = null)
		{
			return CustomWorlds.Register(this, ownerModId);
		}

		public override string ToString()
		{
			return Id + " (" + DisplayName + ")";
		}
	}
	public static class CustomWorlds
	{
		private static readonly object Sync = new object();

		private static readonly Dictionary<string, CustomWorld> Worlds = new Dictionary<string, CustomWorld>(StringComparer.OrdinalIgnoreCase);

		private static readonly List<CustomWorld> Pending = new List<CustomWorld>();

		private static bool _hooked;

		public static IReadOnlyCollection<CustomWorld> All
		{
			get
			{
				lock (Sync)
				{
					return new List<CustomWorld>(Worlds.Values).AsReadOnly();
				}
			}
		}

		public static event Action<CustomWorld> Registered;

		public static event Action<CustomWorld> Unregistered;

		public static event Action<CustomWorld> Activating;

		public static CustomWorld Get(string id)
		{
			if (string.IsNullOrWhiteSpace(id))
			{
				return null;
			}
			lock (Sync)
			{
				CustomWorld value;
				return Worlds.TryGetValue(id, out value) ? value : null;
			}
		}

		public static CustomWorld Register(CustomWorld world, string ownerModId = null)
		{
			if (world == null)
			{
				throw new ArgumentNullException("world");
			}
			if (string.IsNullOrWhiteSpace(world.Id))
			{
				throw new ArgumentException("CustomWorld.Id must be set.", "world");
			}
			if (string.IsNullOrWhiteSpace(world.DisplayName))
			{
				world.DisplayName = world.Id;
			}
			lock (Sync)
			{
				if (Worlds.ContainsKey(world.Id) || Pending.Exists((CustomWorld p) => string.Equals(p.Id, world.Id, StringComparison.OrdinalIgnoreCase)))
				{
					return null;
				}
				world.OwnerModId = ownerModId ?? InferOwner();
				EnsureHook();
				if (ScenarioInjector.ManagerAvailable())
				{
					InjectNow(world);
				}
				else
				{
					Pending.Add(world);
				}
			}
			return world;
		}

		public static bool Unregister(string id)
		{
			CustomWorld value;
			lock (Sync)
			{
				if (!Worlds.TryGetValue(id, out value))
				{
					CustomWorld customWorld = Pending.Find((CustomWorld x) => string.Equals(x.Id, id, StringComparison.OrdinalIgnoreCase));
					if (customWorld != null)
					{
						Pending.Remove(customWorld);
						customWorld.IsRegistered = false;
						return true;
					}
					return false;
				}
				ScenarioInjector.Remove(value.Instance);
				value.IsRegistered = false;
				Worlds.Remove(id);
			}
			try
			{
				CustomWorlds.Unregistered?.Invoke(value);
			}
			catch
			{
			}
			return true;
		}

		public static bool Activate(string id)
		{
			CustomWorld customWorld;
			lock (Sync)
			{
				customWorld = Get(id);
				if (customWorld == null || (Object)(object)customWorld.Instance == (Object)null)
				{
					return false;
				}
			}
			try
			{
				CustomWorlds.Activating?.Invoke(customWorld);
			}
			catch
			{
			}
			return ScenarioInjector.Activate(customWorld.Instance);
		}

		public static void ClearPending()
		{
			lock (Sync)
			{
				Pending.Clear();
			}
		}

		public static void Cleanup()
		{
			lock (Sync)
			{
				CustomWorld[] array = Worlds.Values.ToArray();
				foreach (CustomWorld customWorld in array)
				{
					ScenarioInjector.Remove(customWorld.Instance);
					customWorld.IsRegistered = false;
					Worlds.Remove(customWorld.Id);
					try
					{
						CustomWorlds.Unregistered?.Invoke(customWorld);
					}
					catch
					{
					}
				}
				Pending.Clear();
			}
		}

		public static string[] Names()
		{
			List<string> list = new List<string>();
			foreach (CustomWorld item in All)
			{
				list.Add(item.Id + " - " + item.DisplayName);
			}
			return list.ToArray();
		}

		public static bool IsRegistered(string id)
		{
			lock (Sync)
			{
				return Worlds.ContainsKey(id) || Pending.Exists((CustomWorld p) => string.Equals(p.Id, id, StringComparison.OrdinalIgnoreCase));
			}
		}

		private static void EnsureHook()
		{
			if (!_hooked)
			{
				_hooked = true;
				GameEvents.OnGameStarted += HandleGameStarted;
			}
		}

		private static void HandleGameStarted(OnGameStartedContext ctx)
		{
			List<CustomWorld> list;
			lock (Sync)
			{
				if (Pending.Count == 0)
				{
					return;
				}
				list = new List<CustomWorld>(Pending);
				Pending.Clear();
			}
			foreach (CustomWorld item in list)
			{
				lock (Sync)
				{
					InjectNow(item);
				}
				try
				{
					CustomWorlds.Registered?.Invoke(item);
				}
				catch
				{
				}
			}
		}

		private static void InjectNow(CustomWorld world)
		{
			world.Instance = ScenarioFactory.CreateInstance(world);
			world.IsRegistered = ScenarioInjector.Inject(world.Instance);
			if (world.IsRegistered)
			{
				Worlds[world.Id] = world;
			}
			try
			{
				CustomWorlds.Registered?.Invoke(world);
			}
			catch
			{
			}
		}

		private static string InferOwner()
		{
			try
			{
				string text = Assembly.GetCallingAssembly()?.GetName()?.Name;
				return string.IsNullOrEmpty(text) ? "unknown" : text;
			}
			catch
			{
				return "unknown";
			}
		}
	}
	[BepInPlugin("com.luckyshot.wiki.customworldapi", "LuckyShot Custom World API", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		private void Awake()
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)"LuckyShot Custom World API loaded (library only, no demos, no in-game keys).");
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Mods: use CustomWorld.Create(...).Register() and CustomRun.Create(...).Register(); then CustomRuns.Start(id).");
		}
	}
	internal static class PluginInfo
	{
		public const string GUID = "com.luckyshot.wiki.customworldapi";

		public const string NAME = "LuckyShot Custom World API";

		public const string VERSION = "1.0.0";
	}
	internal static class ScenarioFactory
	{
		public static ScenarioInstance CreateInstance(CustomWorld w)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: 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_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)
			ScenarioAsset val = ScriptableObject.CreateInstance<ScenarioAsset>();
			val.displayName = w.DisplayName;
			val.worldType = w.Category;
			val.skyboxTexture = w.SkyboxTexture;
			val.skyboxTint = w.SkyboxTint;
			val.skyboxExposure = w.SkyboxExposure;
			val.skyboxRotation = w.SkyboxRotation;
			val.overrideDirectionalLight = w.OverrideLight;
			val.directionalLightColor = w.LightColor;
			val.directionalLightIntensity = w.LightIntensity;
			val.directionalLightRotation = w.LightRotation;
			val.radiusTarget = w.Radius;
			ScenarioInstance obj = new GameObject("CustomWorld_" + w.Id)
			{
				hideFlags = (HideFlags)61
			}.AddComponent<ScenarioInstance>();
			obj.asset = val;
			return obj;
		}
	}
	internal static class ScenarioInjector
	{
		private static ScenarioManager Manager()
		{
			GameManager instance = GameManager.Instance;
			if (!((Object)(object)instance != (Object)null))
			{
				return null;
			}
			return instance.scenarioManager;
		}

		public static ScenarioManager ManagerPublic()
		{
			return Manager();
		}

		public static bool ManagerAvailable()
		{
			return (Object)(object)Manager() != (Object)null;
		}

		public static bool Inject(ScenarioInstance inst)
		{
			ScenarioManager val = Manager();
			if ((Object)(object)val == (Object)null || (Object)(object)inst == (Object)null)
			{
				return false;
			}
			if (!val.scenarios.Contains(inst))
			{
				val.scenarios.Add(inst);
			}
			return true;
		}

		public static void Remove(ScenarioInstance inst)
		{
			ScenarioManager val = Manager();
			if ((Object)(object)val != (Object)null && (Object)(object)inst != (Object)null)
			{
				val.scenarios.Remove(inst);
			}
		}

		public static bool Activate(ScenarioInstance inst)
		{
			ScenarioManager val = Manager();
			if ((Object)(object)val == (Object)null || (Object)(object)inst == (Object)null)
			{
				return false;
			}
			val.PreviewActivateScenario(inst);
			return true;
		}
	}
}