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

FREE CopyPaste : 4.2.7 4.2.7

Нет прав для скачивания
C#:
//If debug is defined it will add a stopwatch to the paste and copydata which can be used to profile copying and pasting.
// #define DEBUG
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using Facepunch;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using Oxide.Game.Rust.Libraries.Covalence;
using ProtoBuf;
using UnityEngine;
using Graphics = System.Drawing.Graphics;
using WrapMode = System.Drawing.Drawing2D.WrapMode;
#if DEBUG
using System.Diagnostics;
#endif
// ReSharper disable SpecifyACultureInStringConversionExplicitly
/*
 * CREDITS
 *
 * Orange - Saving ContainerIOEntity
 * UIP88 - Turrets fix
 * bsdinis - Wire fix
 * nivex - Ownership option, sign fix
 * bmgjet - Wallpapers, pattern firework, industrial
 * DezLife - CCTV fix
 * Wulf - Skipping 4.1.24 :D
 * MediocratyItself - added sizing/scaling saving feature
 * 
 */
namespace Oxide.Plugins {
    [Info("Copy Paste", "misticos", "4.2.7")]
    [Description("Copy and paste buildings to save them or move them")]
    public class CopyPaste : CovalencePlugin {
        // ReSharper disable once Unity.IncorrectMonoBehaviourInstantiation
        private readonly Item _emptyItem = new Item {
            info = new ItemDefinition()
        }
        ;
        private readonly IPlayer _consolePlayer = new RustConsolePlayer();
        private int _copyLayer = LayerMask.GetMask("Construction", "Prevent Building", "Construction Trigger", "Trigger", "Deployed", "Default", "Ragdoll"), _groundLayer = LayerMask.GetMask("Terrain", "Default"), _rayCopy = LayerMask.GetMask("Construction", "Deployed", "Tree", "Resource", "Prevent Building"), _rayPaste = LayerMask.GetMask("Construction", "Deployed", "Tree", "Terrain", "World", "Water", "Prevent Building");
        private string _copyPermission = "copypaste.copy", _listPermission = "copypaste.list", _pastePermission = "copypaste.paste", _pastebackPermission = "copypaste.pasteback", _undoPermission = "copypaste.undo", _subDirectory = "copypaste/";
        private readonly HashSet<string> _dlcPrefabs = new();
        private readonly HashSet<int> _dlcItemIds = new();
        private readonly HashSet<ulong> _paidSkinIds = new();
        private readonly Dictionary<string, ItemDefinition> _prefabToItemDef = new();
        private readonly Dictionary<ItemDefinition, string> _itemDefToPrefab = new();
        private bool _pasteReady;
        private readonly List<PasteData> _pendingPastes = new();
        private Dictionary<string, Stack<List<BaseEntity>>> _lastPastes = new Dictionary<string, Stack<List<BaseEntity>>>();
        private Dictionary<string, SignSize> _signSizes = new Dictionary<string, SignSize> {
            {
                "photoframe.landscape", new SignSize(320, 240)
            }
            , {
                "photoframe.large", new SignSize(320, 240)
            }
            , {
                "photoframe.portrait", new SignSize(320, 240)
            }
            , {
                "sign.pictureframe.landscape", new SignSize(256, 192)
            }
            , {
                "sign.pictureframe.tall", new SignSize(128, 512)
            }
            , {
                "sign.pictureframe.portrait", new SignSize(205, 256)
            }
            , {
                "sign.pictureframe.xxl", new SignSize(1024, 512)
            }
            , {
                "sign.pictureframe.xl", new SignSize(512, 512)
            }
            , {
                "sign.small.wood", new SignSize(256, 128)
            }
            , {
                "sign.medium.wood", new SignSize(512, 256)
            }
            , {
                "sign.large.wood", new SignSize(512, 256)
            }
            , {
                "sign.huge.wood", new SignSize(1024, 256)
            }
            , {
                "sign.hanging.banner.large", new SignSize(256, 1024)
            }
            , {
                "sign.pole.banner.large", new SignSize(256, 1024)
            }
            , {
                "sign.post.single", new SignSize(256, 128)
            }
            , {
                "sign.post.double", new SignSize(512, 512)
            }
            , {
                "sign.post.town", new SignSize(512, 256)
            }
            , {
                "sign.post.town.roof", new SignSize(512, 256)
            }
            , {
                "sign.hanging", new SignSize(256, 512)
            }
            , {
                "sign.hanging.ornate", new SignSize(512, 256)
            }
            , {
                "sign.neon.xl.animated", new SignSize(256, 256)
            }
            , {
                "sign.neon.xl", new SignSize(256, 256)
            }
            , {
                "sign.neon.125x215.animated", new SignSize(256, 128)
            }
            , {
                "sign.neon.125x215", new SignSize(256, 128)
            }
            , {
                "sign.neon.125x125", new SignSize(128, 128)
            }
            ,
        }
        ;
        private HashSet<Type> ItemModAssociatedEntities = new() {
            typeof(PaintedItemStorageEntity), typeof(PhotoEntity), typeof(SignContent), typeof(HeadEntity), typeof(PagerEntity), typeof(MobileInventoryEntity), typeof(Cassette)
        }
        ;
        private List<BaseEntity.Slot> _checkSlots = new List<BaseEntity.Slot> {
            BaseEntity.Slot.Lock, BaseEntity.Slot.UpperModifier, BaseEntity.Slot.MiddleModifier, BaseEntity.Slot.LowerModifier
        }
        ;
        public enum CopyMechanics {
            Building, Proximity
        }
        private class SignSize {
            public int Width;
            public int Height;
            public SignSize(int width, int height) {
                Width = width;
                Height = height;
            }
        }
        public enum SkinsMode {
            NoSkins = 0, AllSkins = 1, NoPaidSkins = 2, AllowSpecifiedOnly = 3, BlockSpecifiedOnly = 4
        }
        //Config
        private ConfigData _config;
        private class ConfigData {
            [JsonProperty(PropertyName = "Copy Options")]
            public CopyOptions Copy {
                get;
                set;
            }
            [JsonProperty(PropertyName = "Paste Options")]
            public PasteOptions Paste {
                get;
                set;
            }
            [JsonProperty(PropertyName = "Amount of entities to paste per batch. Use to tweak performance impact of pasting")]
            [DefaultValue(15)]
            public int PasteBatchSize = 15;
            [JsonProperty(PropertyName = "Amount of entities to copy per batch. Use to tweak performance impact of copying")]
            [DefaultValue(100)]
            public int CopyBatchSize = 100;
            [JsonProperty(PropertyName = "Amount of entities to undo per batch. Use to tweak performance impact of undoing")]
            [DefaultValue(15)]
            public int UndoBatchSize = 15;
            [JsonProperty(PropertyName = "Prevent These Prefabs From Spawning", ObjectCreationHandling = ObjectCreationHandling.Replace), DefaultValue(typeof(List<string>), "")]
            public List<string> BlockedPrefabs = new();
            [JsonProperty(PropertyName = "Enable data saving feature")]
            [DefaultValue(true)]
            public bool DataSaving = true;
            public class CopyOptions {
                [JsonProperty(PropertyName = "Check radius from each entity (true/false)")]
                [DefaultValue(true)]
                public bool EachToEach {
                    get;
                    set;
                }
                = true;
                [JsonProperty(PropertyName = "Share (true/false)")]
                [DefaultValue(false)]
                public bool Share {
                    get;
                    set;
                }
                = false;
                [JsonProperty(PropertyName = "Tree (true/false)")]
                [DefaultValue(false)]
                public bool Tree {
                    get;
                    set;
                }
                = false;
                [JsonProperty(PropertyName = "Default radius to look for entities from block")]
                [DefaultValue(3.0f)]
                public float Radius {
                    get;
                    set;
                }
                = 3.0f;
            }
            public class PasteOptions {
                [JsonProperty(PropertyName = "Auth (true/false)")]
                [DefaultValue(false)]
                public bool Auth {
                    get;
                    set;
                }
                = false;
                [JsonProperty(PropertyName = "Deployables (true/false)")]
                [DefaultValue(true)]
                public bool Deployables {
                    get;
                    set;
                }
                = true;
                [JsonProperty(PropertyName = "Inventories (true/false)")]
                [DefaultValue(true)]
                public bool Inventories {
                    get;
                    set;
                }
                = true;
                [JsonProperty(PropertyName = "Vending Machines (true/false)")]
                [DefaultValue(true)]
                public bool VendingMachines {
                    get;
                    set;
                }
                = true;
                [JsonProperty(PropertyName = "Stability (true/false)")]
                [DefaultValue(true)]
                public bool Stability {
                    get;
                    set;
                }
                = true;
                [JsonProperty(PropertyName = "EntityOwner (true/false)")]
                [DefaultValue(true)]
                public bool EntityOwner {
                    get;
                    set;
                }
                = true;
                [JsonProperty(PropertyName = "DLC items and deployables (true/false)")]
                [DefaultValue(true)]
                public bool Dlc {
                    get;
                    set;
                }
                = true;
                [JsonProperty(PropertyName = "Skins (0=no skins, 1=all, 2=no paid skins, 3=allow specified only, 4=block specified only)")]
                [DefaultValue((int)CopyPaste.SkinsMode.AllSkins)]
                public int SkinsMode {
                    get;
                    set;
                }
                = (int)CopyPaste.SkinsMode.AllSkins;
                [JsonProperty(PropertyName = "Specified Skins (skin id, like 2601577757, or item shortname for redirected skins, like hazmatsuit.spacesuit)")]
                public List<object> SpecifiedSkins {
                    get;
                    set;
                }
                = new();
                [JsonIgnore]
                public List<ulong> SpecifiedSkinIds = new();
                [JsonIgnore]
                public List<string> SpecifiedSkinRedirects = new();
            }
        }
        private void LoadVariables() {
            Config.Settings.DefaultValueHandling = DefaultValueHandling.Populate;
            _config = Config.ReadObject<ConfigData>();
            _config.BlockedPrefabs ??= new();
            _config.Paste.SpecifiedSkins ??= new();
            if (!IsValidSkinsMode(_config.Paste.SkinsMode)) {
                PrintWarning("Invalid config value specified for 'Skins', resetting to default of 1 (all skins)");
                _config.Paste.SkinsMode = (int)SkinsMode.AllSkins;
            }
            for (var i = 0; i < _config.Paste.SpecifiedSkins.Count; i++) {
                var str = _config.Paste.SpecifiedSkins[i].ToString();
                if (string.IsNullOrEmpty(str)) continue;
                if (UInt64.TryParse(str, out var skinid)) _config.Paste.SpecifiedSkinIds.Add(skinid);
                else if (ItemManager.FindItemDefinition(str) != null) _config.Paste.SpecifiedSkinRedirects.Add(str);
                else PrintWarning($"Ignoring invalid item shortname in 'Specified Skins': {str}");
            }
            Config.WriteObject(_config, true);
        }
        protected override void LoadDefaultConfig() {
            var configData = new ConfigData {
                Copy = new ConfigData.CopyOptions(), Paste = new ConfigData.PasteOptions()
            }
            ;
            Config.WriteObject(configData, true);
        }
        private bool IsValidSkinsMode(int mode) => Enum.IsDefined(typeof(SkinsMode), mode);
        //Hooks
        private void Init() {
            permission.RegisterPermission(_copyPermission, this);
            permission.RegisterPermission(_listPermission, this);
            permission.RegisterPermission(_pastePermission, this);
            permission.RegisterPermission(_pastebackPermission, this);
            permission.RegisterPermission(_undoPermission, this);
            var compiledLangs = new Dictionary<string, Dictionary<string, string>>();
            foreach (var line in _messages) {
                foreach (var translate in line.Value) {
                    if (!compiledLangs.ContainsKey(translate.Key)) compiledLangs[translate.Key] = new Dictionary<string, string>();
                    compiledLangs[translate.Key][line.Key] = translate.Value;
                }
            }
            foreach (var cLangs in compiledLangs) {
                lang.RegisterMessages(cLangs.Value, this, cLangs.Key);
            }
        }
        private void OnServerInitialized() {
            LoadVariables();
            Vis.colBuffer = new Collider[8192 * 16];
            JsonConvert.DefaultSettings = () => new JsonSerializerSettings {
                Formatting = Formatting.Indented, ReferenceLoopHandling = ReferenceLoopHandling.Ignore
            }
            ;
            ProcessItemDefinitions();
        }
        // Heavily influenced by k1lly0u's Player DLC API plugin
        private void ProcessItemDefinitions() {
            if ((Steamworks.SteamInventory.Definitions?.Length ?? 0) == 0) {
                timer.In(3f, ProcessItemDefinitions);
                return;
            }
            const string WORKSHOP_ID = "workshopid";
            foreach (Steamworks.InventoryDef inventoryDef in Steamworks.SteamInventory.Definitions) {
                if (ulong.TryParse(inventoryDef.GetProperty(WORKSHOP_ID), out ulong skinId)) _paidSkinIds.Add(skinId);
            }
            for (int i = 0; i < ItemSkinDirectory.Instance.skins.Length; i++) {
                ItemSkinDirectory.Skin skin = ItemSkinDirectory.Instance.skins[i];
                _paidSkinIds.Add((ulong)skin.id);
            }
            foreach (ItemDefinition itemDef in ItemManager.itemList) {
                string prefabPath = GetPrefabPathFromItemDef(itemDef);
                if (!string.IsNullOrEmpty(prefabPath)) {
                    _prefabToItemDef[prefabPath] = itemDef;
                    _itemDefToPrefab[itemDef] = prefabPath;
                }
                if (IsDlcItem(itemDef)) {
                    _dlcItemIds.Add(itemDef.itemid);
                    if (!string.IsNullOrEmpty(prefabPath)) _dlcPrefabs.Add(prefabPath);
                }
            }
            Puts($"Skin detection initialized: {_paidSkinIds.Count} official skins, {_dlcItemIds.Count} DLC items. Processing {_pendingPastes.Count} queued paste(s).");
            _pasteReady = true;
            for (int i = 0; i < _pendingPastes.Count; i++) {
                var pasteData = _pendingPastes[i];
                timer.Once(i * 0.1f, () => PasteLoop(pasteData));
            }
            _pendingPastes.Clear();
        }
        private string GetPrefabPathFromItemDef(ItemDefinition def) {
            if (def.TryGetComponent<ItemModDeployable>(out var deployable)) return deployable.entityPrefab.resourcePath;
            if (def.TryGetComponent<ItemModEntity>(out var entity)) return entity.entityPrefab.resourcePath;
            if (def.TryGetComponent<ItemModEntityReference>(out var entityRef)) return entityRef.entityPrefab.resourcePath;
            return null;
        }
        public static bool IsDlcItem(ItemDefinition definition) {
            var bp = definition.Blueprint;
            var parent = definition.Parent ?? definition.isRedirectOf;
            var parentBp = parent?.Blueprint;
            return (definition.steamItem is not null && definition.steamItem.id != 0) || (definition.steamDlc is not null && definition.steamDlc.dlcAppID != 0) || (bp is not null && bp.NeedsSteamDLC) || (parentBp is not null && parentBp.NeedsSteamDLC) || definition.isRedirectOf is not null;
        }
        public ulong FilterSkinId(PasteData pasteData, ulong skinId) {
            if (skinId == 0) return skinId;
            return pasteData.SkinsMode switch {
                SkinsMode.NoSkins => 0, SkinsMode.NoPaidSkins when _paidSkinIds.Contains(skinId) => 0, SkinsMode.AllowSpecifiedOnly when !_config.Paste.SpecifiedSkinIds.Contains(skinId) => 0, SkinsMode.BlockSpecifiedOnly when _config.Paste.SpecifiedSkinIds.Contains(skinId) => 0, _ => skinId
            }
            ;
        }
        public bool GetItemDefinitionForPrefab(string prefabPath, out ItemDefinition def, bool useRedirect = true) {
            def = null;
            if (!_prefabToItemDef.TryGetValue(prefabPath, out def)) return false;
            if (useRedirect && def?.isRedirectOf != null) def = def.isRedirectOf;
            return def != null;
        }
        private bool ShouldRedirectForSkinsMode(PasteData pasteData, ItemDefinition itemDef) {
            var useRedirect = pasteData.SkinsMode == SkinsMode.NoSkins || pasteData.SkinsMode == SkinsMode.NoPaidSkins;
            if (pasteData.SkinsMode == SkinsMode.AllowSpecifiedOnly || pasteData.SkinsMode == SkinsMode.BlockSpecifiedOnly) {
                bool isInSpecifiedList = _config.Paste.SpecifiedSkinRedirects.Contains(itemDef.shortname);
                if (pasteData.SkinsMode == SkinsMode.AllowSpecifiedOnly && !isInSpecifiedList) useRedirect = true;
                else if (pasteData.SkinsMode == SkinsMode.BlockSpecifiedOnly && isInSpecifiedList) useRedirect = true;
            }
            return useRedirect;
        }
#region API
        private bool IsPasteReady() => _pasteReady;
        private object TryCopyFromSteamId(ulong userId, string filename, string[] args, Action callback = null) {
            var player = players.FindPlayerById(userId.ToString())?.Object as BasePlayer;
            if (player == null) return Lang("NOT_FOUND_PLAYER");
            RaycastHit hit;
            if (!Physics.Raycast(player.eyes.HeadRay(), out hit, 1000f, _rayCopy)) return Lang("NO_ENTITY_RAY", player.UserIDString);
            var entity = hit.GetEntity();
            if (!entity.IsValid()) return Lang("NO_ENTITY_RAY", player.UserIDString);
            return TryCopy(hit.point, entity.GetNetworkRotation().eulerAngles, filename, DegreeToRadian(player.GetNetworkRotation().eulerAngles.y), args, player.IPlayer, callback);
        }
        private object TryPasteFromSteamId(ulong userId, string filename, string[] args, Action callback = null, Action<BaseEntity> callbackSpawned = null) {
            var player = players.FindPlayerById(userId.ToString())?.Object as BasePlayer;
            if (player == null) return Lang("NOT_FOUND_PLAYER");
            RaycastHit hit;
            if (!Physics.Raycast(player.eyes.HeadRay(), out hit, 1000f, _rayPaste)) return Lang("NO_ENTITY_RAY", player.UserIDString);
            return TryPaste(hit.point, filename, player.IPlayer, DegreeToRadian(player.GetNetworkRotation().eulerAngles.y), args, callback : callback, callbackSpawned : callbackSpawned).Item1;
        }
        private object TryPasteFromVector3(Vector3 pos, float rotationCorrection, string filename, string[] args, Action callback = null, Action<BaseEntity> callbackSpawned = null) {
            return TryPaste(pos, filename, _consolePlayer, rotationCorrection, args, callback : callback, callbackSpawned : callbackSpawned).Item1;
        }
        private ValueTuple<object, Action> TryPasteFromVector3Cancellable(Vector3 pos, float rotationCorrection, string filename, string[] args, Action callback = null, Action<BaseEntity> callbackSpawned = null) {
            var result = TryPaste(pos, filename, _consolePlayer, rotationCorrection, args, callback : callback, callbackSpawned : callbackSpawned);
            var pasteData = result.Item2;
            return new ValueTuple<object, Action>(result.Item1, () => pasteData.Cancelled = true);
        }
#endregion
        //Other methods
        private object CheckCollision(HashSet<Dictionary<string, object>> entities, Vector3 startPos, float radius) {
            foreach (var entityobj in entities) {
                if (Physics.CheckSphere((Vector3)entityobj["position"], radius, _copyLayer)) return Lang("BLOCKING_PASTE");
            }
            return true;
        }
        private bool CheckPlaced(string prefabname, Vector3 pos, Quaternion rot) {
            const float maxDiff = 0.01f;
            var ents = Pool.Get<List<BaseEntity>>();
            try {
                Vis.Entities(pos, maxDiff, ents);
                foreach (var ent in ents) {
                    if (ent.IsDestroyed || ent.PrefabName != prefabname) continue;
                    if (Vector3.Distance(ent.transform.position, pos) > maxDiff) {
                        continue;
                    }
                    if (Vector3.Distance(ent.transform.rotation.eulerAngles, rot.eulerAngles) > maxDiff) {
                        continue;
                    }
                    return true;
                }
                return false;
            }
            finally {
                Pool.FreeUnmanaged(ref ents);
            }
        }
        private void RemoveEntity(BaseEntity entity) {
            if (!entity.IsValid() || entity.IsDestroyed) return;
            // Cleanup the hotspot beloning to the node.
            var ore = entity as OreResourceEntity;
            if (ore != null) {
                ore.CleanupBonus();
            }
            var io = entity as IOEntity;
            if (io != null) {
                io.ClearConnections();
            }
            var autoTurret = entity as AutoTurret;
            if (autoTurret != null) {
                AutoTurret.interferenceUpdateList.Remove(autoTurret);
            }
            entity.Kill();
        }
        private void UndoLoop(HashSet<BaseEntity> entities, IPlayer player, int count = 0) {
            for (var i = entities.Count - 1; i >= 0; i--) {
                var baseEntity = entities.ElementAt(i);
                if (baseEntity is IItemContainerEntity) {
                    RemoveEntity(baseEntity);
                    entities.Remove(baseEntity);
                }
            }
            // Take an amount of entities from the entity list (defined in config) and kill them. Will be repeated for every tick until there are no entities left.
            entities .Take(_config.UndoBatchSize) .ToList() .ForEach(p => {
                entities.Remove(p);
                RemoveEntity(p);
            }
            );
            // If it gets stuck in infinite loop break the loop.
            if (count != 0 && entities.Count != 0 && entities.Count == count) {
                player?.Reply("Undo cancelled because of infinite loop.");
                return;
            }
            if (entities.Count > 0) NextTick(() => UndoLoop(entities, player, entities.Count));
            else if (player != null) {
                player.Reply(Lang("UNDO_SUCCESS", player.Id));
                if (_lastPastes.ContainsKey(player.Id) && _lastPastes[player.Id].Count == 0) _lastPastes.Remove(player.Id);
            }
        }
        private void Copy(Vector3 sourcePos, Vector3 sourceRot, string filename, float rotationCorrection, CopyMechanics copyMechanics, float range, bool saveTree, bool saveShare, bool eachToEach, IPlayer player, Action callback) {
            var currentLayer = _copyLayer;
            if (saveTree) currentLayer |= LayerMask.GetMask("Tree");
            var copyData = new CopyData {
                Filename = filename, CurrentLayer = currentLayer, RotCor = rotationCorrection, Range = range, SaveShare = saveShare, SaveTree = saveTree, CopyMechanics = copyMechanics, EachToEach = eachToEach, SourcePos = sourcePos, SourceRot = sourceRot, Player = player, BasePlayer = player.Object as BasePlayer, Callback = callback
            }
            ;
            copyData.CheckFrom.Push(sourcePos);
            NextTick(() => CopyLoop(copyData));
        }
        // Main loop for copy, will fetch all the data needed. Is called every tick untill copy is done (can't find any entities)
        private void CopyLoop(CopyData copyData) {
            var checkFrom = copyData.CheckFrom;
            var houseList = copyData.HouseList;
            var buildingId = copyData.BuildingId;
            var copyMechanics = copyData.CopyMechanics;
            var batchSize = checkFrom.Count < _config.CopyBatchSize ? checkFrom.Count : _config.CopyBatchSize;
            var range = copyData.Range;
            /*
                BUILDING BLOCK DETECTION FIX:
                Rust building blocks (foundations, walls, etc.) are 3m x 3m. When the plugin's detection range is
                exactly 3.0f (default) and starting from one building block, Vis.Entities() detection extends precisely
                to the edge of adjacent blocks but doesn't cross their boundaries.

                This creates an edge case where connected building blocks aren't always detected (depending on the
                block's grade and or skin) when there are no deployables positioned such that they would fall within 3m
                range of adjacent building blocks (which would otherwise cause those blocks to be detected).

                By adding a tiny amount (0.001f) to the range when it's exactly 3.0f, we ensure Vis.Entities() detection
                slightly overlaps adjacent blocks, properly capturing the entire connected structure without
                significantly changing the intended detection range.
            */
            if (range == 3.0f) range += 0.001f;
            for (var i = 0; i < batchSize; i++) {
                if (checkFrom.Count == 0) break;
                var list = Pool.Get<List<BaseEntity>>();
                try {
                    Vis.Entities(checkFrom.Pop(), range, list, copyData.CurrentLayer);
                    foreach (var entity in list) {
                        // Skip entities that are already in the list
                        if (!entity.IsValid() || entity.HasParent()) continue;
                        // Skip metal detector flags
                        if (entity.GetComponent<MetalDetectorSource>() != null) continue;
                        if (!houseList.Add(entity)) continue;
                        if (copyMechanics == CopyMechanics.Building) {
                            var buildingBlock = entity.GetComponentInParent<BuildingBlock>();
                            if (buildingBlock != null) {
                                if (buildingId == 0) buildingId = buildingBlock.buildingID;
                                if (buildingId != buildingBlock.buildingID) continue;
                            }
                        }
                        var transform = entity.transform;
                        if (copyData.EachToEach) checkFrom.Push(transform.position);
                        if (entity.GetComponent<BaseLock>() != null) continue;
                        copyData.RawData.Add(EntityData(entity, transform.position, transform.rotation.eulerAngles / Mathf.Rad2Deg, copyData));
                    }
                }
                finally {
                    Pool.FreeUnmanaged(ref list);
                }
                copyData.BuildingId = buildingId;
            }
            if (checkFrom.Count > 0) {
                NextTick(() => CopyLoop(copyData));
            }
            else {
                var path = _subDirectory + copyData.Filename;
                var datafile = Interface.Oxide.DataFileSystem.GetFile(path);
                datafile.Clear();
                var sourcePos = copyData.SourcePos;
                datafile["default"] = new Dictionary<string, object> {
                    {
                        "position", new Dictionary<string, object> {
                            {
                                "x", sourcePos.x.ToString()
                            }
                            , {
                                "y", sourcePos.y.ToString()
                            }
                            , {
                                "z", sourcePos.z.ToString()
                            }
                        }
                    }
                    , {
                        "rotationy", copyData.SourceRot.y.ToString()
                    }
                    , {
                        "rotationdiff", copyData.RotCor.ToString()
                    }
                }
                ;
                datafile["entities"] = copyData.RawData;
                datafile["protocol"] = new Dictionary<string, object> {
                    {
                        "items", 2
                    }
                    , {
                        "version", Version
                    }
                }
                ;
                Interface.Oxide.DataFileSystem.SaveDatafile(path);
                copyData.Player.Reply(Lang("COPY_SUCCESS", copyData.Player.Id, copyData.Filename));
                copyData.Callback?.Invoke();
                Interface.CallHook("OnCopyFinished", copyData.RawData, copyData.Filename, copyData.Player, copyData.SourcePos);
            }
        }
        private float DegreeToRadian(float angle) {
            return (float)(Math.PI * angle / 180.0f);
        }
        private Dictionary<string, object> EntityData(BaseEntity entity, Vector3 entPos, Vector3 entRot, CopyData copyData) {
            var normalizedPos = NormalizePosition(copyData.SourcePos, entPos, copyData.RotCor);
            var isChild = entity.HasParent();
            entRot.y -= copyData.RotCor;
            var data = new Dictionary<string, object> {
                {
                    "prefabname", entity.PrefabName
                }
                , {
                    "skinid", entity.skinID
                }
                , {
                    "flags", TryCopyFlags(entity)
                }
                , {
                    "pos", new Dictionary<string, object> {
                        {
                            "x", isChild ? entity.transform.localPosition.x.ToString() : normalizedPos.x.ToString()
                        }
                        , {
                            "y", isChild ? entity.transform.localPosition.y.ToString() : normalizedPos.y.ToString()
                        }
                        , {
                            "z", isChild ? entity.transform.localPosition.z.ToString() : normalizedPos.z.ToString()
                        }
                    }
                }
                , {
                    "rot", new Dictionary<string, object> {
                        {
                            "x", isChild ? entity.transform.localRotation.eulerAngles.x.ToString() : entRot.x.ToString()
                        }
                        , {
                            "y", isChild ? entity.transform.localRotation.eulerAngles.y.ToString() : entRot.y.ToString()
                        }
                        , {
                            "z", isChild ? entity.transform.localRotation.eulerAngles.z.ToString() : entRot.z.ToString()
                        }
                    }
                }
                , {
                    "ownerid", entity.OwnerID
                }
            }
            ;
            if (entity.networkEntityScale) {
                var scale = entity.transform.localScale;
                data.Add("scale", new Dictionary<string, object> {
                    {
                        "x", scale.x.ToString()
                    }
                    , {
                        "y", scale.y.ToString()
                    }
                    , {
                        "z", scale.z.ToString()
                    }
                }
                );
            }
            if (entity.HasParent()) {
                if (entity.parentBone != 0) {
                    data.Add("parentbone", StringPool.Get(entity.parentBone));
                }
                if (GetSlot(entity.GetParentEntity(), entity, out BaseEntity.Slot? theslot) && theslot != null) {
                    data.Add("slot", (int)theslot);
                }
            }
            if (entity.children != null && entity.children.Count > 0) {
                var children = new List<object>();
                foreach (var child in entity.children) {
                    if (!child.IsValid()) continue;
                    children.Add(EntityData(child, child.transform.position, child.transform.rotation.eulerAngles, copyData));
                }
                if(children.Count > 0 ) data.Add("children", children);
            }
            var growableEntity = entity as GrowableEntity;
            if (growableEntity != null) {
                var genes = GrowableGeneEncoding.EncodeGenesToInt(growableEntity.Genes);
                if (genes > 0) {
                    data.Add("genes", genes);
                }
                var perent = growableEntity.GetParentEntity();
                if (perent != null) {
                    data.Add("hasParent", true);
                }
            }
            // TryCopySlots(entity, data, copyData.SaveShare);
            var codeLock = entity.GetComponent<CodeLock>();
            if (codeLock != null) {
                data.Add("code", codeLock.code);
                if (copyData.SaveShare) data.Add("whitelistPlayers", codeLock.whitelistPlayers);
                if (codeLock.guestCode != null && codeLock.guestCode.Length == 4) {
                    data.Add("guestCode", codeLock.guestCode);
                    if (copyData.SaveShare) data.Add("guestPlayers", codeLock.guestPlayers);
                }
            }
            var keyLock = entity.GetComponent<KeyLock>();
            if (keyLock != null) {
                data.Add("code", keyLock.keyCode.ToString());
                data.Add("firstKeyCreated", keyLock.firstKeyCreated);
            }
            var buildingblock = entity as BuildingBlock;
            if (buildingblock != null) {
                data.Add("grade", buildingblock.grade);
                if (buildingblock.customColour != 0) {
                    data.Add("customColour", buildingblock.customColour);
                }
                if (buildingblock.HasWallpaper(0)) {
                    data.Add("wallpaperID", buildingblock.wallpaperID);
                    data.Add("wallpaperHealth", buildingblock.wallpaperHealth);
                    data.Add("wallpaperRotation", buildingblock.wallpaperRotation);
                }
                if (buildingblock.HasWallpaper(1)) {
                    data.Add("wallpaperID2", buildingblock.wallpaperID2);
                    data.Add("wallpaperHealth2", buildingblock.wallpaperHealth2);
                    data.Add("wallpaperRotation2", buildingblock.wallpaperRotation2);
                }
            }
            var container = entity as IItemContainerEntity;
            if (container != null && container.inventory != null) {
                ExtractInventory(data, container.inventory, copyData);
            }
            var iSignage = entity as ISignage;
            if (iSignage != null) {
                ExtractTextures(data, iSignage.GetTextureCRCs(), entity, iSignage.FileType);
            }
            var photoEntity = entity as PhotoEntity;
            if (photoEntity != null) {
                ExtractTextures(data, photoEntity.GetContentCRCs, entity, FileStorage.Type.jpg);
            }
            var photoFrame = entity as PhotoFrame;
            if (photoFrame != null && photoFrame._photoEntity.uid.IsValid) {
                data.Add("photoEntity", photoFrame._photoEntity.uid.Value);
            }
            var signContent = entity as SignContent;
            if (signContent != null) {
                ExtractTextures(data, signContent.GetContentCRCs, entity, signContent.FileType);
            }
            var paintedItemStorageEntity = entity as PaintedItemStorageEntity;
            if (paintedItemStorageEntity != null) {
                ExtractTextures(data, paintedItemStorageEntity.GetContentCRCs, entity, FileStorage.Type.png);
            }
            var shutterFrame = entity as ShutterFrame;
            if (shutterFrame != null) data.Add("isShutterOpen", shutterFrame.IsShutterOpen);
            var ornateFrame = entity as OrnateFrame;
            if (ornateFrame != null) {
                data.Add("frameText", ornateFrame.FrameText);
                data.Add("textColour", SerializeUnityEngineColor(ornateFrame.TextColour));
            }
            var lights = entity as ChristmasLights;
            if (lights != null) {
                data.Add("animationStyle", lights.animationStyle);
            }
            var stringLights = entity as StringLights;
            if (stringLights != null) {
                var lightsPointsList = new List<Dictionary<string, object>>();
                foreach (var pointEntry in stringLights.points) {
                    lightsPointsList.Add(new Dictionary<string, object> {
                        {
                            "normal", pointEntry.normal
                        }
                        , {
                            "point", NormalizePosition(copyData.SourcePos, pointEntry.point, copyData.RotCor)
                        }
                        , {
                            "slack", pointEntry.slack
                        }
                        ,
                    }
                    );
                }
                data.Add("points", lightsPointsList);
            }
            var chandelier = entity as Chandelier;
            if (chandelier != null) {
                data.Add("chandelierLength", chandelier.ChandelierLength);
            }
            var orientableLight = entity as OrientableLight;
            if (orientableLight != null) {
                data.Add("pitchAmount", orientableLight.pitchAmount);
                data.Add("yawAmount", orientableLight.yawAmount);
            }
            var mannequin = entity as Mannequin;
            if (mannequin != null) {
                data.Add("poseIndex", mannequin.PoseIndex);
            }
            var partyBalloon = entity as PartyBalloon;
            if (partyBalloon != null) {
                data.Add("balloonText", partyBalloon.BalloonText);
                data.Add("balloonColour", SerializeUnityEngineColor(partyBalloon.BalloonColour));
                data.Add("textColour", SerializeUnityEngineColor(partyBalloon.TextColour));
            }
            if (copyData.SaveShare) {
                var sleepingBag = entity as SleepingBag;
                if (sleepingBag != null) {
                    data.Add("sleepingbag", new Dictionary<string, object> {
                        {
                            "niceName", sleepingBag.niceName
                        }
                        , {
                            "deployerUserID", sleepingBag.deployerUserID
                        }
                        , {
                            "isPublic", sleepingBag.IsPublic()
                        }
                    }
                    );
                }
                var cupboard = entity as BuildingPrivlidge;
                if (cupboard != null) {
                    data.Add("cupboard", new Dictionary<string, object> {
                        {
                            "authorizedPlayers", cupboard.authorizedPlayers.ToList()
                        }
                    }
                    );
                }
                var autoTurret = entity as AutoTurret;
                if (autoTurret != null) {
                    data.Add("autoturret", new Dictionary<string, object> {
                        {
                            "authorizedPlayers", autoTurret.authorizedPlayers.ToList()
                        }
                    }
                    );
                }
            }
            var firework = entity as PatternFirework;
            if (firework != null && firework?.Design != null && firework?.Design?.stars != null) {
                data.Add("patternfirework", new Dictionary<string, object> {
                    {
                        "editedBy", firework.Design.editedBy
                    }
                    , {
                        "stars", SerializeStarPattern(firework.Design.stars)
                    }
                    ,
                }
                );
            }
            var tinCanAlarm = entity as TinCanAlarm;
            if (tinCanAlarm != null) {
                if (tinCanAlarm.endPoint != Vector3.zero) {
                    data.Add("endPoint", NormalizePosition(copyData.SourcePos, tinCanAlarm.endPoint, copyData.RotCor));
                }
            }
            var cctvRc = entity as CCTV_RC;
            if (cctvRc != null) {
                data.Add("cctv", new Dictionary<string, object> {
                    {
                        "yaw", cctvRc.yawAmount
                    }
                    , {
                        "pitch", cctvRc.pitchAmount
                    }
                    , {
                        "rcIdentifier", cctvRc.rcIdentifier
                    }
                }
                );
            }
            var computerStation = entity as ComputerStation;
            if (computerStation != null) {
                data.Add("bookmarks", computerStation.GenerateControlBookmarkString());
            }
            var wantedPoster = entity as WantedPoster;
            if (wantedPoster != null) {
                data.Add("wantedPoster", new Dictionary<string, object> {
                    {
                        "playerId", wantedPoster.playerId
                    }
                    , {
                        "playerName", wantedPoster.playerName
                    }
                }
                );
            }
            var headEntity = entity as HeadEntity;
            if (headEntity != null) {
                ExtractHeadData(data, headEntity.CurrentTrophyData);
            }
            var huntingTrophy = entity as HuntingTrophy;
            if (huntingTrophy != null) {
                ExtractHeadData(data, huntingTrophy.CurrentTrophyData);
            }
            // Save RF frequencies for non-IOEntity RF objects (IOEntity frequencies are handled separately)
            var rfObject = entity as IRFObject;
            if (rfObject != null && entity is not IOEntity) {
                var frequency = rfObject.GetFrequency();
                if (frequency > 0) data.Add("frequency", frequency);
            }
            var cassette = entity as Cassette;
            if (cassette != null) {
                ExtractCassette(data, cassette);
            }
            var elevator = entity as Elevator;
            if (elevator != null) {
                data.Add("Floor", elevator.Floor);
            }
            var weaponRack = entity as WeaponRack;
            if (weaponRack != null) {
                var gridSlots = new List<object>();
                foreach (var weaponRackGridSlot in weaponRack.gridSlots) {
                    if (weaponRackGridSlot != null && weaponRackGridSlot.Used) {
                        gridSlots.Add(new Dictionary<string, object> {
                            {
                                "GridSlotIndex", weaponRackGridSlot.GridSlotIndex
                            }
                            , {
                                "InventoryIndex", weaponRackGridSlot.InventoryIndex
                            }
                            , {
                                "Rotation", weaponRackGridSlot.Rotation
                            }
                            ,
                        }
                        );
                    }
                }
                data.Add("gridSlots", gridSlots);
            }
            var commandBlock = entity as global : : CommandBlock;
            if (commandBlock != null) {
                data.Add("currentCommand", commandBlock.currentCommand);
                data.Add("lastPlayerID", commandBlock.lastPlayerID);
            }
            var phoneController = entity.GetComponent<PhoneController>();
            if (phoneController != null && phoneController.savedVoicemail != null && phoneController.savedVoicemail.Count > 0) {
                var savedVoicemail = new List<object>();
                foreach (var voicemail in phoneController.savedVoicemail) {
                    var oggByte = FileStorage.server.Get(voicemail.audioId, FileStorage.Type.ogg, entity.net.ID);
                    if (oggByte != null) {
                        savedVoicemail.Add(new Dictionary<string, object> {
                            {
                                "audio", Convert.ToBase64String(oggByte)
                            }
                            , {
                                "userName", voicemail.userName
                            }
                        }
                        );
                    }
                }
                data.Add("savedVoicemail", savedVoicemail);
            }
            var vendingMachine = entity as VendingMachine;
            if (vendingMachine != null) {
                var sellOrders = new List<object>();
                foreach (var vendItem in vendingMachine.sellOrders.sellOrders) {
                    sellOrders.Add(new Dictionary<string, object> {
                        {
                            "itemToSellID", vendItem.itemToSellID
                        }
                        , {
                            "itemToSellAmount", vendItem.itemToSellAmount
                        }
                        , {
                            "currencyID", vendItem.currencyID
                        }
                        , {
                            "currencyAmountPerItem", vendItem.currencyAmountPerItem
                        }
                        , {
                            "inStock", vendItem.inStock
                        }
                        , {
                            "currencyIsBP", vendItem.currencyIsBP
                        }
                        , {
                            "itemToSellIsBP", vendItem.itemToSellIsBP
               
// ... [Code preview truncated due to length. Full source in attached file] ...

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