Иконка ресурса

FREE TeamShare : 1.4.4 1.4.4

Нет прав для скачивания
C#:
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using UnityEngine;
namespace Oxide.Plugins {
    [Info("TeamShare", "Uzumi & NordicRust", "1.4.4")]
    [Description("Allows automatic team auth on codelocks, turrets, and tool cupboards via the /share command. Team blueprint sharing follows Operating Mode and can be disabled in config; when Use Permissions is on, sharing requires teamshare.use and teamshare.blueprint.")]
    public class TeamShare : RustPlugin {
        [PluginReference]
        private Plugin WelcomeController;
        [PluginReference]
        private Plugin NoEscape;
        [PluginReference]
        private Plugin Clans;
        // Some servers run Clans Reborn under this plugin name.
        [PluginReference]
        private Plugin ClansReborn;
        private class Configuration {
            [JsonProperty("Use Permissions")]
            public bool UsePermissions = true;
            [JsonProperty("Using WelcomeController")]
            public bool UsingWelcomeController = false;
            [JsonProperty("Debug Mode")]
            public bool DebugMode = false;
            [JsonProperty("Messages")]
            public Dictionary<string, string> Messages = new Dictionary<string, string> {
                ["NoPermission"]
                = "You don't have permission to use this command.", ["InvalidCode"] = "Invalid code. Please enter a 4-digit numerical code.", ["CodeSet"] = "Code set to: {0}", ["GuestCodeSet"] = "Guest code set to: {0}", ["NoCodeSet"] = "You have not set any code. Use the UI to set a code.", ["CodeAutoLocked"] = "Code lock placed with code {0}.", ["CodeAutoLockedWithGuest"] = "Code lock placed with code {0} and guest code {1}.", ["CupboardAuthorized"] = "{0} authorized on the Tool Cupboard", ["NoEscape.RaidBlocked"] = "Cannot set codes during raid block.", ["NoEscape.CombatBlocked"] = "Cannot set codes during combat block.", ["NoGuestCodeSet"] = "Please enter a guest code first.", ["AuthedBackward"] = "Authed \"{0}\" to {1} codelocks, {2} turrets and {3} TC's", ["BlueprintSharedSharer"] = "You shared \"{0}\" with {1} teammate(s).", ["BlueprintReceivedReceiver"] = "{0} shared \"{1}\" with the team.", ["BlueprintBulkReceived"] = "Team share: you received {0} blueprint(s) from {1}.", ["BlueprintBulkFromYourLibrary"] = "Team share: {0} received {1} blueprint(s) from your library."
            }
            ;
            [JsonProperty("UI Settings")]
            public UISettings UISettings = new UISettings();
            [JsonProperty("Commands Settings")]
            public CommandsSettings CommandsSettings = new CommandsSettings();
            [JsonProperty("AddonName for WelcomeController")]
            public string AddonName = "TeamShare";
            [JsonProperty("NoEscape Integration")]
            public NoEscapeIntegrationSettings NoEscapeIntegration = new NoEscapeIntegrationSettings();
            [JsonProperty("Operating Mode")]
            public int OperatingMode = 1;
            [JsonProperty("Blueprint team sharing enabled")]
            public bool BlueprintTeamSharingEnabled = true;
            [JsonProperty("Blueprint clan sharing enabled (Clans Reborn)")]
            public bool BlueprintClanSharingEnabled = true;
            [JsonProperty("Blueprint share from research items (study action)")]
            public bool BlueprintShareFromItems = true;
            [JsonProperty("Blueprint share from tech tree unlocks")]
            public bool BlueprintShareFromTechTree = true;
            [JsonProperty("Blueprint share blocked item short names")]
            public List<string> BlueprintShareBlockedShortNames = new List<string>();
            [JsonProperty("Blueprint library resync delay seconds after learn")]
            public float BlueprintLibraryResyncDelaySeconds = 3f;
        }
        public class CommandsSettings {
            [JsonProperty("Open UI Command")]
            public string OpenUI = "teamui";
            [JsonProperty("Share Command")]
            public string Share = "share";
        }
        public class UISettings {
            public string UIBackgroundColor {
                get;
                set;
            }
            = "0 0 0 0.6";
            public string UIPrimaryColor {
                get;
                set;
            }
            = "1 0.4 0 0.5";
            public string UIDangerButtonColor {
                get;
                set;
            }
            = "1 0 0 1";
            [JsonProperty("UIToggleOnColor")]
            public string UIToggleOnColor {
                get;
                set;
            }
            = "0.15 0.6 0.15 1";
            [JsonProperty("UIToggleOffColor")]
            public string UIToggleOffColor {
                get;
                set;
            }
            = "0.6 0.15 0.15 1";
            [JsonProperty("Animated Buttons")]
            public bool AnimatedButtons = true;
        }
        public class NoEscapeIntegrationSettings {
            [JsonProperty("Block During Raid Block")]
            public bool BlockDuringRaidBlock = true;
            [JsonProperty("Block During Combat Block")]
            public bool BlockDuringCombatBlock = true;
        }
        private const int OPERATING_MODE_PER_PLACEMENT = 1;
        private const int OPERATING_MODE_BACKWARD_AUTH = 2;
        private class EntityCache {
            public readonly HashSet<AutoTurret> AutoTurrets = new HashSet<AutoTurret>();
            public readonly HashSet<BuildingPrivlidge> BuildingPrivlidges = new HashSet<BuildingPrivlidge>();
            public readonly HashSet<CodeLock> CodeLocks = new HashSet<CodeLock>();
        }
        private class PlayerData {
            public bool enabledCodelock {
                get;
                set;
            }
            = true;
            public bool enabledCupboard {
                get;
                set;
            }
            = true;
            public bool enabledTurret {
                get;
                set;
            }
            = true;
            public bool enabledQuiet {
                get;
                set;
            }
            = false;
            public bool enabledGuestCode {
                get;
                set;
            }
            = false;
        }
        private const string PERMISSION_USE = "teamshare.use";
        private const string PERMISSION_CODELOCK = "teamshare.codelock";
        private const string PERMISSION_CUPBOARD = "teamshare.cupboard";
        private const string PERMISSION_TURRET = "teamshare.turret";
        private const string PERMISSION_GUEST = "teamshare.guest";
        private const string PERMISSION_BLUEPRINT = "teamshare.blueprint";
        private DynamicConfigFile _playerCodesData;
        private DynamicConfigFile _playerGuestCodesData;
        private DynamicConfigFile _playerDataFile;
        private static Configuration _pluginConfig;
        private Dictionary<ulong, string> _playerCodes = new Dictionary<ulong, string>();
        private Dictionary<ulong, string> _playerGuestCodes = new Dictionary<ulong, string>();
        private Dictionary<ulong, PlayerData> _playerData = new Dictionary<ulong, PlayerData>();
        private Dictionary<ulong, string> playerUIs = new Dictionary<ulong, string>();
        private Dictionary<ulong, string> playerTempCodes = new Dictionary<ulong, string>();
        private Dictionary<ulong, string> playerTempGuestCodes = new Dictionary<ulong, string>();
        private Dictionary<ulong, bool> playerCodeRevealed = new Dictionary<ulong, bool>();
        private Dictionary<ulong, bool> playerGuestCodeRevealed = new Dictionary<ulong, bool>();
        private Dictionary<ulong, Timer> codeChangedTimers = new Dictionary<ulong, Timer>();
        private Dictionary<ulong, Timer> guestCodeChangedTimers = new Dictionary<ulong, Timer>();
        private Dictionary<string, Timer> animationTimers = new Dictionary<string, Timer>();
        private UISettings uiSettings;
        private readonly Dictionary<ulong, EntityCache> _playerEntities = new Dictionary<ulong, EntityCache>();
        private DynamicConfigFile _blueprintTrackingFile;
        // receiverId -> (sharerId -> blueprintIds)
        private Dictionary<string, Dictionary<string, HashSet<int>>> _blueprintTeamSharedByPlayer = new Dictionary<string, Dictionary<string, HashSet<int>>>();
        private bool _blueprintTrackingDirty;
        private readonly Dictionary<ulong, Timer> _blueprintLibraryResyncTimers = new Dictionary<ulong, Timer>();
        // receiverId -> (sharerId -> blueprintIds)
        private Dictionary<string, Dictionary<string, HashSet<int>>> _blueprintClanSharedByPlayer = new Dictionary<string, Dictionary<string, HashSet<int>>>();
        private DynamicConfigFile _blueprintClanTrackingFile;
        private bool _blueprintClanTrackingDirty;
        private readonly Dictionary<string, HashSet<ulong>> _clanMembersByTag = new Dictionary<string, HashSet<ulong>>();
        private class TeamBlueprintTrackingSerialized {
            public Dictionary<string, Dictionary<string, List<int>>> TeamSharedBlueprintIdsByReceiver = new Dictionary<string, Dictionary<string, List<int>>>();
        }
        // Backward compatible loader for old tracking format (receiverId -> blueprintIds).
        private class TeamBlueprintTrackingSerializedV1 {
            public Dictionary<string, List<int>> TeamSharedBlueprintIdsByPlayer = new Dictionary<string, List<int>>();
        }
        private class ClanBlueprintTrackingSerialized {
            public Dictionary<string, Dictionary<string, List<int>>> ClanSharedBlueprintIdsByReceiver = new Dictionary<string, Dictionary<string, List<int>>>();
        }
        private class ToggleOption {
            public string Label;
            public string Command;
            public bool IsOn;
            public string Permission;
        }
#region Hooks and Initialization
        void Init() {
            LoadConfigData();
            EnsureConfigurationDefaults();
            LoadPlayerData();
            permission.RegisterPermission(PERMISSION_USE, this);
            permission.RegisterPermission(PERMISSION_CODELOCK, this);
            permission.RegisterPermission(PERMISSION_CUPBOARD, this);
            permission.RegisterPermission(PERMISSION_TURRET, this);
            permission.RegisterPermission(PERMISSION_GUEST, this);
            permission.RegisterPermission(PERMISSION_BLUEPRINT, this);
            lang.RegisterMessages(_pluginConfig.Messages, this);
            uiSettings = _pluginConfig.UISettings;
            HandleCommands();
            LoadClanBlueprintTracking();
            RebuildClanMemberCache();
            if (!BlueprintSharingHooksEnabled()) {
                Unsubscribe(nameof(OnItemAction));
                Unsubscribe(nameof(OnBlueprintLearned));
                Unsubscribe(nameof(OnTechTreeNodeUnlock));
                Unsubscribe(nameof(OnTechTreeNodeUnlocked));
                Unsubscribe(nameof(OnPlayerStudyBlueprint));
            }
            else {
                if (!_pluginConfig.BlueprintShareFromItems) {
                    Unsubscribe(nameof(OnItemAction));
                    Unsubscribe(nameof(OnPlayerStudyBlueprint));
                }
                if (!_pluginConfig.BlueprintShareFromTechTree) {
                    Unsubscribe(nameof(OnBlueprintLearned));
                    Unsubscribe(nameof(OnTechTreeNodeUnlock));
                    Unsubscribe(nameof(OnTechTreeNodeUnlocked));
                }
            }
            Interface.CallHook("OnWCRequestColors", _pluginConfig.AddonName);
            if (_pluginConfig.DebugMode) {
                Puts("TeamShare plugin initialized.");
            }
        }
        private void LoadConfigData() {
            try {
                _pluginConfig = Config.ReadObject<Configuration>();
                if (_pluginConfig == null) throw new Exception();
                if (_pluginConfig.DebugMode) {
                    Puts("Configuration loaded successfully.");
                }
            }
            catch {
                PrintError("Configuration file is corrupt or missing. Creating new configuration.");
                LoadDefaultConfig();
            }
        }
        private void EnsureConfigurationDefaults() {
            if (_pluginConfig.Messages == null) _pluginConfig.Messages = new Dictionary<string, string>();
            foreach (var kv in new Configuration().Messages) {
                if (!_pluginConfig.Messages.ContainsKey(kv.Key)) _pluginConfig.Messages[kv.Key] = kv.Value;
            }
        }
        protected override void LoadDefaultConfig() {
            _pluginConfig = new Configuration();
            SaveConfig();
            if (_pluginConfig.DebugMode) {
                Puts("Default configuration loaded.");
            }
        }
        protected override void SaveConfig() {
            Config.WriteObject(_pluginConfig, true);
            if (_pluginConfig.DebugMode) {
                Puts("Configuration saved.");
            }
        }
        private void LoadPlayerData() {
            _playerCodesData = Interface.Oxide.DataFileSystem.GetDatafile("TeamShare/PlayerCodes");
            _playerGuestCodesData = Interface.Oxide.DataFileSystem.GetDatafile("TeamShare/PlayerGuestCodes");
            _playerDataFile = Interface.Oxide.DataFileSystem.GetDatafile("TeamShare/PlayerData");
            try {
                _playerCodes = _playerCodesData.ReadObject<Dictionary<ulong, string>>();
                if (_pluginConfig.DebugMode) {
                    Puts("Player codes loaded.");
                }
            }
            catch {
                _playerCodes = new Dictionary<ulong, string>();
                PrintError("Failed to load PlayerCodes data. Initialized empty dictionary.");
            }
            try {
                _playerGuestCodes = _playerGuestCodesData.ReadObject<Dictionary<ulong, string>>();
                if (_pluginConfig.DebugMode) {
                    Puts("Player guest codes loaded.");
                }
            }
            catch {
                _playerGuestCodes = new Dictionary<ulong, string>();
                PrintError("Failed to load PlayerGuestCodes data. Initialized empty dictionary.");
            }
            try {
                _playerData = _playerDataFile.ReadObject<Dictionary<ulong, PlayerData>>();
                if (_pluginConfig.DebugMode) {
                    Puts("Player data loaded.");
                }
            }
            catch {
                _playerData = new Dictionary<ulong, PlayerData>();
                PrintError("Failed to load PlayerData. Initialized empty dictionary.");
            }
            _blueprintTrackingFile = Interface.Oxide.DataFileSystem.GetDatafile("TeamShare/BlueprintTracking");
            try {
                _blueprintTeamSharedByPlayer = new Dictionary<string, Dictionary<string, HashSet<int>>>();
                // Try v2 format first.
                var raw = _blueprintTrackingFile.ReadObject<TeamBlueprintTrackingSerialized>() ?? new TeamBlueprintTrackingSerialized();
                if (raw.TeamSharedBlueprintIdsByReceiver != null && raw.TeamSharedBlueprintIdsByReceiver.Count > 0) {
                    foreach (var receiverKvp in raw.TeamSharedBlueprintIdsByReceiver) {
                        var perSharer = new Dictionary<string, HashSet<int>>();
                        if (receiverKvp.Value != null) {
                            foreach (var sharerKvp in receiverKvp.Value) {
                                perSharer[sharerKvp.Key] = new HashSet<int>(sharerKvp.Value ?? new List<int>());
                            }
                        }
                        _blueprintTeamSharedByPlayer[receiverKvp.Key] = perSharer;
                    }
                }
                else {
                    // Fallback to v1 format. We store under sharerId "*" since we do not know the actual sharer.
                    var rawV1 = _blueprintTrackingFile.ReadObject<TeamBlueprintTrackingSerializedV1>() ?? new TeamBlueprintTrackingSerializedV1();
                    if (rawV1.TeamSharedBlueprintIdsByPlayer != null) {
                        foreach (var kv in rawV1.TeamSharedBlueprintIdsByPlayer) {
                            _blueprintTeamSharedByPlayer[kv.Key] = new Dictionary<string, HashSet<int>> {
                                ["*"]
                                = new HashSet<int>(kv.Value ?? new List<int>())
                            }
                            ;
                        }
                    }
                }
                if (_pluginConfig.DebugMode) {
                    Puts("Blueprint tracking data loaded.");
                }
            }
            catch {
                _blueprintTeamSharedByPlayer = new Dictionary<string, Dictionary<string, HashSet<int>>>();
                PrintError("Failed to load TeamShare blueprint tracking. Initialized empty.");
            }
        }
        private void SavePlayerData() {
            _playerCodesData.WriteObject(_playerCodes);
            _playerGuestCodesData.WriteObject(_playerGuestCodes);
            _playerDataFile.WriteObject(_playerData);
            SaveBlueprintTracking();
            SaveClanBlueprintTracking();
            if (_pluginConfig.DebugMode) {
                Puts("Player data saved.");
            }
        }
        private void LoadClanBlueprintTracking() {
            _blueprintClanTrackingFile = Interface.Oxide.DataFileSystem.GetDatafile("TeamShare/ClanBlueprintTracking");
            try {
                _blueprintClanSharedByPlayer = new Dictionary<string, Dictionary<string, HashSet<int>>>();
                var raw = _blueprintClanTrackingFile.ReadObject<ClanBlueprintTrackingSerialized>() ?? new ClanBlueprintTrackingSerialized();
                if (raw.ClanSharedBlueprintIdsByReceiver != null && raw.ClanSharedBlueprintIdsByReceiver.Count > 0) {
                    foreach (var receiverKvp in raw.ClanSharedBlueprintIdsByReceiver) {
                        var perSharer = new Dictionary<string, HashSet<int>>();
                        if (receiverKvp.Value != null) {
                            foreach (var sharerKvp in receiverKvp.Value) {
                                perSharer[sharerKvp.Key] = new HashSet<int>(sharerKvp.Value ?? new List<int>());
                            }
                        }
                        _blueprintClanSharedByPlayer[receiverKvp.Key] = perSharer;
                    }
                }
                if (_pluginConfig.DebugMode) Puts("Clan blueprint tracking data loaded.");
            }
            catch {
                _blueprintClanSharedByPlayer = new Dictionary<string, Dictionary<string, HashSet<int>>>();
                PrintError("Failed to load Clan blueprint tracking. Initialized empty.");
            }
        }
        private HashSet<ulong> FetchClanMembersByTag(string tag) {
            var clansPlugin = GetClansPlugin();
            if (clansPlugin == null) return new HashSet<ulong>();
            var clan = clansPlugin.Call<JObject>("GetClan", tag);
            if (clan == null) return new HashSet<ulong>();
            var membersToken = clan["members"];
            if (membersToken == null) return new HashSet<ulong>();
            var set = new HashSet<ulong>();
            if (membersToken is JArray arr) {
                foreach (var t in arr) {
                    if (t == null) continue;
                    if (ulong.TryParse(t.ToString(), out var id)) set.Add(id);
                }
            }
            return set;
        }
        private void RebuildClanMemberCache() {
            _clanMembersByTag.Clear();
            var clansPlugin = GetClansPlugin();
            if (clansPlugin == null) return;
            var tags = clansPlugin.Call<JArray>("GetAllClans");
            if (tags == null) return;
            foreach (var t in tags) {
                var tag = t?.ToString();
                if (string.IsNullOrEmpty(tag)) continue;
                _clanMembersByTag[tag] = FetchClanMembersByTag(tag);
            }
        }
        private PlayerData GetPlayerData(ulong userID) {
            if (!_playerData.ContainsKey(userID)) {
                _playerData.Add(userID, new PlayerData());
                SavePlayerData();
                if (_pluginConfig.DebugMode) {
                    Puts($"Created new PlayerData for UserID: {userID}");
                }
            }
            return _playerData[userID];
        }
        private bool IsPermitted(BasePlayer player) {
            if (_pluginConfig.UsePermissions && !permission.UserHasPermission(player.UserIDString, PERMISSION_USE)) {
                if (_pluginConfig.DebugMode) {
                    Puts($"Player {player.displayName} does not have permission to use TeamShare.");
                }
                return false;
            }
            return true;
        }
        private bool HasBlueprintSharerPermission(ulong sharerUserId) {
            if (!_pluginConfig.UsePermissions) return true;
            string id = sharerUserId.ToString();
            if (!permission.UserHasPermission(id, PERMISSION_USE)) return false;
            return permission.UserHasPermission(id, PERMISSION_BLUEPRINT);
        }
        private bool CanPlayerInitiateBlueprintSharing(BasePlayer player) {
            if (player == null) return false;
            if (!IsPermitted(player)) return false;
            return HasFeaturePermission(player, PERMISSION_BLUEPRINT);
        }
        private bool HasFeaturePermission(BasePlayer player, string perm) {
            if (!_pluginConfig.UsePermissions) return true;
            return permission.UserHasPermission(player.UserIDString, perm);
        }
        private bool IsValidCode(string code) {
            bool isValid = code.Length == 4 && int.TryParse(code, out _);
            if (_pluginConfig.DebugMode) {
                Puts($"Code validation for '{code}': {isValid}");
            }
            return isValid;
        }
        private void SetPlayerCode(ulong playerId, string code) {
            _playerCodes[playerId] = code;
            SavePlayerData();
            if (_pluginConfig.DebugMode) {
                Puts($"Set main code for UserID {playerId} to {code}");
            }
        }
        private string GetPlayerCode(ulong playerId) {
            string code = _playerCodes.TryGetValue(playerId, out string value) ? value : null;
            if (_pluginConfig.DebugMode) {
                Puts($"Retrieved main code for UserID {playerId}: {code}");
            }
            return code;
        }
        private void SetPlayerGuestCode(ulong playerId, string code) {
            _playerGuestCodes[playerId] = code;
            SavePlayerData();
            if (_pluginConfig.DebugMode) {
                Puts($"Set guest code for UserID {playerId} to {code}");
            }
        }
        private string GetPlayerGuestCode(ulong playerId) {
            string code = _playerGuestCodes.TryGetValue(playerId, out string value) ? value : null;
            if (_pluginConfig.DebugMode) {
                Puts($"Retrieved guest code for UserID {playerId}: {code}");
            }
            return code;
        }
        [HookMethod("IsUsingPlugin")]
        private bool IsUsingPlugin(string pluginName) {
            bool isUsing = pluginName.Equals(_pluginConfig.AddonName, StringComparison.OrdinalIgnoreCase);
            if (_pluginConfig.DebugMode) {
                Puts($"IsUsingPlugin check for '{pluginName}': {isUsing}");
            }
            return isUsing;
        }
        [HookMethod("OnWCRequestedUIPanel")]
        private void OnWCRequestedUIPanel(BasePlayer player, string panelName, string neededPlugin) {
            if (!neededPlugin.Equals(_pluginConfig.AddonName, StringComparison.OrdinalIgnoreCase)) return;
            if (_pluginConfig.DebugMode) {
                Puts($"Received UI panel request '{panelName}' from player {player.displayName}.");
            }
            CreateUI(player, panelName);
        }
        void OnWCRequestColors(string pluginName) {
            if (!pluginName.Equals(_pluginConfig.AddonName, StringComparison.OrdinalIgnoreCase)) return;
            if (_pluginConfig.DebugMode) {
                Puts($"Requesting theme colors for plugin '{pluginName}'.");
            }
            Interface.CallHook("WCSendColors", ConvertToDictionary(uiSettings), pluginName);
        }
        void OnWCSentThemeColors(List<string> pluginNames, Dictionary<string, string> themeColors) {
            if (!pluginNames.Contains(_pluginConfig.AddonName)) return;
            if (_pluginConfig.DebugMode) {
                Puts($"Received theme colors for plugin '{_pluginConfig.AddonName}'.");
            }
            uiSettings.UIBackgroundColor = themeColors.ContainsKey("BackgroundColor") ? themeColors["BackgroundColor"] : uiSettings.UIBackgroundColor;
            uiSettings.UIPrimaryColor = themeColors.ContainsKey("PrimaryButtonColor") ? themeColors["PrimaryButtonColor"] : uiSettings.UIPrimaryColor;
            uiSettings.UIDangerButtonColor = themeColors.ContainsKey("SecondaryButtonColor") ? themeColors["SecondaryButtonColor"] : uiSettings.UIDangerButtonColor;
            SaveConfig();
        }
        private static Dictionary<string, string> ConvertToDictionary(UISettings uiSettings) {
            var dictionary = new Dictionary<string, string>();
            foreach (var property in typeof(UISettings).GetProperties()) {
                string key = property.Name;
                string value = property.GetValue(uiSettings)?.ToString();
                dictionary[key] = value;
            }
            return dictionary;
        }
        private void HandleCommands() {
            cmd.AddChatCommand(_pluginConfig.CommandsSettings.OpenUI, this, OpenTeamShareUI);
            cmd.AddChatCommand(_pluginConfig.CommandsSettings.Share, this, OpenTeamShareUI);
            if (_pluginConfig.DebugMode) {
                Puts($"Chat commands registered: /{_pluginConfig.CommandsSettings.OpenUI}, /{_pluginConfig.CommandsSettings.Share}");
            }
        }
        private void OnServerSave() {
            SavePlayerData();
        }
        private void Unload() {
            foreach (var kvp in codeChangedTimers.ToList()) {
                kvp.Value?.Destroy();
            }
            codeChangedTimers.Clear();
            foreach (var kvp in guestCodeChangedTimers.ToList()) {
                kvp.Value?.Destroy();
            }
            guestCodeChangedTimers.Clear();
            foreach (var kvp in animationTimers.ToList()) {
                kvp.Value?.Destroy();
            }
            animationTimers.Clear();
            foreach (var kvp in _blueprintLibraryResyncTimers.ToList()) {
                kvp.Value?.Destroy();
            }
            _blueprintLibraryResyncTimers.Clear();
            foreach (BasePlayer player in BasePlayer.activePlayerList) {
                DestroyUI(player);
            }
            SavePlayerData();
            if (_pluginConfig?.DebugMode == true) {
                Puts("TeamShare plugin unloaded. All UIs and timers destroyed, data saved.");
            }
        }
        private void OnServerInitialized() {
            if (_pluginConfig.OperatingMode != OPERATING_MODE_BACKWARD_AUTH) return;
            foreach (var serverEntity in BaseNetworkable.serverEntities) {
                if (serverEntity == null || serverEntity.IsDestroyed) continue;
                if (serverEntity is AutoTurret autoTurret) {
                    if (autoTurret.OwnerID == 0) continue;
                    if (!_pluginConfig.UsePermissions || permission.UserHasPermission(autoTurret.OwnerID.ToString(), PERMISSION_USE)) AddEntityToCache(autoTurret.OwnerID, autoTurret);
                    continue;
                }
                if (serverEntity is BuildingPrivlidge buildingPrivlidge) {
                    if (buildingPrivlidge.OwnerID == 0) continue;
                    if (!_pluginConfig.UsePermissions || permission.UserHasPermission(buildingPrivlidge.OwnerID.ToString(), PERMISSION_USE)) AddEntityToCache(buildingPrivlidge.OwnerID, buildingPrivlidge);
                    continue;
                }
                if (serverEntity is CodeLock codeLock) {
                    var parent = codeLock.GetParentEntity();
                    ulong ownerId = codeLock.OwnerID != 0 ? codeLock.OwnerID : parent?.OwnerID ?? 0;
                    if (ownerId == 0) continue;
                    if (!_pluginConfig.UsePermissions || permission.UserHasPermission(ownerId.ToString(), PERMISSION_USE)) AddEntityToCache(ownerId, codeLock);
                }
            }
            if (_pluginConfig.DebugMode) Puts("Mode 2: Entity cache rebuilt from server entities.");
        }
#endregion
#region Entity Deployment Hooks
        void OnEntitySpawned(BaseNetworkable entity) {
            if (entity == null) return;
            if (entity is CodeLock codelock) {
                HandleCodeLockDeployment(codelock);
            }
            else if (entity is BuildingPrivlidge cupboard) {
                HandleCupboardDeployment(cupboard);
            }
            else if (entity is AutoTurret turret) {
                HandleAutoTurretDeployment(turret);
            }
        }
        private void HandleCodeLockDeployment(CodeLock codelock) {
            BasePlayer player = GetPermittedOwner(codelock);
            if (player == null || !IsPermitted(player)) return;
            if (!HasFeaturePermission(player, PERMISSION_CODELOCK)) return;
            if (_pluginConfig.DebugMode) {
                Puts($"Handling CodeLock deployment by {player.displayName} (UserID: {player.UserIDString})");
            }
            if (NoEscape != null) {
                object raidBlockedResult = NoEscape.Call("IsRaidBlocked", player);
                if (_pluginConfig.NoEscapeIntegration.BlockDuringRaidBlock && raidBlockedResult is bool isRaidBlocked && isRaidBlocked) {
                    player.ChatMessage(Lang("NoEscape.RaidBlocked", player.UserIDString));
                    if (_pluginConfig.DebugMode) {
                        Puts($"Raid block active. Deployment of CodeLock by {player.displayName} blocked.");
                    }
                    return;
                }
                object combatBlockedResult = NoEscape.Call("IsCombatBlocked", player);
                if (_pluginConfig.NoEscapeIntegration.BlockDuringCombatBlock && combatBlockedResult is bool isCombatBlocked && isCombatBlocked) {
                    player.ChatMessage(Lang("NoEscape.CombatBlocked", player.UserIDString));
                    if (_pluginConfig.DebugMode) {
                        Puts($"Combat block active. Deployment of CodeLock by {player.displayName} blocked.");
                    }
                    return;
                }
            }
            PlayerData pData = GetPlayerData(player.userID);
            if (pData.enabledCodelock) {
                string code = GetPlayerCode(player.userID);
                if (!string.IsNullOrEmpty(code)) {
                    codelock.code = code;
                    codelock.hasCode = true;
                    codelock.SetFlagLocal(BaseEntity.Flags.Locked, true);
                    codelock.whitelistPlayers.Clear();
                    SetEntityWhitelist(player, codelock);
                    if (pData.enabledGuestCode && HasFeaturePermission(player, PERMISSION_GUEST)) {
                        string guestCode = GetPlayerGuestCode(player.userID);
                        if (!string.IsNullOrEmpty(guestCode)) {
                            codelock.guestCode = guestCode;
                            codelock.hasGuestCode = true;
                            codelock.guestPlayers.Clear();
                        }
                        else {
                            codelock.hasGuestCode = false;
                        }
                    }
                    else {
                        codelock.hasGuestCode = false;
                    }
                    codelock.SendNetworkUpdateImmediate();
                    if (!pData.enabledQuiet) {
                        List<string> authorizedNames = GetAuthorizedNames(GetTeamMembers(player));
                        string message = pData.enabledGuestCode && codelock.hasGuestCode ? $"Code lock placed with code \"{code}\" and guest code \"{codelock.guestCode}\" authed {string.Join(", ", authorizedNames)}" : $"Code lock placed with code \"{code}\" authed {string.Join(", ", authorizedNames)}";
                        SendChatMessage(player, message);
                    }
                }
                else {
                    if (!pData.enabledQuiet) SendChatMessage(player, Lang("NoCodeSet", player.UserIDString));
                }
            }
            if (_pluginConfig.OperatingMode == OPERATING_MODE_BACKWARD_AUTH) {
                AddEntityToCache(player.userID, codelock);
            }
            if (_pluginConfig.DebugMode) {
                Puts($"CodeLock deployment handled for {player.displayName}.");
            }
        }
        private void HandleCupboardDeployment(BuildingPrivlidge cupboard) {
            BasePlayer player = GetPermittedOwner(cupboard);
            if (player == null || !IsPermitted(player)) return;
            if (!HasFeaturePermission(player, PERMISSION_CUPBOARD)) return;
            if (_pluginConfig.DebugMode) {
                Puts($"Handling Tool Cupboard deployment by {player.displayName} (UserID: {player.UserIDString})");
            }
            PlayerData pData = GetPlayerData(player.userID);
            if (pData.enabledCupboard) {
                SetEntityWhitelist(player, cupboard);
                cupboard.SendNetworkUpdateImmediate();
                if (!pData.enabledQuiet) {
                    List<string> authorizedNames = GetAuthorizedNames(GetTeamMembers(player));
                    string authedMessage = $"Authorized {string.Join(", ", authorizedNames)} on the Tool Cupboard";
                    SendChatMessage(player, authedMessage);
                }
            }
            if (_pluginConfig.OperatingMode == OPERATING_MODE_BACKWARD_AUTH) {
                AddEntityToCache(player.userID, cupboard);
            }
            if (_pluginConfig.DebugMode) {
                Puts($"Tool Cupboard deployment handled for {player.displayName}.");
            }
        }
        private void HandleAutoTurretDeployment(AutoTurret turret) {
            BasePlayer player = GetPermittedOwner(turret);
            if (player == null || !IsPermitted(player)) return;
            if (!HasFeaturePermission(player, PERMISSION_TURRET)) return;
            if (_pluginConfig.DebugMode) {
                Puts($"Handling Auto Turret deployment by {player.displayName} (UserID: {player.UserIDString})");
            }
            PlayerData pData = GetPlayerData(player.userID);
            if (pData.enabledTurret) {
                SetEntityWhitelist(player, turret);
                turret.SendNetworkUpdateImmediate();
                if (!pData.enabledQuiet) {
                    List<string> authorizedNames = GetAuthorizedNames(GetTeamMembers(player));
                    string authedMessage = $"Authorized {string.Join(", ", authorizedNames)} on the Auto Turret";
                    SendChatMessage(player, authedMessage);
                }
            }
            if (_pluginConfig.OperatingMode == OPERATING_MODE_BACKWARD_AUTH) {
                AddEntityToCache(player.userID, turret);
            }
            if (_pluginConfig.DebugMode) {
                Puts($"Auto Turret deployment handled for {player.displayName}.");
            }
        }
        private BasePlayer GetPermittedOwner(BaseEntity entity) {
            if (entity == null) return null;
            BasePlayer player = BasePlayer.FindByID(entity.OwnerID);
            if (player == null || !IsPermitted(player)) {
                if (_pluginConfig.DebugMode) {
                    Puts($"Entity owner not found or lacks permission.");
                }
                return null;
            }
            if (_pluginConfig.DebugMode) {
                Puts($"Permitted owner found: {player.displayName} (UserID: {player.UserIDString})");
            }
            return player;
        }
        private List<ulong> GetTeamMembers(BasePlayer player) {
            if (player == null) return new List<ulong>();
            List<ulong> members = new List<ulong> {
                player.userID
            }
            ;
            if (player.currentTeam != 0) {
                RelationshipManager.PlayerTeam team = RelationshipManager.ServerInstance.FindTeam(player.currentTeam);
                if (team != null) {
                    foreach (ulong memberId in team.members) {
                        if (memberId != player.userID) members.Add(memberId);
                    }
                }
            }
            if (_pluginConfig.DebugMode) {
                Puts($"Team members for {player.displayName}: {string.Join(", ", members)}");
            }
            return members;
        }
        private List<string> GetAuthorizedNames(List<ulong> memberIds) {
            List<string> names = new List<string>();
            foreach (ulong id in memberIds) {
                string name = covalence.Players.FindPlayerById(id.ToString())?.Name ?? "Unknown";
                names.Add($"\"{name}\"");
            }
            return names;
        }
        private void SetEntityWhitelist(BasePlayer player, CodeLock codelock) {
            List<ulong> teamMembers = GetTeamMembers(player);
            foreach (ulong memberId in teamMembers) {
                codelock.whitelistPlayers.Add(memberId);
            }
            if (_pluginConfig.DebugMode) {
                foreach (ulong memberId in teamMembers) {
                    Puts($"UserID {memberId} authorized on CodeLock by {player.displayName}.");
                }
            }
        }
        private void SetEntityWhitelist(BasePlayer player, BuildingPrivlidge cupboard) {
            List<ulong> teamMembers = GetTeamMembers(player);
            foreach (ulong memberId in teamMembers) {
                cupboard.authorizedPlayers.Add(memberId);
            }
            if (_pluginConfig.DebugMode) {
                foreach (ulong memberId in teamMembers) {
                    Puts($"UserID {memberId} authorized on Tool Cupboard by {player.displayName}.");
                }
            }
        }
        private void SetEntityWhitelist(BasePlayer player, AutoTurret turret) {
            List<ulong> teamMembers = GetTeamMembers(player);
            foreach (ulong memberId in teamMembers) {
                turret.authorizedPlayers.Add(memberId);
            }
            if (_pluginConfig.DebugMode) {
                foreach (ulong memberId in teamMembers) {
                    Puts($"UserID {memberId} authorized on Auto Turret by {player.displayName}.");
                }
            }
        }
#region Team blueprint sharing
        private bool BlueprintSharingHooksEnabled() {
            if (!_pluginConfig.BlueprintTeamSharingEnabled) return false;
            return _pluginConfig.BlueprintShareFromItems || _pluginConfig.BlueprintShareFromTechTree;
        }
        private bool ClanBlueprintSharingEnabled() {
            if (!_pluginConfig.BlueprintClanSharingEnabled) return false;
            var clansPlugin = GetClansPlugin();
            return clansPlugin != null && clansPlugin.IsLoaded;
        }
        private Plugin GetClansPlugin() {
            if (ClansReborn != null && ClansReborn.IsLoaded) return ClansReborn;
            if (Clans != null && Clans.IsLoaded) return Clans;
            return null;
        }
        private bool IsClanMember(ulong playerId, ulong otherId) {
            var clansPlugin = GetClansPlugin();
            return clansPlugin != null && clansPlugin.Call<bool>("IsClanMember", playerId, otherId);
        }
        private List<ulong> GetClanMembers(ulong playerId) {
            var clansPlugin = GetClansPlugin();
            if (clansPlugin == null) return new List<ulong>();
            var members = clansPlugin.Call<List<string>>("GetClanMembers", playerId);
            if (members == null) return new List<ulong>();
            var result = new List<ulong>();
            foreach (var idStr in members) {
                if (ulong.TryParse(idStr, out var id)) result.Add(id);
            }
            return result;
        }
        private bool PlayerHasClanmatesForBlueprintShare(ulong playerId) {
            var members = GetClanMembers(playerId);
            return members.Count > 1;
        }
        private List<ulong> GetClanmateIdsForBlueprintShare(ulong sharerId) {
            return GetClanMembers(sharerId).Where(id => id != sharerId).ToList();
        }
        private void HandleBlueprintTeamInviteAccepted(RelationshipManager.PlayerTeam playerTeam, BasePlayer joiningPlayer) {
            if (!BlueprintSharingHooksEnabled() || playerTeam == null || joiningPlayer == null) return;
            ulong joinerId = joiningPlayer.userID;
            timer.Once(1f, () => {
                if (playerTeam.members == null || !playerTeam.members.Contains(joinerId)) return;
                foreach (ulong otherId in playerTeam.members) {
                    if (otherId == joinerId) continue;
                    ShareAllBlueprintsFromTo(otherId, joinerId);
                    ShareAllBlueprintsFromTo(joinerId, otherId);
                }
                FlushBlueprintTrackingIfDirty();
            }
            );
        }
        private void HandleClanMemberJoined(ulong joiningId, IEnumerable<ulong> existingMemberIds) {
            if (!ClanBlueprintSharingEnabled()) return;
            if (existingMemberIds == null) return;
            foreach (ulong otherId in existingMemberIds) {
                if (otherId == joiningId) continue;
                ShareAllBlueprintsFromToClan(otherId, joiningId);
                ShareAllBlueprintsFromToClan(joiningId, otherId);
            }
            FlushClanBlueprintTrackingIfDirty();
        }
        private void HandleClanMemberGone(ulong leavingId, IEnumerable<ulong> remainingMemberIds) {
            if (!ClanBlueprintSharingEnabled()) return;
            // Remove blueprints the leaving player received from clanmates.
            RemoveTrackedClanBlueprintsFromPlayer(leavingId);
            // Remove blueprints remaining members received from the leaving player.
            if (remainingMemberIds != null) {
                foreach (ulong receiverId in remainingMemberIds) {
                    if (receiverId == leavingId) continue;
                    RemoveTrackedClanBlueprintsFromPlayer(receiverId, leavingId);
                }
            }
            FlushClanBlueprintTrackingIfDirty();
        }
        private void ScheduleBlueprintLibrarySyncToTeammates(ulong learnerId) {
            if (!BlueprintSharingHooksEnabled()) return;
            var learner = BasePlayer.FindByID(learnerId);
            if (learner != null && !CanPlayerInitiateBlueprintSharing(learner)) return;
            if (!PlayerHasTeammatesForBlueprintShare(learnerId)) return;
            float delay = _pluginConfig.BlueprintLibraryResyncDelaySeconds;
            if (delay < 0f) delay = 0f;
            if (_blueprintLibraryResyncTimers.TryGetValue(learnerId, out var existing)) {
                existing?.Destroy();
                _blueprintLibraryResyncTimers.Remove(learnerId);
            }
            ulong idCopy = learnerId;
            _blueprintLibraryResyncTimers[learnerId] = timer.Once(delay, () => {
                _blueprintLibraryResyncTimers.Remove(idCopy);
                NextTick(() => RunBlueprintLibrarySyncFromPlayerToAllTeammates(idCopy));
            }
            );
        }
        private void RunBlueprintLibrarySyncFromPlayerToAllTeammates(ulong sharerId) {
            if (!BlueprintSharingHooksEnabled()) return;
            if (!HasBlueprintSharerPermission(sharerId)) return;
            var team = RelationshipManager.ServerInstance?.FindPlayersTeam(sharerId);
            if (team?.members == null || team.members.Count < 2) return;
            foreach (ulong teammateId in team.members) {
                if (teammateId == sharerId) continue;
                ShareAllBlueprintsFromTo(sharerId, teammateId);
            }
            FlushBlueprintTrackingIfDirty();
        }
        private void CancelBlueprintLibraryResyncTimer(ulong playerId) {
            if (!_blueprintLibraryResyncTimers.TryGetValue(playerId, out var t)) return;
            t?.Destroy();
            _blueprintLibraryResyncTimers.Remove(playerId);
        }
        private void HandleBlueprintPlayerLeftTeam(ulong leavingPlayerId, IList<ulong> lastKnownTeamMembers = null) {
            // Remove blueprints the leaving player received from the team.
            RemoveTrackedTeamBlueprintsFromPlayer(leavingPlayerId);
            // Also remove blueprints other players received from the leaving player.
            if (lastKnownTeamMembers == null || lastKnownTeamMembers.Count == 0) return;
            foreach (ulong receiverId in lastKnownTeamMembers) {
                if (receiverId == leavingPlayerId) continue;
                RemoveTrackedTeamBlueprintsFromPlayer(receiverId, leavingPlayerId);
            }
        }
        private void ShareAllBlueprintsFromTo(ulong sharerId, ulong receiverId) {
            if (sharerId == receiverId) return;
            if (!HasBlueprintSharerPermission(sharerId)) return;
            var filtered = GetFilteredUnlockedBlueprintIdsForPlayer(sharerId);
            if (filtered.Count == 0) return;
            var queue = new List<int>();
            bool track = _pluginConfig.OperatingMode == OPERATING_MODE_BACKWARD_AUTH;
            foreach (int blueprintId in filtered) {
                QueueBlueprintUnlockForTeam(sharerId, receiverId, blueprintId, queue, track);
            }
            if (queue.Count > 0) {
                int n = ProcessQueuedBlueprintUnlocks(receiverId, queue);
                if (n > 0) {
                    string sharerName = ResolvePlayerDisplayName(sharerId);
                    string receiverName = ResolvePlayerDisplayName(receiverId);
                    var receiver = BasePlayer.FindByID(receiverId);
                    if (receiver != null && receiver.IsConnected) SendChatMessage(receiver, Lang("BlueprintBulkReceived", receiver.UserIDString), n, sharerName);
                    var sharer = BasePlayer.FindByID(sharerId);
                    if (sharer != null && sharer.IsConnected) SendChatMessage(sharer, Lang("BlueprintBulkFromYourLibrary", sharer.UserIDString), receiverName, n);
       
// ... [Code preview truncated due to length. Full source in attached file] ...

Автор
15FPS
Скачиваний
0
Просмотры
1
Первый выпуск
Обновление
Оценка
0.00 звёзд 0 оценок
Сверху