using Oxide.Core; using Oxide.Core.Plugins; using System; using System.Collections.Generic; using System.Linq; namespace Oxide.Plugins { /* * This Version Changes: * - Fixed compiling issues in update */ [Info("ADR Watch", "Pho3niX90", "1.0.2")] [Description("Records a demo when banned players TC's and codelocks are accessed")] internal class ADRWatch : RustPlugin { [PluginReference] Plugin AutoDemoRecord, Clans; Dictionary _banWatchList = new Dictionary(); int lastSavedCount = 0; private ADRWatchConfig config; #region Helpers List GetTeamMembers(ulong userid) => RelationshipManager.ServerInstance.FindPlayersTeam(userid)?.members; bool IsMemberOrAlly(ulong userid1, ulong userid2) { if (userid1.Equals(userid2)) return true; var isClan = Clans != null && Clans.IsLoaded ? Clans.Call("IsMemberOrAlly", userid1.ToString(), userid2.ToString()) : false; var teamMembers = GetTeamMembers(userid1); var isTeam = teamMembers != null ? teamMembers.Contains(userid2) : false; return isClan || isTeam; } void CheckHooks() { if (config.monitorEvent_OnCodeEntered) Subscribe(nameof(OnCodeEntered)); else Unsubscribe(nameof(OnCodeEntered)); if (config.monitorEvent_OnCupboardAuthorize) Subscribe(nameof(OnCupboardAuthorize)); else Unsubscribe(nameof(OnCupboardAuthorize)); if (config.monitorEvent_OnCupboardClearList) Subscribe(nameof(OnCupboardClearList)); else Unsubscribe(nameof(OnCupboardClearList)); if (config.monitorEvent_OnCupboardDeauthorize) Subscribe(nameof(OnCupboardDeauthorize)); else Unsubscribe(nameof(OnCupboardDeauthorize)); } bool IsWatched(ulong userId, ulong suspectedUserId) { if (config.ignoreTeamMembers && IsMemberOrAlly(userId, suspectedUserId)) { return false; } return _banWatchList.ContainsKey(userId); } void Record(BasePlayer player, string msg) { AutoDemoRecord?.Call("API_StartRecording", player, msg, config.recordMinutes); } #endregion #region Hooks void Loaded() { LoadData(); CheckHooks(); } void Unload() => SaveData(); void OnServerSave() => SaveData(); void OnPlayerBanned(string name, ulong id, string address, string reason) { _banWatchList.TryAdd(id, DateTime.Now); } void OnUserBanned(string name, string id, string ipAddress, string reason) { _banWatchList.TryAdd(ulong.Parse(id), DateTime.Now); } void OnUserUnbanned(string name, string id, string ipAddress) { ulong userId = ulong.Parse(id); if (_banWatchList.ContainsKey(userId)) { _banWatchList.Remove(ulong.Parse(id)); } } object OnCodeEntered(CodeLock codeLock, BasePlayer player, string code) { if (IsWatched(codeLock.OwnerID, player.userID)) { Record(player, string.Format(GetMsg("Watched Events - Code Entered - Owned"), code, codeLock.OwnerID, codeLock.name)); } else { foreach (var userId in codeLock.whitelistPlayers) { if (IsWatched(userId, player.userID)) { Record(player, string.Format(GetMsg("Watched Events - Code Entered - Whitelist"), code, codeLock.OwnerID, codeLock.name)); break; } } foreach (var userId in codeLock.guestPlayers) { if (IsWatched(userId, player.userID)) { Record(player, string.Format(GetMsg("Watched Events - Code Entered - Guest"), code, codeLock.OwnerID, codeLock.name)); break; } } } return null; } void OnCupboardAuthorize(BuildingPrivlidge privilege, BasePlayer player) { if (IsWatched(privilege.OwnerID, player.userID)) { Record(player, string.Format(GetMsg("Watched Events - Cupboard Authorize - Owned"), privilege.OwnerID)); } else { foreach (var userProto in privilege.authorizedPlayers) { if (IsWatched(userProto.userid, player.userID)) { // trigger recording, he is authed on it. Record(player, string.Format(GetMsg("Watched Events - Cupboard Authorize - Authed"), privilege.OwnerID)); break; } } } } void OnCupboardClearList(BuildingPrivlidge privilege, BasePlayer player) { if (IsWatched(privilege.OwnerID, player.userID)) { Record(player, string.Format(GetMsg("Watched Events - Cupboard Clearlist - Owned"), privilege.OwnerID)); } else { foreach (var userProto in privilege.authorizedPlayers) { if (IsWatched(userProto.userid, player.userID)) { Record(player, string.Format(GetMsg("Watched Events - Cupboard Clearlist - Authed"), privilege.OwnerID)); break; } } } } void OnCupboardDeauthorize(BuildingPrivlidge privilege, BasePlayer player) { if (IsWatched(privilege.OwnerID, player.userID)) { Record(player, string.Format(GetMsg("Watched Events - Cupboard Deauthorize - Owned"), privilege.OwnerID)); } else { foreach (var userProto in privilege.authorizedPlayers) { if (IsWatched(userProto.userid, player.userID)) { Record(player, string.Format(GetMsg("Watched Events - Cupboard Deauthorize - Authed"), privilege.OwnerID)); break; } } } } #endregion #region Configuration private class ADRWatchConfig { // Config default vars public int monitorHours = 24; public int recordMinutes = 10; public bool ignoreTeamMembers = true; public bool monitorEvent_OnCodeEntered = true; public bool monitorEvent_OnCupboardAuthorize = true; public bool monitorEvent_OnCupboardClearList = true; public bool monitorEvent_OnCupboardDeauthorize = true; // Plugin reference private ADRWatch plugin; public ADRWatchConfig(ADRWatch plugin) { this.plugin = plugin; /** * Load all saved config values * */ GetConfig(ref monitorHours, "General", "Monitor banned for X hours"); GetConfig(ref recordMinutes, "General", "Record for X minutes"); GetConfig(ref ignoreTeamMembers, "General", "Ignore team mates"); GetConfig(ref monitorEvent_OnCodeEntered, "Watched Events", "Code Entered"); GetConfig(ref monitorEvent_OnCupboardAuthorize, "Watched Events", "Cupboard Authorize"); GetConfig(ref monitorEvent_OnCupboardDeauthorize, "Watched Events", "Cupboard Deauthorize"); GetConfig(ref monitorEvent_OnCupboardClearList, "Watched Events", "Cupboard ClearList"); plugin.SaveConfig(); } private void GetConfig(ref T variable, params string[] path) { if (path.Length == 0) return; if (plugin.Config.Get(path) == null) { SetConfig(ref variable, path); plugin.PrintWarning($"Added new field to config: {string.Join("/", path)}"); } variable = (T)Convert.ChangeType(plugin.Config.Get(path), typeof(T)); } private void SetConfig(ref T variable, params string[] path) => plugin.Config.Set(path.Concat(new object[] { variable }).ToArray()); } string GetMsg(string key) => lang.GetMessage(key, this); protected override void LoadConfig() { base.LoadConfig(); config = new ADRWatchConfig(this); } protected override void LoadDefaultMessages() { lang.RegisterMessages(new Dictionary { ["Watched Events - Code Entered - Owned"] = "Entered code `{0}` correctly on a banned player's ({1}) {2}", ["Watched Events - Code Entered - Guest"] = "Entered code `{0}` correctly on {2} that a banned player ({1}) is guest to", ["Watched Events - Code Entered - Whitelist"] = "Entered code `{0}` correctly on {2} that a banned player ({1}) is whitelisted to", ["Watched Events - Cupboard Authorize - Owned"] = "Authorized on a banned player's ({0}) TC", ["Watched Events - Cupboard Authorize - Authed"] = "Authorized on a TC that a banned player ({0}) is authorized on", ["Watched Events - Cupboard Deauthorize - Owned"] = "Deauthed on a TC a banned player ({0}) owns", ["Watched Events - Cupboard Deauthorize - Authed"] = "Deauthed on a TC a banned player ({0}) is authorized on", ["Watched Events - Cupboard Clearlist - Owned"] = "Cleared a TC that belongs to a banned player ({0})", ["Watched Events - Cupboard Clearlist - Authed"] = "Cleared a TC that a banned player ({0}) is authorized on", }, this); } void LoadData() { try { _banWatchList = Interface.Oxide.DataFileSystem.ReadObject>(this.Name); lastSavedCount = _banWatchList.Count(); } catch (Exception e) { Puts(e.Message); } } void SaveData() { _banWatchList = _banWatchList.Where(x => x.Value >= DateTime.Now.AddHours(-config.monitorHours)).ToDictionary(i => i.Key, i => i.Value); int records = _banWatchList.Count(); int recordsDiff = records - lastSavedCount; if (recordsDiff == 0) return; try { Interface.Oxide.DataFileSystem.WriteObject(this.Name, _banWatchList, true); lastSavedCount = records; } catch (Exception e) { Puts(e.Message); } } protected override void LoadDefaultConfig() => PrintWarning("Generating new configuration file."); #endregion } }