Decompiled source of Prop Placer v1.0.2

PropMod.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Mirror;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("PropMod")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+bf80c8ca3708c9d5e6b58206d3a09d728788d2dd")]
[assembly: AssemblyProduct("PropMod")]
[assembly: AssemblyTitle("PropMod")]
[assembly: AssemblyVersion("1.0.0.0")]
public class CommandHandler
{
	[HarmonyPatch(typeof(ChatBehaviour), "Send_ChatMessage")]
	public class ChatBehaviour_Send_ChatMessage
	{
		public static bool Prefix(ChatBehaviour __instance, ref string _message)
		{
			PropMod instance = PropMod.Instance;
			if (_message == null || !_message.StartsWith("/"))
			{
				return true;
			}
			string[] array = _message.Split(' ');
			string text = array[0].ToLower();
			string[] array2 = ((array.Length > 1) ? array[1..] : new string[0]);
			string text2 = text;
			string text3 = text2;
			if (text3 == "/list_props")
			{
				PropMod.ListPropsInChat();
				return false;
			}
			return true;
		}
	}

	[HarmonyPatch(typeof(ChatBehaviour), "Rpc_RecieveChatMessage")]
	public static class ChatBehaviour_Rpc_RecieveChatMessage
	{
		public static bool Prefix(ref ChatBehaviour __instance, ref string message)
		{
			if (!NetworkServer.active)
			{
				return true;
			}
			PropMod instance = PropMod.Instance;
			if (!message.StartsWith("."))
			{
				return true;
			}
			Player component = ((Component)__instance).GetComponent<Player>();
			if ((Object)(object)component == (Object)null)
			{
				return true;
			}
			string[] array = message.Split(' ');
			string text = array[0].ToLower();
			string[] array2 = ((array.Length > 1) ? array[1..] : new string[0]);
			PropMod.propManagers.TryGetValue(component, out var value);
			if (value == null)
			{
				PropMod.Logger.LogError((object)("Player " + component._nickname + " doesn't have an associated prop manager!"));
				return true;
			}
			switch (text)
			{
			case ".place":
				if (array2.Length != 0)
				{
					string prefabName = array2[0].ToLower();
					value.TryPlaceAction(prefabName);
					return false;
				}
				return true;
			case ".undo":
				value.UndoProp();
				return false;
			case ".clear":
				value.ClearProps();
				return false;
			case ".clearall":
				value.ClearAllProps();
				return false;
			default:
				return true;
			}
		}
	}

	[HarmonyPatch(typeof(AtlyssNetworkManager), "OnServerDisconnect")]
	public static class AtlyssNetworkManager_OnServerDisconnect
	{
		public static void Prefix(ref NetworkConnectionToClient _conn)
		{
			List<HC_PeerListEntry> list = HostConsole._current?._peerListEntries;
			int connectionId = ((NetworkConnection)_conn).connectionId;
			Player val = null;
			if (list == null)
			{
				return;
			}
			for (int i = 0; i < list.Count; i++)
			{
				if (((ListDataEntry)list[i])._dataID == connectionId)
				{
					val = list[i]._peerPlayer;
					break;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			PropMod instance = PropMod.Instance;
			if (PropMod.propManagers.TryGetValue(val, out var value))
			{
				PlayerPropManager value2;
				if (instance.deletePropsOnDisconnect.Value)
				{
					value.ClearProps();
				}
				else if (PropMod.propManagers.TryGetValue(Player._mainPlayer, out value2))
				{
					value2.ClaimPropOwnership(value);
				}
				else
				{
					PropMod.Logger.LogWarning((object)"Couldn't transfer props to host! Falling back to removing orphaned props.");
					value.ClearProps();
				}
				PropMod.propManagers.Remove(val);
			}
		}
	}
}
public class PlayerPropManager
{
	public Player owner;

	public Stack<GameObject> placedProps = new Stack<GameObject>();

	public PlayerPropManager(Player player)
	{
		owner = player;
	}

	public void TryPlaceAction(string prefabName)
	{
		PropMod instance = PropMod.Instance;
		if (PropMod.propPrefabs.TryGetValue(prefabName, out var value))
		{
			if (owner._isHostPlayer || placedProps.Count < instance.maxPropNum.Value)
			{
				PlaceProp(value);
			}
		}
		else
		{
			PropMod.Logger.LogWarning((object)("Couldn't find prop named " + prefabName));
		}
	}

	public void PlaceProp(GameObject prefab)
	{
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: 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_0082: Unknown result type (might be due to invalid IL or missing references)
		//IL_0087: 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_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_009d: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		if (NetworkServer.active)
		{
			PropMod.Logger.LogInfo((object)("Placing " + ((Object)prefab).name + " from player " + owner._nickname));
			Vector3 val = ((Component)owner).transform.position + ((Component)owner).transform.forward * 5f + ((Component)owner).transform.up * -1f;
			Quaternion rotation = ((Component)owner).transform.rotation;
			GameObject val2 = Object.Instantiate<GameObject>(prefab, val, rotation);
			SceneManager.MoveGameObjectToScene(val2, owner._playerMapInstance._loadedScene);
			val2.SetActive(true);
			NetworkServer.Spawn(val2, (NetworkConnection)null);
			placedProps.Push(val2);
		}
	}

	public void UndoProp()
	{
		if (NetworkServer.active && placedProps.TryPop(out var result))
		{
			NetworkServer.Destroy(result);
		}
	}

	public void ClearProps()
	{
		while (placedProps.Count > 0)
		{
			UndoProp();
		}
	}

	public void ClearAllProps()
	{
		if (!owner._isHostPlayer)
		{
			return;
		}
		foreach (PlayerPropManager value in PropMod.propManagers.Values)
		{
			value.ClearProps();
		}
	}

	public void ClaimPropOwnership(PlayerPropManager otherManager)
	{
		if (otherManager != null && otherManager != this)
		{
			GameObject result;
			while (otherManager.placedProps.TryPop(out result))
			{
				placedProps.Push(result);
			}
		}
	}
}
[BepInPlugin("firenoobsta.propplacer", "Prop Placer", "1.0.2")]
public class PropMod : BaseUnityPlugin
{
	[HarmonyPatch(typeof(MainMenuManager), "Start")]
	public class RegisterProps
	{
		[HarmonyPostfix]
		private static void Postfix(MainMenuManager __instance)
		{
			Logger.LogInfo((object)"Registering props ...");
			foreach (GameObject value in propPrefabs.Values)
			{
				NetworkIdentity component = value.GetComponent<NetworkIdentity>();
				if ((Object)(object)component == (Object)null)
				{
					Logger.LogError((object)("Couldn't register prop " + ((Object)value).name + " because it has no Network Identity component"));
					continue;
				}
				if (component.assetId != 0)
				{
					NetworkClient.RegisterPrefab(value);
					continue;
				}
				MD5 mD = MD5.Create();
				byte[] b = mD.ComputeHash(Encoding.UTF8.GetBytes(((Object)value).name));
				Guid guid = new Guid(b);
				uint num = NetworkIdentity.AssetGuidToUint(guid);
				try
				{
					NetworkClient.RegisterPrefab(value, num);
				}
				catch (Exception ex)
				{
					Logger.LogError((object)("Error trying to register " + ((Object)value).name + "!"));
					Logger.LogError((object)ex.Message);
				}
			}
		}
	}

	[HarmonyPatch(typeof(Player), "Awake")]
	public static class CreatePropManager
	{
		public static void Postfix(Player __instance)
		{
			if (NetworkServer.active)
			{
				propManagers.Add(__instance, new PlayerPropManager(__instance));
			}
		}
	}

	internal static ManualLogSource Logger;

	public static string AssetFolderPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

	public static string PluginFolderPath = Paths.PluginPath;

	public static Dictionary<string, GameObject> propPrefabs = new Dictionary<string, GameObject>();

	public static Dictionary<Player, PlayerPropManager> propManagers = new Dictionary<Player, PlayerPropManager>();

	public static PropMod Instance { get; private set; }

	public static List<AssetBundle> PropBundles { get; private set; }

	public ConfigEntry<bool> deletePropsOnDisconnect { get; private set; }

	public ConfigEntry<int> maxPropNum { get; private set; }

	private void Awake()
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Expected O, but got Unknown
		Logger = ((BaseUnityPlugin)this).Logger;
		Harmony val = new Harmony("firenoobsta.propplacer");
		val.PatchAll();
		Instance = this;
		PropBundles = new List<AssetBundle>();
		deletePropsOnDisconnect = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DeleteOnDisconnect", true, "Choose whether to delete all props a specific player placed when they leave the server. If set to false, abandoned props will transfer ownership to host.");
		maxPropNum = ((BaseUnityPlugin)this).Config.Bind<int>("General", "MaxPropNum", 5, "Maximum number of props clients in your server can place (per player). Hosts can place unlimited amounts. Setting to 0 means only the host can place props.");
	}

	private void Start()
	{
		Logger.LogInfo((object)"Prop Placer Loaded!");
		Logger.LogInfo((object)"Version 1.0.2");
		if (Directory.Exists(PluginFolderPath))
		{
			CheckDirectory(PluginFolderPath);
		}
		Logger.LogInfo((object)"List of loaded Props: ");
		foreach (string key in propPrefabs.Keys)
		{
			Logger.LogInfo((object)(key ?? ""));
		}
	}

	public static void CheckDirectory(string dirPath)
	{
		string[] files = Directory.GetFiles(dirPath);
		string[] array = files;
		foreach (string filePath in array)
		{
			CheckFile(filePath);
		}
		string[] directories = Directory.GetDirectories(dirPath);
		string[] array2 = directories;
		foreach (string dirPath2 in array2)
		{
			CheckDirectory(dirPath2);
		}
	}

	public static void CheckFile(string filePath)
	{
		if (!filePath.EndsWith(".propbundle"))
		{
			return;
		}
		Logger.LogInfo((object)("Loading prop asset bundle: " + Path.GetFileName(filePath)));
		AssetBundle val = AssetBundle.LoadFromFile(filePath);
		if ((Object)(object)val == (Object)null)
		{
			Logger.LogError((object)("Failed to load asset bundle: " + Path.GetFileName(filePath)));
			return;
		}
		GameObject[] array = val.LoadAllAssets<GameObject>();
		foreach (GameObject val2 in array)
		{
			FixPrefabAudioSources(val2);
			if (!propPrefabs.TryAdd(((Object)val2).name.ToLower(), val2))
			{
				Logger.LogError((object)("Failed to add " + ((Object)val2).name + " to list of props"));
			}
		}
		PropBundles.Add(val);
		Logger.LogInfo((object)"Successfully loaded bundle!");
	}

	public static void FixPrefabAudioSources(GameObject prefab)
	{
		AudioMixer val = Resources.Load<AudioMixer>("_sound/_mixer/_mixerMain");
		if ((Object)(object)val == (Object)null)
		{
			Logger.LogWarning((object)"Couldn't load main mixer from resources!");
			return;
		}
		AudioSource[] componentsInChildren = prefab.GetComponentsInChildren<AudioSource>();
		foreach (AudioSource val2 in componentsInChildren)
		{
			if ((Object)(object)val2.outputAudioMixerGroup != (Object)null)
			{
				val2.outputAudioMixerGroup = val.FindMatchingGroups(((Object)val2.outputAudioMixerGroup).name)[0];
			}
		}
	}

	public static void ListPropsInChat()
	{
		ChatBehaviour chatBehaviour = Player._mainPlayer._chatBehaviour;
		if ((Object)(object)chatBehaviour == (Object)null)
		{
			Logger.LogError((object)"Couldn't get main player's chat behavior component");
			return;
		}
		chatBehaviour.New_ChatMessage("Available props:");
		foreach (string key in propPrefabs.Keys)
		{
			chatBehaviour.New_ChatMessage(key);
		}
	}
}