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

FREE EntityScaleManager : 2.1.3 2.1.3

Нет прав для скачивания
C#:
using Network;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;
namespace Oxide.Plugins {
    [Info("Entity Scale Manager", "WhiteThunder", "2.1.3")]
    [Description("Utilities for resizing entities.")]
    internal class EntityScaleManager : CovalencePlugin {
#region Fields
        [PluginReference]
        Plugin ParentedEntityRenderFix;
        private static EntityScaleManager _pluginInstance;
        private static Configuration _pluginConfig;
        private static StoredData _pluginData;
        private const string PermissionScaleUnrestricted = "entityscalemanager.unrestricted";
        private const string SpherePrefab = "assets/prefabs/visualization/sphere.prefab";
        // This could be improved by calculating the time needed for the resize,
        // since the amount of time required seems to depend on the scale.private const float ExpectedResizeDuration = 7f;
#endregion
#region Hooks
        private void Init() {
            _pluginInstance = this;
            _pluginData = StoredData.Load();
            permission.RegisterPermission(PermissionScaleUnrestricted, this);
            if (!_pluginConfig.HideSpheresAfterResize) {
                Unsubscribe(nameof(OnEntitySnapshot));
                Unsubscribe(nameof(OnPlayerDisconnected));
                Unsubscribe(nameof(OnNetworkGroupLeft));
                Unsubscribe(nameof(CanStartTelekinesis));
            }
        }
        private void Unload() {
            _pluginData.Save();
            EntitySubscriptionManager.Instance.Clear();
            NetworkSnapshotManager.Instance.Clear();
            _pluginData = null;
            _pluginConfig = null;
            _pluginInstance = null;
        }
        private void OnServerInitialized() {
            foreach (var networkable in BaseNetworkable.serverEntities) {
                var entity = networkable as BaseEntity;
                if (entity == null) continue;
                var parentSphere = GetParentSphere(entity);
                if (parentSphere != null && _pluginData.ScaledEntities.Contains(entity.net.ID.Value)) RefreshScaledEntity(entity, parentSphere);
            }
        }
        private void OnServerSave() {
            _pluginData.Save();
        }
        private void OnNewSave() {
            _pluginData = StoredData.Clear();
        }
        private void OnEntityKill(BaseEntity entity) {
            if (entity == null || entity.net == null) return;
            if (!_pluginData.ScaledEntities.Remove(entity.net.ID.Value)) return;
            EntitySubscriptionManager.Instance.RemoveEntity(entity.net.ID);
            var parentSphere = GetParentSphere(entity);
            if (parentSphere != null) {
                // Destroy the sphere that was used to scale the entity.// This assumes that only one entity was scaled using this sphere.// We could instead check if the sphere still has children, but keeping the sphere
                // might cause it to never be killed after the remaining children are killed.// Plugins should generally parent other entities using a separate sphere, or
                // parent to the scaled entity itself.parentSphere.Invoke(() =>
                {
                    if (!parentSphere.IsDestroyed) parentSphere.Kill();
                }
                , 0);
            }
        }
        private void OnPlayerDisconnected(BasePlayer player) {
            EntitySubscriptionManager.Instance.RemoveSubscriber(player.userID);
        }
        private bool? OnEntitySnapshot(BaseEntity entity, Connection connection) {
            if (entity == null || entity.net == null) return null;
            if (!_pluginData.ScaledEntities.Contains(entity.net.ID.Value)) return null;
            var parentSphere = GetParentSphere(entity);
            if (parentSphere == null) return null;
            // Detect when the vanilla network cache has been cleared in order to invalidate the custom cache.if (entity._NetworkCache == null)
            NetworkSnapshotManager.Instance.InvalidateForEntity(entity.net.ID);
            var resizeState = EntitySubscriptionManager.Instance.GetResizeState(entity.net.ID, connection.ownerid);
            if (resizeState == ResizeState.Resized) {
                // Don't track CPU time of this since it's almost identidcal to the vanilla behavior being cancelled.// Tracking it would give server operators false information that this plugin is spending more CPU time than it is.TrackEnd();
                NetworkSnapshotManager.Instance.SendModifiedSnapshot(entity, connection);
                TrackStart();
                return false;
            }
            if (resizeState == ResizeState.NeedsResize) {
                // The entity is now starting to resize for this client.// Start a timer to cause this client to start using the custom snapshots after resize.timer.Once(ExpectedResizeDuration, () =>
                {
                    if (entity != null && parentSphere != null && EntitySubscriptionManager.Instance.DoneResizing(entity.net.ID, connection.ownerid)) {
                        // Send a snapshot to the client indicating that the entity is not parented to the sphere.NetworkSnapshotManager.Instance.SendModifiedSnapshot(entity, connection);
                        // Terminate the sphere on the client.// Subsequent snapshots to this client will use different logic.NetworkUtils.TerminateOnClient(parentSphere, connection);
                    }
                }
                );
            }
            // Send normal snapshot which indicates the entity has a sphere parent.return null;
        }
        // Clients destroy entities from a network group when they leave it.// This helps determine later on whether the client is creating the entity or simply receiving an update.private void OnNetworkGroupLeft(BasePlayer player, Network.Visibility.Group group)
        {
            for (var i = 0; i < group.networkables.Count; i++) {
                var networkable = group.networkables.Values.Buffer[i];
                if (networkable == null) continue;
                var entity = networkable.handler as BaseNetworkable;
                if (entity == null || entity.net == null) continue;
                EntitySubscriptionManager.Instance.RemoveEntitySubscription(entity.net.ID, player.userID);
            }
        }
        // This hook is exposed by plugin: Telekinesis.private Tuple<BaseEntity, BaseEntity> OnTelekinesisStart(BasePlayer player, BaseEntity entity)
        {
            if (!_pluginData.ScaledEntities.Contains(entity.net.ID.Value)) return null;
            var parentSphere = GetParentSphere(entity);
            if (parentSphere == null) return null;
            // Move the sphere, but rotate the child.// This is done because spheres have default rotation to avoid client-side interpolation issues.return new Tuple<BaseEntity, BaseEntity>(parentSphere, entity);
        }
        // This hook is exposed by plugin: Telekinesis.private string CanStartTelekinesis(BasePlayer player, SphereEntity moveEntity, BaseEntity rotateEntity)
        {
            if (!_pluginData.ScaledEntities.Contains(rotateEntity.net.ID.Value)) return null;
            return GetMessage(player, "Error.CannotMoveWithHiddenSpheres");
        }
#endregion
#region API
        private float API_GetScale(BaseEntity entity) {
            if (entity == null || entity.net == null) return 1;
            if (!_pluginData.ScaledEntities.Contains(entity.net.ID.Value)) return 1;
            var parentSphere = GetParentSphere(entity);
            if (parentSphere == null) return 1;
            return parentSphere.currentRadius;
        }
        private bool API_ScaleEntity(BaseEntity entity, float scale) {
            if (entity == null || entity.net == null) return false;
            return TryScaleEntity(entity, scale);
        }
        private bool API_ScaleEntity(BaseEntity entity, int scale) => API_ScaleEntity(entity, (float)scale);
        private void API_RegisterScaledEntity(BaseEntity entity) {
            if (entity == null || entity.net == null) return;
            _pluginData.ScaledEntities.Add(entity.net.ID.Value);
        }
#endregion
#region Commands
        [Command("scale")]
        private void CommandScale(IPlayer player, string cmd, string[] args) {
            if (player.IsServer) return;
            if (!player.HasPermission(PermissionScaleUnrestricted)) {
                ReplyToPlayer(player, "Error.NoPermission");
                return;
            }
            float scale;
            if (args.Length == 0 || !float.TryParse(args[0], out scale)) {
                ReplyToPlayer(player, "Error.Syntax", cmd);
                return;
            }
            var basePlayer = player.Object as BasePlayer;
            var entity = GetLookEntity(basePlayer);
            if (entity == null) {
                ReplyToPlayer(player, "Error.NoEntityFound");
                return;
            }
            if (TryScaleEntity(entity, scale)) ReplyToPlayer(player, "Scale.Success", scale);
            else ReplyToPlayer(player, "Error.ScaleBlocked", scale);
        }
        [Command("getscale")]
        private void CommandGetScale(IPlayer player) {
            if (player.IsServer) return;
            if (!player.HasPermission(PermissionScaleUnrestricted)) {
                ReplyToPlayer(player, "Error.NoPermission");
                return;
            }
            var basePlayer = player.Object as BasePlayer;
            var entity = GetLookEntity(basePlayer);
            if (entity == null) {
                ReplyToPlayer(player, "Error.NoEntityFound");
                return;
            }
            if (!_pluginData.ScaledEntities.Contains(entity.net.ID.Value)) {
                ReplyToPlayer(player, "Error.NotTracked");
                return;
            }
            var parentSphere = GetParentSphere(entity);
            if (parentSphere == null) {
                ReplyToPlayer(player, "Error.NotScaled");
                return;
            }
            ReplyToPlayer(player, "GetScale.Success", parentSphere.currentRadius);
        }
#endregion
#region Helper Methods
        private static bool EntityScaleWasBlocked(BaseEntity entity, float scale) {
            object hookResult = Interface.CallHook("OnEntityScale", entity, scale);
            return hookResult is bool && (bool)hookResult == false;
        }
        private static BaseEntity GetLookEntity(BasePlayer basePlayer, float maxDistance = 20) {
            RaycastHit hit;
            return Physics.Raycast(basePlayer.eyes.HeadRay(), out hit, maxDistance, Physics.DefaultRaycastLayers, QueryTriggerInteraction.Ignore) ? hit.GetEntity() : null;
        }
        private static void EnableGlobalBroadcastFixed(BaseEntity entity, bool wants) {
            entity.globalBroadcast = wants;
            if (wants) {
                entity.UpdateNetworkGroup();
            }
            else if (entity.net?.group?.ID == 0) {
                // Fix vanilla bug that prevents leaving the global network group.var group = entity.net.sv.visibility.GetGroup(entity.transform.position);
                entity.net.SwitchGroup(group);
            }
        }
        private static void SetupSphereEntity(SphereEntity sphereEntity, BaseEntity scaledEntity) {
            // SphereEntity has enableSaving off by default, so enable it if the child has saving enabled.// This fixes an issue where the resized child gets orphaned on restart and spams console errors every 2 seconds.sphereEntity.EnableSaving(scaledEntity.enableSaving);
            // SphereEntity has globalBroadcast on by default, but it should generally be off for scaled entities.// This fixes an issue where clients who resubscribe do not recreate the sphere or its children.EnableGlobalBroadcastFixed(sphereEntity, scaledEntity.globalBroadcast);
        }
        private static void SetSphereSize(SphereEntity sphereEntity, float scale) {
            sphereEntity.currentRadius = scale;
            sphereEntity.lerpRadius = scale;
            sphereEntity.transform.localScale = new Vector3(scale, scale, scale);
        }
        private static SphereEntity CreateSphere(Vector3 position, Quaternion rotation, float scale, BaseEntity scaledEntity) {
            var sphereEntity = GameManager.server.CreateEntity(SpherePrefab, position, rotation) as SphereEntity;
            if (sphereEntity == null) return null;
            SetupSphereEntity(sphereEntity, scaledEntity);
            SetSphereSize(sphereEntity, scale);
            sphereEntity.SetParent(scaledEntity.GetParentEntity());
            sphereEntity.Spawn();
            return sphereEntity;
        }
        private static void RefreshScaledEntity(BaseEntity scaledEntity, SphereEntity parentSphere) {
            SetupSphereEntity(parentSphere, scaledEntity);
            if (_pluginConfig.HideSpheresAfterResize) {
                foreach (var subscriber in scaledEntity.net.group.subscribers) EntitySubscriptionManager.Instance.InitResized(scaledEntity.net.ID, subscriber.ownerid);
            }
        }
        private static SphereEntity GetParentSphere(BaseEntity entity) => entity.GetParentEntity() as SphereEntity;
        private static BaseEntity GetFirstChild(SphereEntity parentSphere) {
            return parentSphere.children.Count > 0 ? parentSphere.children[0] : null;
        }
        private static void UnparentFromSphere(BaseEntity scaledEntity) {
            var sphereEntity = GetParentSphere(scaledEntity);
            if (sphereEntity == null) return;
            // Unparenting an entity automatically transfers the local scale of the parent to the child.// So we have to invert the local scale of the child to compensate.scaledEntity.transform.localScale /= sphereEntity.currentRadius;
            // If the sphere already has a parent, simply move the entity to it.// Parent is possibly null but that's ok since that will simply unparent.scaledEntity.SetParent(sphereEntity.GetParentEntity(), worldPositionStays: true, sendImmediate: true);
            sphereEntity.Kill();
            EntitySubscriptionManager.Instance.RemoveEntity(scaledEntity.net.ID);
            _pluginData.ScaledEntities.Remove(scaledEntity.net.ID.Value);
        }
        private static bool TryScaleEntity(BaseEntity entity, float scale) {
            if (EntityScaleWasBlocked(entity, scale)) return false;
            var parentSphere = GetParentSphere(entity);
            // Only resize an existing sphere if it's registered.// This allows spheres fully managed by other plugins to remain untouched.if (parentSphere != null && _pluginData.ScaledEntities.Contains(entity.net.ID.Value))
            {
                if (scale == parentSphere.currentRadius) return true;
                NetworkUtils.TerminateOnClient(entity);
                NetworkUtils.TerminateOnClient(parentSphere);
                // Clear the cache in ParentedEntityRenderFix._pluginInstance.ParentedEntityRenderFix?.Call("OnEntityKill", entity);
                // Remove the entity from the subscriber manager to allow clients to resize it.// This could result in a client who is already resizing it to not resize it fully,
                // but that's not worth the trouble to fix.EntitySubscriptionManager.Instance.RemoveEntity(entity.net.ID);
                if (scale == 1) {
                    UnparentFromSphere(entity);
                }
                else {
                    SetSphereSize(parentSphere, scale);
                    // Resend the child as well since it was previously terminated on clients.NetworkUtils.SendUpdateImmediateRecursive(parentSphere);
                }
                Interface.CallHook("OnEntityScaled", entity, scale);
                return true;
            }
            if (scale == 1) return true;
            _pluginData.ScaledEntities.Add(entity.net.ID.Value);
            var entityTransform = entity.transform;
            parentSphere = CreateSphere(entityTransform.localPosition, Quaternion.identity, scale, entity);
            entityTransform.localPosition = Vector3.zero;
            entity.SetParent(parentSphere, worldPositionStays : false, sendImmediate : true);
            Interface.CallHook("OnEntityScaled", entity, scale);
            return true;
        }
#endregion
#region Network Utils
        private static class NetworkUtils {
            public static void TerminateOnClient(BaseNetworkable entity, Connection connection = null) {
                var write = Net.sv.StartWrite();
                write.PacketID(Message.Type.EntityDestroy);
                write.EntityID(entity.net.ID);
                write.UInt8((byte)BaseNetworkable.DestroyMode.None);
                write.Send(connection != null ? new SendInfo(connection) : new SendInfo(entity.net.group.subscribers));
            }
            public static void SendUpdateImmediateRecursive(BaseEntity entity) {
                entity.SendNetworkUpdateImmediate();
                foreach (var child in entity.children) SendUpdateImmediateRecursive(child);
            }
        }
#endregion
#region Network Snapshot Manager
        private abstract class BaseNetworkSnapshotManager {
            private readonly Dictionary<NetworkableId, MemoryStream> _networkCache = new Dictionary<NetworkableId, MemoryStream>();
            public void Clear() {
                _networkCache.Clear();
            }
            public void InvalidateForEntity(NetworkableId entityId) {
                _networkCache.Remove(entityId);
            }
            // Mostly copied from:
            // - `BaseNetworkable.SendAsSnapshot(Connection)`
            // - `BasePlayer.SendEntitySnapshot(BaseNetworkable)`
            public void SendModifiedSnapshot(BaseEntity entity, Connection connection) {
                var write = Net.sv.StartWrite();
                connection.validate.entityUpdates++;
                var saveInfo = new BaseNetworkable.SaveInfo() {
                    forConnection = connection, forDisk = false
                }
                ;
                write.PacketID(Message.Type.Entities);
                write.UInt32(connection.validate.entityUpdates);
                ToStreamForNetwork(entity, write, saveInfo);
                write.Send(new SendInfo(connection));
            }
            // Mostly copied from `BaseNetworkable.ToStream(Stream, SaveInfo)`.private void ToStream(BaseEntity entity, Stream stream, BaseNetworkable.SaveInfo saveInfo)
            {
                using (saveInfo.msg = Facepunch.Pool.Get<ProtoBuf.Entity>()) {
                    entity.Save(saveInfo);
                    Interface.CallHook("OnEntitySaved", entity, saveInfo);
                    HandleOnEntitySaved(entity, saveInfo);
                    saveInfo.msg.ToProto(stream);
                    entity.PostSave(saveInfo);
                }
            }
            // Mostly copied from `BaseNetworkable.ToStreamForNetwork(Stream, SaveInfo)`.private Stream ToStreamForNetwork(BaseEntity entity, Stream stream, BaseNetworkable.SaveInfo saveInfo)
            {
                MemoryStream cachedStream;
                if (!_networkCache.TryGetValue(entity.net.ID, out cachedStream)) {
                    cachedStream = BaseNetworkable.EntityMemoryStreamPool.Count > 0 ? BaseNetworkable.EntityMemoryStreamPool.Dequeue() : new MemoryStream(8);
                    ToStream(entity, cachedStream, saveInfo);
                    _networkCache[entity.net.ID] = cachedStream;
                }
                cachedStream.WriteTo(stream);
                return cachedStream;
            }
            // Handler for modifying save info when building a snapshot.protected abstract void HandleOnEntitySaved(BaseEntity entity, BaseNetworkable.SaveInfo saveInfo);
        }
        private class NetworkSnapshotManager : BaseNetworkSnapshotManager {
            private static NetworkSnapshotManager _instance = new NetworkSnapshotManager();
            public static NetworkSnapshotManager Instance => _instance;
            protected override void HandleOnEntitySaved(BaseEntity entity, BaseNetworkable.SaveInfo saveInfo) {
                var parentSphere = GetParentSphere(entity);
                if (parentSphere == null) return;
                var scale = parentSphere.currentRadius;
                var transform = entity.transform;
                var grandparent = parentSphere.GetParentEntity();
                if (grandparent == null) {
                    saveInfo.msg.parent = null;
                    saveInfo.msg.baseEntity.pos = transform.position;
                    saveInfo.msg.baseEntity.rot = transform.rotation.eulerAngles;
                }
                else {
                    saveInfo.msg.parent.uid = grandparent.net.ID;
                    saveInfo.msg.baseEntity.pos = parentSphere.transform.localPosition;
                }
            }
        }
#endregion
#region Entity Subscription Manager
        private enum ResizeState {
            NeedsResize, Resizing, Resized
        }
        private class EntitySubscriptionManager {
            private static EntitySubscriptionManager _instance = new EntitySubscriptionManager();
            public static EntitySubscriptionManager Instance => _instance;
            // This is used to keep track of which clients are aware of each entity
            // When we expect the client to destroy an entity, we update this state
            private readonly Dictionary<NetworkableId, Dictionary<ulong, ResizeState>> _networkResizeState = new Dictionary<NetworkableId, Dictionary<ulong, ResizeState>>();
            public void Clear() {
                _networkResizeState.Clear();
            }
            private Dictionary<ulong, ResizeState> EnsureEntity(NetworkableId entityId) {
                Dictionary<ulong, ResizeState> clientToResizeState;
                if (!_networkResizeState.TryGetValue(entityId, out clientToResizeState)) {
                    clientToResizeState = new Dictionary<ulong, ResizeState>();
                    _networkResizeState[entityId] = clientToResizeState;
                }
                return clientToResizeState;
            }
            public void InitResized(NetworkableId entityId, ulong userId) {
                EnsureEntity(entityId).Add(userId, ResizeState.Resized);
            }
            public ResizeState GetResizeState(NetworkableId entityId, ulong userId) {
                var clientToResizeState = EnsureEntity(entityId);
                ResizeState resizeState;
                if (clientToResizeState.TryGetValue(userId, out resizeState)) return resizeState;
                clientToResizeState[userId] = ResizeState.Resizing;
                return ResizeState.NeedsResize;
            }
            // Returns true if it was still resizing.// Absence in the data structure indicates the client deleted it.public bool DoneResizing(NetworkableId entityId, ulong userId)
            {
                Dictionary<ulong, ResizeState> clientToResizeState;
                if (!_networkResizeState.TryGetValue(entityId, out clientToResizeState)) return false;
                if (!clientToResizeState.ContainsKey(userId)) return false;
                clientToResizeState[userId] = ResizeState.Resized;
                return true;
            }
            public void RemoveEntitySubscription(NetworkableId entityId, ulong userId) {
                Dictionary<ulong, ResizeState> clientToResizeState;
                if (!_networkResizeState.TryGetValue(entityId, out clientToResizeState)) return;
                clientToResizeState.Remove(userId);
            }
            public void RemoveEntity(NetworkableId entityId) {
                _networkResizeState.Remove(entityId);
            }
            public void RemoveSubscriber(ulong userId) {
                foreach (var entry in _networkResizeState) entry.Value.Remove(userId);
            }
        }
#endregion
#region Data
        private class StoredData {
            [JsonProperty("ScaledEntities")]
            public HashSet<ulong> ScaledEntities = new HashSet<ulong>();
            public static StoredData Load() => Interface.Oxide.DataFileSystem.ReadObject<StoredData>(_pluginInstance.Name) ?? new StoredData();
            public static StoredData Clear() => new StoredData().Save();
            public StoredData Save() {
                Interface.Oxide.DataFileSystem.WriteObject(_pluginInstance.Name, this);
                return this;
            }
        }
#endregion
#region Configuration
        private class Configuration : SerializableConfiguration {
            [JsonProperty("Hide spheres after resize (performance intensive)")]
            public bool HideSpheresAfterResize = false;
        }
        private Configuration GetDefaultConfig() => new Configuration();
#endregion
#region Configuration Boilerplate
        private class SerializableConfiguration {
            public string ToJson() => JsonConvert.SerializeObject(this);
            public Dictionary<string, object> ToDictionary() => JsonHelper.Deserialize(ToJson()) as Dictionary<string, object>;
        }
        private static class JsonHelper {
            public static object Deserialize(string json) => ToObject(JToken.Parse(json));
            private static object ToObject(JToken token) {
                switch (token.Type) {
                    case JTokenType.Object : return token.Children<JProperty>().ToDictionary(prop => prop.Name, prop => ToObject(prop.Value));
                    case JTokenType.Array : return token.Select(ToObject).ToList();
                    default : return ((JValue)token).Value;
                }
            }
        }
        private bool MaybeUpdateConfig(SerializableConfiguration config) {
            var currentWithDefaults = config.ToDictionary();
            var currentRaw = Config.ToDictionary(x => x.Key, x => x.Value);
            return MaybeUpdateConfigDict(currentWithDefaults, currentRaw);
        }
        private bool MaybeUpdateConfigDict(Dictionary<string, object> currentWithDefaults, Dictionary<string, object> currentRaw) {
            bool changed = false;
            foreach (var key in currentWithDefaults.Keys) {
                object currentRawValue;
                if (currentRaw.TryGetValue(key, out currentRawValue)) {
                    var defaultDictValue = currentWithDefaults[key] as Dictionary<string, object>;
                    var currentDictValue = currentRawValue as Dictionary<string, object>;
                    if (defaultDictValue != null) {
                        if (currentDictValue == null) {
                            currentRaw[key] = currentWithDefaults[key];
                            changed = true;
                        }
                        else if (MaybeUpdateConfigDict(defaultDictValue, currentDictValue)) changed = true;
                    }
                }
                else {
                    currentRaw[key] = currentWithDefaults[key];
                    changed = true;
                }
            }
            return changed;
        }
        protected override void LoadDefaultConfig() => _pluginConfig = GetDefaultConfig();
        protected override void LoadConfig() {
            base.LoadConfig();
            try {
                _pluginConfig = Config.ReadObject<Configuration>();
                if (_pluginConfig == null) {
                    throw new JsonException();
                }
                if (MaybeUpdateConfig(_pluginConfig)) {
                    LogWarning("Configuration appears to be outdated; updating and saving");
                    SaveConfig();
                }
            }
            catch (Exception e) {
                LogError(e.Message);
                LogWarning($"Configuration file {Name}.json is invalid; using defaults");
                LoadDefaultConfig();
            }
        }
        protected override void SaveConfig() {
            Log($"Configuration changes saved to {Name}.json");
            Config.WriteObject(_pluginConfig, true);
        }
#endregion
#region Localization
        private string GetMessage(string playerId, string messageName, params object[] args) {
            var message = lang.GetMessage(messageName, this, playerId);
            return args.Length > 0 ? string.Format(message, args) : message;
        }
        private void ChatMessage(BasePlayer player, string messageName, params object[] args) => player.ChatMessage(GetMessage(player.IPlayer, messageName, args));
        private string GetMessage(IPlayer player, string messageName, params object[] args) => GetMessage(player.Id, messageName, args);
        private string GetMessage(BasePlayer player, string messageName, params object[] args) => GetMessage(player.UserIDString, messageName, args);
        private void ReplyToPlayer(IPlayer player, string messageName, params object[] args) => player.Reply(GetMessage(player, messageName, args));
        protected override void LoadDefaultMessages() {
            lang.RegisterMessages(new Dictionary<string, string> {
                ["Error.NoPermission"]
                = "You don't have permission to do that.", ["Error.Syntax"] = "Syntax: {0} <size>", ["Error.NoEntityFound"] = "Error: No entity found.", ["Error.NotTracked"] = "Error: That entity is not tracked by Entity Scale Manager.", ["Error.NotScaled"] = "Error: That entity is not scaled.", ["Error.ScaleBlocked"] = "Error: Another plugin prevented you from scaling that entity to size {0}.", ["Error.CannotMoveWithHiddenSpheres"] = "You may not move resized entities while spheres are configured to be hidden.", ["GetScale.Success"] = "Entity scale is: {0}", ["Scale.Success"] = "Entity was scaled to: {0}",
            }
            , this, "en");
        }
#endregion
    }
}

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

Другие ресурсы пользователя 15FPS

Сверху