using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Logging;
using ComputerysModdingUtilities;
using FishNet.Managing.Scened;
using FishNet.Transporting;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using MyceliumNetworking;
using Steamworks;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: StraftatMod(false)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Koki")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+8e8ce28e4576cafe43a76154f184be8c5c2259ce")]
[assembly: AssemblyProduct("CustomLevelsReborn")]
[assembly: AssemblyTitle("CustomLevelsReborn")]
[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;
}
}
}
[DefaultExecutionOrder(-500)]
public class ImportGameObjects : MonoBehaviour
{
private void Awake()
{
foreach (GameObject sceneGO in StealSceneGOs.SceneGOs)
{
GameObject obj = Object.Instantiate<GameObject>(sceneGO);
obj.transform.SetParent(((Component)this).transform);
obj.SetActive(true);
((Object)obj).name = ((Object)obj).name.Replace("(Clone)", "");
}
}
}
internal enum WeaponType
{
AAA12,
AKK,
APMine,
AR15,
BaseballBat,
Bayshore,
BeamLoad,
Bender,
BigFattyBro,
BlankState,
Bublee,
Bukanee,
Claymore,
Couperet,
Crisis,
CurvedKnife,
DF_Blister,
DF_Cyst,
DF_GodSword,
DF_Torrent,
Dispenser,
DualLauncher,
Elephant,
FG42,
Flamberge,
FlashLight,
Gamma,
GammaGen2,
GlaiveGun,
GlandGrenade,
Glock,
Gun,
Gust,
HandCanon,
HandGrenade,
Havoc,
Hill_H15,
HK_Caws,
HK_G11,
Impetus,
JahvalMahmaerd,
Kanye,
Katana,
Keso,
Kusma,
M2000,
Mac10,
Minigun,
Mortini,
Nizeh,
Nugget,
Phoenix,
Propeller,
Prophet,
ProximityMine,
QCW05,
Repulsar,
Revolver,
RocketLauncher,
SawedOff,
Shotgun,
Silenzzio,
SMG,
SmithCarbine,
StunGrenade,
StunMine,
Stylus,
Taser,
Tromblonj,
Warden,
Webley,
Yangtse
}
public class CustomSpawner : MonoBehaviour
{
[SerializeField]
private WeaponType _weapon;
[Range(0f, 60f)]
[SerializeField]
private float _weaponRespawnTimeInSeconds = 3f;
private void Awake()
{
string text = _weapon.ToString();
if (text == "AKK")
{
text = "AK-K";
}
if (SpawnerManager.NameToWeaponDict.Count == 0)
{
SpawnerManager.PopulateAllWeapons();
}
ItemSpawner component = ((Component)this).gameObject.GetComponent<ItemSpawner>();
component.itemToSpawn = SpawnerManager.NameToWeaponDict[text];
((Spawner)component).weaponRespawnTimeInSeconds = _weaponRespawnTimeInSeconds;
((Component)component).gameObject.SetActive(true);
}
}
internal class SyncMaps : MonoBehaviour
{
[HarmonyPatch(typeof(SteamLobby), "OnLobbyEntered")]
private static class HandleLobbyEnter
{
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_0050: Expected O, but got Unknown
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Expected O, but got Unknown
//IL_0077: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Expected O, but got Unknown
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Expected O, but got Unknown
MethodInfo methodInfo = AccessTools.Method(typeof(Transport), "SetClientAddress", (Type[])null, (Type[])null);
MethodInfo methodInfo2 = AccessTools.Method(typeof(SyncMaps), "DetermineMidMatchJoin", (Type[])null, (Type[])null);
return new CodeMatcher(instructions, (ILGenerator)null).MatchForward(true, (CodeMatch[])(object)new CodeMatch[2]
{
new CodeMatch((OpCode?)OpCodes.Callvirt, (object)methodInfo, (string)null),
new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null)
}).Insert((CodeInstruction[])(object)new CodeInstruction[2]
{
new CodeInstruction(OpCodes.Call, (object)methodInfo2),
new CodeInstruction(OpCodes.Ret, (object)null)
}).InstructionEnumeration();
}
}
[HarmonyPatch(typeof(MapSelection), "UpdateScenes")]
private static class BlockDisabledMapsFromQueue
{
private static void Prefix(MapSelection __instance)
{
SelectSceneInstance[] sceneInstances = __instance.sceneInstances;
foreach (SelectSceneInstance val in sceneInstances)
{
if (Enumerable.Contains(mapsToDisable.Keys, val.sceneName))
{
val.selected = false;
}
}
}
}
[HarmonyPatch(typeof(SceneMotor), "ServerStartGameScene")]
private static class SetMapsInRotation
{
private static void Postfix(SceneMotor __instance)
{
CollectionExtensions.Do<string>(__instance.PlayListMapsQueue.Where(((IEnumerable<string>)CLRPlugin.SceneToBundleDir.Keys).Contains<string>), (Action<string>)delegate(string map)
{
foreach (string mapVersion in CLRPlugin.MapVersions)
{
if (mapVersion.Substring(0, mapVersion.LastIndexOf("-")) == map)
{
customMapsInRotation.Add(mapVersion);
}
}
});
MyceliumNetwork.SetLobbyData("MapsInRotation", (object)string.Join(";", customMapsInRotation));
MyceliumNetwork.SetLobbyData("GameStarted", (object)true);
customMapsInRotation.Clear();
}
}
[HarmonyPatch(typeof(SteamLobby), "EnterExplorationMap")]
private static class BlockExploringDisabledMap
{
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
//IL_0043: Expected O, but got Unknown
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Expected O, but got Unknown
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Expected O, but got Unknown
MethodInfo methodInfo = AccessTools.Method(typeof(SyncMaps), "IsMapDisabled", (Type[])null, (Type[])null);
Label label = default(Label);
return new CodeMatcher(instructions, generator).End().CreateLabel(ref label).Start()
.Insert((CodeInstruction[])(object)new CodeInstruction[3]
{
new CodeInstruction(OpCodes.Ldarg_1, (object)null),
new CodeInstruction(OpCodes.Call, (object)methodInfo),
new CodeInstruction(OpCodes.Brtrue, (object)label)
})
.InstructionEnumeration();
}
}
private static readonly uint ID = 568324179u;
private static Dictionary<string, List<CSteamID>> mapsToDisable = new Dictionary<string, List<CSteamID>>();
private static List<string> customMapsInRotation = new List<string>();
private void Awake()
{
MyceliumNetwork.RegisterNetworkObject((object)this, ID, 0);
MyceliumNetwork.RegisterLobbyDataKey("MapsInRotation");
MyceliumNetwork.RegisterLobbyDataKey("GameStarted");
MyceliumNetwork.LobbyCreated += ResetMapLists;
MyceliumNetwork.PlayerLeft += OnLobbyLeave;
SceneManager.sceneLoaded += ResetLobbyKey;
}
private void ResetLobbyKey(Scene scene, LoadSceneMode _)
{
if (MyceliumNetwork.IsHost && MyceliumNetwork.InLobby && ((Scene)(ref scene)).name == "MainMenu")
{
MyceliumNetwork.SetLobbyData("GameStarted", (object)false);
}
}
private void ResetMapLists()
{
mapsToDisable.Clear();
customMapsInRotation.Clear();
MyceliumNetwork.SetLobbyData("GameStarted", (object)false);
}
private static void Connect()
{
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
if (((Transport)SteamLobby.Instance._fishySteamworks).StartConnection(false))
{
SteamLobby.Instance.inSteamLobby = true;
TargetedRPC(MyceliumNetwork.LobbyHost, "DisableNonSharedMaps", new object[1] { string.Join(";;", CLRPlugin.MapVersions) });
}
else
{
Debug.LogError((object)"Failed to start FishySteamworks connection");
SteamLobby.Instance.LeaveLobby();
}
}
private static void DetermineMidMatchJoin()
{
if (MyceliumNetwork.IsHost || !MyceliumNetwork.GetLobbyData<bool>("GameStarted"))
{
Connect();
}
else if (MyceliumNetwork.GetLobbyData<string>("MapsInRotation").Split(";").Except(CLRPlugin.MapVersions)
.Any())
{
PauseManager.Instance.WriteOfflineLog("You are missing maps currently being used in this lobby!");
SteamLobby.Instance.LeaveLobby();
}
else
{
Connect();
}
}
private string[] GetNonSharedMaps(string input)
{
return (from map in CLRPlugin.MapVersions.Except(input.Split(";;"))
select map.Substring(0, map.LastIndexOf("-"))).ToArray();
}
[CustomRPC]
private void DisableNonSharedMaps(string clientMapString, RPCInfo sender)
{
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
//IL_00b9: 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)
string[] nonSharedMaps = GetNonSharedMaps(clientMapString);
string[] array = nonSharedMaps;
foreach (string key in array)
{
if (!mapsToDisable.TryGetValue(key, out var value))
{
value = new List<CSteamID>();
mapsToDisable.Add(key, value);
}
value.Add(sender.SenderSteamID);
}
foreach (KeyValuePair<string, GameObject> mapDisabledSprite in CLRPlugin.MapDisabledSprites)
{
if (nonSharedMaps.Contains(mapDisabledSprite.Key))
{
mapDisabledSprite.Value.SetActive(true);
}
}
if (nonSharedMaps.Length != 0 && SceneMotor.Instance.currentSceneName == null && !SceneMotor.Instance.testMap)
{
PauseManager.Instance.ShowInfoPopup(SteamFriends.GetFriendPersonaName(sender.SenderSteamID) + " is missing " + string.Join(", ", nonSharedMaps) + "!");
}
}
private static bool IsMapDisabled(string mapname)
{
bool num = Enumerable.Contains(mapsToDisable.Keys, mapname);
if (num)
{
PauseManager.Instance.WriteOfflineLog("Someone in the lobby doesn't have this map");
}
return num;
}
private void OnLobbyLeave(CSteamID id)
{
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
if (!MyceliumNetwork.IsHost || MyceliumNetwork.Players.Length == 0)
{
return;
}
List<string> list = new List<string>();
foreach (KeyValuePair<string, List<CSteamID>> item in mapsToDisable)
{
if (item.Value.Contains(id))
{
item.Value.Remove(id);
if (item.Value.Count == 0)
{
list.Add(item.Key);
CLRPlugin.MapDisabledSprites[item.Key].SetActive(false);
}
}
}
CollectionExtensions.Do<string>((IEnumerable<string>)list, (Action<string>)delegate(string m)
{
mapsToDisable.Remove(m);
});
if (list.Count > 0 && (SceneMotor.Instance.currentSceneName == null || !SceneMotor.Instance.testMap))
{
PauseManager.Instance.WriteOfflineLog(string.Join(", ", list) + " have been re-enabled.");
}
}
private static void TargetedRPC(CSteamID target, string methodname, object[] parameters)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
MyceliumNetwork.RPCTarget(ID, methodname, target, (ReliableType)1, parameters);
}
}
internal static class BundleLoad
{
private static AssetBundle bundleRef;
internal static void UnloadBundle(Scene scene)
{
if (Object.op_Implicit((Object)(object)bundleRef) && CLRPlugin.SceneToBundleDir.ContainsKey(((Scene)(ref scene)).name))
{
bundleRef.Unload(true);
bundleRef = null;
}
}
internal static void Start(string sceneName)
{
if (!Object.op_Implicit((Object)(object)bundleRef) && CLRPlugin.SceneToBundleDir.ContainsKey(sceneName))
{
bundleRef = AssetBundle.LoadFromFile(CLRPlugin.SceneToBundleDir[sceneName]);
}
}
}
internal static class MultiplayerBundleLoad
{
[HarmonyPatch(typeof(SceneMotor), "GetNextMap")]
private static class LoadHost
{
private static void Prepare()
{
SceneManager.sceneUnloaded += BundleLoad.UnloadBundle;
}
private static void Postfix(string __result)
{
BundleLoad.Start(__result);
}
}
[HarmonyPatch(typeof(DefaultSceneProcessor), "BeginLoadAsync")]
private static class LoadClient
{
private static void Prefix(string sceneName)
{
BundleLoad.Start(sceneName);
}
}
}
[HarmonyPatch(typeof(SceneMotor), "RpcLogic___EnterScene_3615296227")]
internal static class SingleplayerBundleLoad
{
private static void Prefix(string sceneName)
{
BundleLoad.Start(sceneName);
}
}
[HarmonyPatch(typeof(MapsManager), "InitMaps")]
internal static class RegisterScenes
{
private static void Postfix(MapsManager __instance)
{
//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_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: 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_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_0072: Expected O, but got Unknown
//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)
List<Map> list = new List<Map>();
int num = __instance.allMaps.Length;
foreach (string key in CLRPlugin.SceneToBundleDir.Keys)
{
Map val = new Map
{
index = num++,
mapName = key,
isDlcExclusive = false,
isAltMap = key.EndsWith("_alt"),
isSelected = false,
isUnlocked = true,
mapInstance = null
};
list.Add(val);
__instance.allMapsDict.Add(val.mapName, val);
GameObject val2 = Object.Instantiate<GameObject>(__instance.mapInstance, __instance.standardMapParent.position, Quaternion.identity, __instance.standardMapParent);
val.mapInstance = val2.GetComponent<MapInstance>();
val.mapInstance.name = val.mapName;
val.mapInstance.selected = val.isSelected;
}
__instance.SortMapsFromMapInstanceName();
Map[] allMaps = __instance.allMaps;
List<Map> list2 = list;
int num2 = 0;
Map[] array = (Map[])(object)new Map[allMaps.Length + list2.Count];
ReadOnlySpan<Map> readOnlySpan = new ReadOnlySpan<Map>(allMaps);
readOnlySpan.CopyTo(new Span<Map>(array).Slice(num2, readOnlySpan.Length));
num2 += readOnlySpan.Length;
foreach (Map item in list2)
{
array[num2] = item;
num2++;
}
__instance.allMaps = array;
List<int> list3 = new List<int>();
list3.AddRange(__instance.unlockedMaps);
list3.AddRange(list.Select((Map map) => map.index));
__instance.unlockedMaps = list3.ToArray();
}
}
[HarmonyPatch(typeof(MapInstance), "Start")]
internal static class SetThumbnail
{
public static void Postfix(MapInstance __instance)
{
if (!Object.op_Implicit((Object)(object)__instance.sprite) && CLRPlugin.MapThumbnails.ContainsKey(__instance.name))
{
__instance.sprite = CLRPlugin.MapThumbnails[__instance.name];
__instance.img.texture = (Texture)(object)__instance.sprite;
__instance.UpdateUI();
}
}
}
[HarmonyPatch(typeof(SelectSceneInstance), "Start")]
internal static class SetThumbnailAgain
{
public static void Postfix(SelectSceneInstance __instance)
{
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_0068: Expected O, but got Unknown
//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
if (!Object.op_Implicit((Object)(object)__instance.sprite))
{
if (CLRPlugin.MapThumbnails.ContainsKey(__instance.sceneName))
{
__instance.sprite = CLRPlugin.MapThumbnails[__instance.sceneName];
__instance.mapImg.texture = (Texture)(object)__instance.sprite;
__instance.UpdateUI();
}
if (!CLRPlugin.MapDisabledSprites.ContainsKey(__instance.sceneName))
{
GameObject val = new GameObject();
val.AddComponent<Image>().sprite = CLRPlugin.MapDisabledSprite;
((Object)val).name = "MapDisabled";
val.SetActive(false);
val.transform.SetParent(((Component)__instance).gameObject.transform);
val.transform.localPosition = new Vector3(-77.4f, 0f, 0f);
val.transform.localScale = new Vector3(1.1f, 0.6f, 0f);
CLRPlugin.MapDisabledSprites.TryAdd(__instance.sceneName, val);
}
}
}
}
internal static class StealSceneGOs
{
private static readonly string MapToStealFrom = "TheSamePlace_08";
private static readonly List<string> RequiredGOs = new List<string>(5) { "GameManager", "NetworkManager", "---USER INTERFACE---", "Main Camera", "EventSystem" };
internal static List<GameObject> SceneGOs = new List<GameObject>();
internal static void OnSceneLoad(Scene s, LoadSceneMode mode)
{
if (((Scene)(ref s)).name == "MainMenu")
{
SceneManager.LoadSceneAsync(MapToStealFrom, (LoadSceneMode)1);
}
else
{
if (!(((Scene)(ref s)).name == MapToStealFrom))
{
return;
}
CLRPlugin.Log.LogInfo((object)"This error isn't that important :)");
GameObject[] rootGameObjects = ((Scene)(ref s)).GetRootGameObjects();
foreach (GameObject val in rootGameObjects)
{
if (RequiredGOs.Contains(((Object)val).name))
{
val.SetActive(false);
GameObject val2 = Object.Instantiate<GameObject>(val);
Object.DontDestroyOnLoad((Object)(object)val2);
SceneGOs.Add(val2);
val.SetActive(true);
}
}
SceneManager.sceneLoaded -= OnSceneLoad;
SceneManager.UnloadSceneAsync(MapToStealFrom);
}
}
}
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("com.koki.lvlreborn", "Custom Levels Reborn", "1.1.5")]
public class CLRPlugin : BaseUnityPlugin
{
[Serializable]
public class ThunderstoreManifest
{
public string name;
public string version_number;
public string website_url;
public string description;
}
internal static ManualLogSource Log;
internal static List<string> MapVersions = new List<string>();
internal static Sprite MapDisabledSprite;
internal static Dictionary<string, string> SceneToBundleDir = new Dictionary<string, string>();
internal static Dictionary<string, Texture2D> MapThumbnails = new Dictionary<string, Texture2D>();
internal static Dictionary<string, GameObject> MapDisabledSprites = new Dictionary<string, GameObject>();
private Harmony _harmony = new Harmony("com.koki.lvlreborn");
private static string PluginDir;
private void Awake()
{
Log = ((BaseUnityPlugin)this).Logger;
((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
_harmony.PatchAll();
PluginDir = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
if (PluginDir == null)
{
PluginDir = Path.Combine(Paths.PluginPath, "DEVELOPMENT-BUILD-Custom Levels Reborn");
}
FindBundles();
((Component)this).gameObject.AddComponent<SyncMaps>();
SceneManager.sceneLoaded += StealSceneGOs.OnSceneLoad;
}
private void FindBundles()
{
MapDisabledSprite = AssetBundle.LoadFromFile(Path.Combine(PluginDir, "clr_shared")).LoadAsset<Sprite>("MapDisableOverlay");
foreach (string item in Directory.EnumerateDirectories(Paths.PluginPath))
{
string packageVersion = GetPackageVersion(item);
string text = Directory.GetDirectories(item, "CustomMaps", SearchOption.AllDirectories).FirstOrDefault();
if (!Utility.IsNullOrWhiteSpace(text))
{
LoadBundles(text, packageVersion);
}
}
((BaseUnityPlugin)this).Logger.LogInfo((object)("Loaded maps: " + string.Join(", ", MapVersions)));
}
private void LoadBundles(string dir, string packageVer)
{
foreach (string item in Directory.EnumerateFiles(dir, "*", SearchOption.AllDirectories))
{
AssetBundle val = AssetBundle.LoadFromFile(item);
if (val.isStreamedSceneAssetBundle)
{
foreach (string item2 in val.GetAllScenePaths().Select(Path.GetFileNameWithoutExtension))
{
SceneToBundleDir.Add(item2, item);
MapVersions.Add(item2 + "-v" + packageVer);
}
val.Unload(true);
}
else if (item.EndsWith("_resources"))
{
Texture2D[] array = val.LoadAllAssets<Texture2D>();
foreach (Texture2D val2 in array)
{
MapThumbnails.Add(((Object)val2).name, val2);
}
}
}
}
private string GetPackageVersion(string folder)
{
string path = Path.Combine(folder, "manifest.json");
try
{
ThunderstoreManifest thunderstoreManifest = JsonUtility.FromJson<ThunderstoreManifest>(File.ReadAllText(path));
if (thunderstoreManifest != null && !string.IsNullOrEmpty(thunderstoreManifest.version_number))
{
return thunderstoreManifest.version_number;
}
}
catch (Exception)
{
}
return "{NO_VERSION_FOUND}";
}
}
namespace CustomLevelsReborn
{
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "com.koki.lvlreborn";
public const string PLUGIN_NAME = "Custom Levels Reborn";
public const string PLUGIN_VERSION = "1.1.5";
}
}