Skip to content

Instantly share code, notes, and snippets.

@acidumirae
Created December 6, 2024 05:30
Show Gist options
  • Save acidumirae/4e99463fa5ae8bd50dc02d4e8e439239 to your computer and use it in GitHub Desktop.
Save acidumirae/4e99463fa5ae8bd50dc02d4e8e439239 to your computer and use it in GitHub Desktop.
Fix the type 'System.Text.StringBuilder' cannot be used as type parameter 'T' in the generic type or method 'Pool.Free<T>(ref T)'.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Facepunch;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Plugins;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Auto Doors", "Wulf/lukespragg/Arainrr/James/Bushhy", "3.3.10", ResourceId = 1924)]
[Description("Automatically closes doors behind players after X seconds")]
public class AutoDoors : RustPlugin
{
#region Fields
[PluginReference] private Plugin RustTranslationAPI;
private const string PERMISSION_USE = "autodoors.use";
private readonly Hash<ulong, Timer> doorTimers = new Hash<ulong, Timer>();
private readonly Dictionary<string, string> supportedDoors = new Dictionary<string, string>();
private HashSet<DoorManipulator> doorManipulators;
#endregion Fields
#region Oxide Hooks
private void Init()
{
LoadData();
Unsubscribe(nameof(OnEntitySpawned));
permission.RegisterPermission(PERMISSION_USE, this);
if (configData.chatS.commands.Length == 0)
{
configData.chatS.commands = new[] { "ad" };
}
foreach (var command in configData.chatS.commands)
{
cmd.AddChatCommand(command, this, nameof(CmdAutoDoor));
}
}
private void OnServerInitialized()
{
UpdateConfig();
if (configData.globalS.excludeDoorController)
{
doorManipulators = new HashSet<DoorManipulator>();
Subscribe(nameof(OnEntitySpawned));
foreach (var doorManipulator in BaseNetworkable.serverEntities.OfType<DoorManipulator>())
{
OnEntitySpawned(doorManipulator);
}
}
}
private void OnEntitySpawned(DoorManipulator doorManipulator)
{
if (doorManipulator == null || doorManipulator.OwnerID == 0) return;
doorManipulators.Add(doorManipulator);
}
private void OnEntityKill(DoorManipulator doorManipulator)
{
if (doorManipulator == null || doorManipulators == null) return;
doorManipulators.RemoveWhere(x => x == doorManipulator);
}
private void OnEntityKill(Door door)
{
if (door == null || door.net == null) return;
var doorID = door.net.ID.Value;
Timer value;
if (doorTimers.TryGetValue(doorID, out value))
{
value?.Destroy();
doorTimers.Remove(doorID);
}
foreach (var playerData in storedData.playerData.Values)
{
playerData.theDoorS.Remove(doorID);
}
}
private void OnServerSave() => timer.Once(UnityEngine.Random.Range(0f, 60f), SaveData);
private void Unload()
{
foreach (var value in doorTimers.Values)
{
value?.Destroy();
}
SaveData();
}
private void OnDoorOpened(Door door, BasePlayer player)
{
if (door == null || door.net == null || !door.IsOpen()) return;
if (!supportedDoors.ContainsKey(door.ShortPrefabName)) return;
if (!configData.globalS.useUnownedDoor && door.OwnerID == 0) return;
if (configData.globalS.excludeDoorController && HasDoorController(door)) return;
if (configData.usePermission && !permission.UserHasPermission(player.UserIDString, PERMISSION_USE)) return;
var playerData = GetPlayerData(player.userID, true);
if (!playerData.doorData.enabled) return;
float autoCloseTime;
var doorID = door.net.ID.Value;
StoredData.DoorData doorData;
if (playerData.theDoorS.TryGetValue(doorID, out doorData))
{
if (!doorData.enabled) return;
autoCloseTime = doorData.time;
}
else if (playerData.doorTypeS.TryGetValue(door.ShortPrefabName, out doorData))
{
if (!doorData.enabled) return;
autoCloseTime = doorData.time;
}
else autoCloseTime = playerData.doorData.time;
if (autoCloseTime <= 0) return;
if (Interface.CallHook("OnDoorAutoClose", player, door) != null) return;
Timer value;
if (doorTimers.TryGetValue(doorID, out value))
{
value?.Destroy();
}
doorTimers[doorID] = timer.Once(autoCloseTime, () =>
{
doorTimers.Remove(doorID);
if (door == null || !door.IsOpen()) return;
if (configData.globalS.cancelOnKill && player != null && player.IsDead()) return;
door.SetFlag(BaseEntity.Flags.Open, false);
door.SendNetworkUpdateImmediate();
});
}
private void OnDoorClosed(Door door, BasePlayer player)
{
if (door == null || door.net == null || door.IsOpen()) return;
Timer value;
if (doorTimers.TryGetValue(door.net.ID.Value, out value))
{
value?.Destroy();
doorTimers.Remove(door.net.ID.Value);
}
}
#endregion Oxide Hooks
#region Methods
private bool HasDoorController(Door door)
{
foreach (var doorManipulator in doorManipulators)
{
if (doorManipulator != null && doorManipulator.targetDoor == door)
{
return true;
}
}
return false;
}
private StoredData.PlayerData GetPlayerData(ulong playerID, bool readOnly = false)
{
StoredData.PlayerData playerData;
if (!storedData.playerData.TryGetValue(playerID, out playerData))
{
playerData = new StoredData.PlayerData
{
doorData = new StoredData.DoorData
{
enabled = configData.globalS.defaultEnabled,
time = configData.globalS.defaultDelay,
}
};
if (readOnly)
{
return playerData;
}
storedData.playerData.Add(playerID, playerData);
}
return playerData;
}
private static Door GetLookingAtDoor(BasePlayer player)
{
RaycastHit rHit;
if (Physics.Raycast(player.eyes.HeadRay(), out rHit, 10f, Rust.Layers.Mask.Construction))
{
return rHit.GetEntity() as Door;
}
return null;
}
private void UpdateConfig()
{
foreach (var itemDefinition in ItemManager.GetItemDefinitions())
{
var itemModDeployable = itemDefinition.GetComponent<ItemModDeployable>();
if (itemModDeployable == null) continue;
var door = GameManager.server.FindPrefab(itemModDeployable.entityPrefab.resourcePath)?.GetComponent<Door>();
if (door == null || string.IsNullOrEmpty(door.ShortPrefabName)) continue;
ConfigData.DoorSettings doorSettings;
if (!configData.doorS.TryGetValue(itemDefinition.shortname, out doorSettings))
{
doorSettings = new ConfigData.DoorSettings
{
enabled = true,
displayName = itemDefinition.displayName.english
};
configData.doorS.Add(itemDefinition.shortname, doorSettings);
}
if (doorSettings.enabled && !supportedDoors.ContainsKey(door.ShortPrefabName))
{
supportedDoors.Add(door.ShortPrefabName, doorSettings.displayName);
}
}
SaveConfig();
}
#region RustTranslationAPI
private string GetDeployableTranslation(string language, string deployable) => (string)RustTranslationAPI.Call("GetDeployableTranslation", language, deployable);
private string GetDeployableDisplayName(BasePlayer player, string deployable, string displayName)
{
if (RustTranslationAPI != null)
{
displayName = GetDeployableTranslation(lang.GetLanguage(player.UserIDString), deployable);
if (!string.IsNullOrEmpty(displayName))
{
return displayName;
}
}
return displayName;
}
#endregion RustTranslationAPI
#endregion Methods
#region ChatCommand
private void CmdAutoDoor(BasePlayer player, string command, string[] args)
{
if (configData.usePermission && !permission.UserHasPermission(player.UserIDString, PERMISSION_USE))
{
Print(player, Lang("NotAllowed", player.UserIDString));
return;
}
var playerData = GetPlayerData(player.userID);
if (args == null || args.Length == 0)
{
playerData.doorData.enabled = !playerData.doorData.enabled;
Print(player, Lang("AutoDoor", player.UserIDString, playerData.doorData.enabled ? Lang("Enabled", player.UserIDString) : Lang("Disabled", player.UserIDString)));
return;
}
float time;
if (float.TryParse(args[0], out time))
{
if (time <= configData.globalS.maximumDelay && time >= configData.globalS.minimumDelay)
{
playerData.doorData.time = time;
if (!playerData.doorData.enabled) playerData.doorData.enabled = true;
Print(player, Lang("AutoDoorDelay", player.UserIDString, time));
return;
}
Print(player, Lang("AutoDoorDelayLimit", player.UserIDString, configData.globalS.minimumDelay, configData.globalS.maximumDelay));
return;
}
switch (args[0].ToLower())
{
case "a":
case "all":
{
if (args.Length > 1)
{
if (float.TryParse(args[1], out time))
{
if (time <= configData.globalS.maximumDelay && time >= configData.globalS.minimumDelay)
{
playerData.doorData.time = time;
playerData.doorTypeS.Clear();
playerData.theDoorS.Clear();
Print(player, Lang("AutoDoorDelayAll", player.UserIDString, time));
return;
}
Print(player,
Lang("AutoDoorDelayLimit", player.UserIDString, configData.globalS.minimumDelay,
configData.globalS.maximumDelay));
return;
}
}
break;
}
case "s":
case "single":
{
var door = GetLookingAtDoor(player);
if (door == null || door.net == null)
{
Print(player, Lang("DoorNotFound", player.UserIDString));
return;
}
string doorDisplayName;
if (!supportedDoors.TryGetValue(door.ShortPrefabName, out doorDisplayName))
{
Print(player, Lang("DoorNotSupported", player.UserIDString));
return;
}
StoredData.DoorData doorData;
if (!playerData.theDoorS.TryGetValue(door.net.ID.Value, out doorData))
{
doorData = new StoredData.DoorData
{ enabled = true, time = configData.globalS.defaultDelay };
playerData.theDoorS.Add(door.net.ID.Value, doorData);
}
if (args.Length <= 1)
{
doorData.enabled = !doorData.enabled;
Print(player,
Lang("AutoDoorSingle", player.UserIDString,
GetDeployableDisplayName(player, door.ShortPrefabName, doorDisplayName),
doorData.enabled
? Lang("Enabled", player.UserIDString)
: Lang("Disabled", player.UserIDString)));
return;
}
if (float.TryParse(args[1], out time))
{
if (time <= configData.globalS.maximumDelay && time >= configData.globalS.minimumDelay)
{
doorData.time = time;
Print(player, Lang("AutoDoorSingleDelay", player.UserIDString,
GetDeployableDisplayName(player, door.ShortPrefabName, doorDisplayName), time));
return;
}
Print(player,
Lang("AutoDoorDelayLimit", player.UserIDString, configData.globalS.minimumDelay,
configData.globalS.maximumDelay));
return;
}
break;
}
case "t":
case "type":
{
var door = GetLookingAtDoor(player);
if (door == null || door.net == null)
{
Print(player, Lang("DoorNotFound", player.UserIDString));
return;
}
string doorDisplayName;
if (!supportedDoors.TryGetValue(door.ShortPrefabName, out doorDisplayName))
{
Print(player, Lang("DoorNotSupported", player.UserIDString));
return;
}
StoredData.DoorData doorData;
if (!playerData.doorTypeS.TryGetValue(door.ShortPrefabName, out doorData))
{
doorData = new StoredData.DoorData
{ enabled = true, time = configData.globalS.defaultDelay };
playerData.doorTypeS.Add(door.ShortPrefabName, doorData);
}
if (args.Length <= 1)
{
doorData.enabled = !doorData.enabled;
Print(player,
Lang("AutoDoorType", player.UserIDString, GetDeployableDisplayName(player, door.ShortPrefabName, doorDisplayName),
doorData.enabled
? Lang("Enabled", player.UserIDString)
: Lang("Disabled", player.UserIDString)));
return;
}
if (float.TryParse(args[1], out time))
{
if (time <= configData.globalS.maximumDelay && time >= configData.globalS.minimumDelay)
{
doorData.time = time;
Print(player, Lang("AutoDoorTypeDelay", player.UserIDString,
GetDeployableDisplayName(player, door.ShortPrefabName, doorDisplayName), time));
return;
}
Print(player,
Lang("AutoDoorDelayLimit", player.UserIDString, configData.globalS.minimumDelay,
configData.globalS.maximumDelay));
return;
}
break;
}
case "h":
case "help":
{
StringBuilder stringBuilder = Pool.Get<StringBuilder>();
stringBuilder.AppendLine();
var firstCmd = configData.chatS.commands[0];
stringBuilder.AppendLine(Lang("AutoDoorSyntax", player.UserIDString, firstCmd));
stringBuilder.AppendLine(Lang("AutoDoorSyntax1", player.UserIDString, firstCmd,
configData.globalS.minimumDelay, configData.globalS.maximumDelay));
stringBuilder.AppendLine(Lang("AutoDoorSyntax2", player.UserIDString, firstCmd));
stringBuilder.AppendLine(Lang("AutoDoorSyntax3", player.UserIDString, firstCmd,
configData.globalS.minimumDelay, configData.globalS.maximumDelay));
stringBuilder.AppendLine(Lang("AutoDoorSyntax4", player.UserIDString, firstCmd));
stringBuilder.AppendLine(Lang("AutoDoorSyntax5", player.UserIDString, firstCmd,
configData.globalS.minimumDelay, configData.globalS.maximumDelay));
stringBuilder.AppendLine(Lang("AutoDoorSyntax6", player.UserIDString, firstCmd,
configData.globalS.minimumDelay, configData.globalS.maximumDelay));
Print(player, stringBuilder.ToString());
stringBuilder.Clear();
//Pool.Free(ref stringBuilder);
Pool.FreeUnmanaged(ref stringBuilder);
return;
}
}
Print(player, Lang("SyntaxError", player.UserIDString, configData.chatS.commands[0]));
}
#endregion ChatCommand
#region ConfigurationFile
private ConfigData configData;
private class ConfigData
{
[JsonProperty(PropertyName = "Use permissions")]
public bool usePermission = false;
[JsonProperty(PropertyName = "Clear data on map wipe")]
public bool clearDataOnWipe = false;
[JsonProperty(PropertyName = "Global settings")]
public GlobalSettings globalS = new GlobalSettings();
[JsonProperty(PropertyName = "Chat settings")]
public ChatSettings chatS = new ChatSettings();
[JsonProperty(PropertyName = "Door Settings")]
public Dictionary<string, DoorSettings> doorS = new Dictionary<string, DoorSettings>();
public class DoorSettings
{
public bool enabled;
public string displayName;
}
public class GlobalSettings
{
[JsonProperty(PropertyName = "Allows automatic closing of unowned doors")]
public bool useUnownedDoor = false;
[JsonProperty(PropertyName = "Exclude door controller")]
public bool excludeDoorController = true;
[JsonProperty(PropertyName = "Cancel on player dead")]
public bool cancelOnKill = false;
[JsonProperty(PropertyName = "Default enabled")]
public bool defaultEnabled = true;
[JsonProperty(PropertyName = "Default delay")]
public float defaultDelay = 5f;
[JsonProperty(PropertyName = "Maximum delay")]
public float maximumDelay = 10f;
[JsonProperty(PropertyName = "Minimum delay")]
public float minimumDelay = 5f;
}
public class ChatSettings
{
[JsonProperty(PropertyName = "Chat command")]
public string[] commands = { "ad", "autodoor" };
[JsonProperty(PropertyName = "Chat prefix")]
public string prefix = "<color=#00FFFF>[AutoDoors]</color>: ";
[JsonProperty(PropertyName = "Chat steamID icon")]
public ulong steamIDIcon = 0;
}
[JsonProperty(PropertyName = "Version")]
public VersionNumber version;
}
protected override void LoadConfig()
{
base.LoadConfig();
try
{
configData = Config.ReadObject<ConfigData>();
if (configData == null)
{
LoadDefaultConfig();
}
else
{
UpdateConfigValues();
}
}
catch (Exception ex)
{
PrintError($"The configuration file is corrupted. \n{ex}");
LoadDefaultConfig();
}
SaveConfig();
}
protected override void LoadDefaultConfig()
{
PrintWarning("Creating a new configuration file");
configData = new ConfigData();
configData.version = Version;
}
protected override void SaveConfig() => Config.WriteObject(configData);
private void UpdateConfigValues()
{
if (configData.version < Version)
{
if (configData.version <= default(VersionNumber))
{
string prefix, prefixColor;
if (GetConfigValue(out prefix, "Chat Settings", "Chat Prefix") && GetConfigValue(out prefixColor, "Chat Settings", "Chat Prefix Color"))
{
configData.chatS.prefix = $"<color={prefixColor}>{prefix}</color>: ";
}
}
configData.version = Version;
}
}
private bool GetConfigValue<T>(out T value, params string[] path)
{
var configValue = Config.Get(path);
if (configValue == null)
{
value = default(T);
return false;
}
value = Config.ConvertValue<T>(configValue);
return true;
}
#endregion ConfigurationFile
#region DataFile
private StoredData storedData;
private class StoredData
{
public readonly Dictionary<ulong, PlayerData> playerData = new Dictionary<ulong, PlayerData>();
public class PlayerData
{
public DoorData doorData = new DoorData();
public readonly Dictionary<ulong, DoorData> theDoorS = new Dictionary<ulong, DoorData>();
public readonly Dictionary<string, DoorData> doorTypeS = new Dictionary<string, DoorData>();
}
public class DoorData
{
public bool enabled;
public float time;
}
}
private void LoadData()
{
try
{
storedData = Interface.Oxide.DataFileSystem.ReadObject<StoredData>(Name);
}
catch
{
storedData = null;
}
finally
{
if (storedData == null)
{
ClearData();
}
}
}
private void SaveData() => Interface.Oxide.DataFileSystem.WriteObject(Name, storedData);
private void ClearData()
{
storedData = new StoredData();
SaveData();
}
private void OnNewSave(string filename)
{
if (configData.clearDataOnWipe)
{
ClearData();
}
else
{
foreach (var value in storedData.playerData.Values)
{
value.theDoorS.Clear();
}
SaveData();
}
}
#endregion DataFile
#region LanguageFile
private void Print(BasePlayer player, string message)
{
Player.Message(player, message, configData.chatS.prefix, configData.chatS.steamIDIcon);
}
private string Lang(string key, string id = null, params object[] args) => string.Format(lang.GetMessage(key, this, id), args);
protected override void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary<string, string>
{
["NotAllowed"] = "You do not have permission to use this command",
["Enabled"] = "<color=#8ee700>Enabled</color>",
["Disabled"] = "<color=#ce422b>Disabled</color>",
["AutoDoor"] = "Automatic door closing is now {0}",
["AutoDoorDelay"] = "Automatic door closing delay set to {0}s. (Doors set by 'single' and 'type' are not included)",
["AutoDoorDelayAll"] = "Automatic closing delay of all doors set to {0}s",
["DoorNotFound"] = "You need to look at a door",
["DoorNotSupported"] = "This type of door is not supported",
["AutoDoorDelayLimit"] = "Automatic door closing delay allowed is between {0}s and {1}s",
["AutoDoorSingle"] = "Automatic closing of this <color=#4DFF4D>{0}</color> is {1}",
["AutoDoorSingleDelay"] = "Automatic closing delay of this <color=#4DFF4D>{0}</color> is {1}s",
["AutoDoorType"] = "Automatic closing of <color=#4DFF4D>{0}</color> door is {1}",
["AutoDoorTypeDelay"] = "Automatic closing delay of <color=#4DFF4D>{0}</color> door is {1}s",
["SyntaxError"] = "Syntax error, type '<color=#ce422b>/{0} <help | h></color>' to view help",
["AutoDoorSyntax"] = "<color=#ce422b>/{0} </color> - Enable/Disable automatic door closing",
["AutoDoorSyntax1"] = "<color=#ce422b>/{0} [time (seconds)]</color> - Set automatic closing delay for doors, the allowed time is between {1}s and {2}s. (Doors set by 'single' and 'type' are not included)",
["AutoDoorSyntax2"] = "<color=#ce422b>/{0} <single | s></color> - Enable/Disable automatic closing of the door you are looking at",
["AutoDoorSyntax3"] = "<color=#ce422b>/{0} <single | s> [time (seconds)]</color> - Set automatic closing delay for the door you are looking at, the allowed time is between {1}s and {2}s",
["AutoDoorSyntax4"] = "<color=#ce422b>/{0} <type | t></color> - Enable/disable automatic door closing for the type of door you are looking at. ('type' is just a word, not the type of door)",
["AutoDoorSyntax5"] = "<color=#ce422b>/{0} <type | t> [time (seconds)]</color> - Set automatic closing delay for the type of door you are looking at, the allowed time is between {1}s and {2}s. ('type' is just a word, not the type of door)",
["AutoDoorSyntax6"] = "<color=#ce422b>/{0} <all | a> [time (seconds)]</color> - Set automatic closing delay for all doors, the allowed time is between {1}s and {2}s.",
}, this);
lang.RegisterMessages(new Dictionary<string, string>
{
["NotAllowed"] = "您没有权限使用该命令",
["Enabled"] = "<color=#8ee700>已启用</color>",
["Disabled"] = "<color=#ce422b>已禁用</color>",
["AutoDoor"] = "自动关门现在的状态为 {0}",
["AutoDoorDelay"] = "自动关门延迟设置为 {0}秒",
["AutoDoorDelayAll"] = "全部门的自动关闭延迟设置为 {0}秒",
["DoorNotFound"] = "请您看着一条门再输入指令",
["DoorNotSupported"] = "不支持您看着的这种门",
["AutoDoorDelayLimit"] = "自动关门延迟应该在 {0}秒 和 {1}秒 之间",
["AutoDoorSingle"] = "这条 <color=#4DFF4D>{0}</color> 的自动关闭状态为 {1}",
["AutoDoorSingleDelay"] = "这条 <color=#4DFF4D>{0}</color> 的自动关闭延迟为 {1}秒",
["AutoDoorType"] = "这种 <color=#4DFF4D>{0}</color> 的自动关闭状态为 {1}",
["AutoDoorTypeDelay"] = "这种 <color=#4DFF4D>{0}</color> 的自动关闭延迟为 {1}秒",
["SyntaxError"] = "语法错误, 输入 '<color=#ce422b>/{0} <help | h></color>' 查看帮助",
["AutoDoorSyntax"] = "<color=#ce422b>/{0} </color> - 启用/禁用自动关门",
["AutoDoorSyntax1"] = "<color=#ce422b>/{0} [时间 (秒)]</color> - 设置自动关门延迟。(时间在 {1}秒 和 {2}秒 之间) (不包括'single'和'type'设置的门)",
["AutoDoorSyntax2"] = "<color=#ce422b>/{0} <single | s></color> - 为您看着的这条门,启用/禁用自动关门",
["AutoDoorSyntax3"] = "<color=#ce422b>/{0} <single | s> [时间 (秒)]</color> - 为您看着的这条门设置自动关闭延迟。(时间在 {1}秒 和 {2}秒 之间)",
["AutoDoorSyntax4"] = "<color=#ce422b>/{0} <type | t></color> - 为您看着的这种门,启用/禁用自动关门",
["AutoDoorSyntax5"] = "<color=#ce422b>/{0} <type | t> [时间 (秒)]</color> - 为您看着的这种门设置自动关闭延迟。(时间在 {1}秒 和 {2}秒 之间)",
["AutoDoorSyntax6"] = "<color=#ce422b>/{0} <all | a> [时间 (秒)]</color> - 为所有门设置自动关闭延迟。(时间在 {1}秒 和 {2}秒 之间)",
}, this, "zh-CN");
}
#endregion LanguageFile
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment