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

FREE CopyPaste : 4.2.0 4.2.0

Нет прав для скачивания
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;
#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
 * 
 */
namespace Oxide.Plugins {
    [Info("Copy Paste", "misticos", "4.2.0")]
    [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 Dictionary<string, Stack<List<BaseEntity>>> _lastPastes = new Dictionary<string, Stack<List<BaseEntity>>>();
        private Dictionary<string, SignSize> _signSizes = new Dictionary<string, SignSize> {
            //{"spinner.wheel.deployed", new SignSize(512, 512)},
            {
                "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;
            }
        }
        //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 = "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;
            }
        }
        private void LoadVariables() {
            Config.Settings.DefaultValueHandling = DefaultValueHandling.Populate;
            _config = Config.ReadObject<ConfigData>();
            Config.WriteObject(_config, true);
        }
        protected override void LoadDefaultConfig() {
            var configData = new ConfigData {
                Copy = new ConfigData.CopyOptions(), Paste = new ConfigData.PasteOptions()
            }
            ;
            Config.WriteObject(configData, true);
        }
        //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
            }
            ;
        }
#region API
        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 UndoLoop(HashSet<BaseEntity> entities, IPlayer player, int count = 0) {
            foreach (var storageContainer in entities.OfType<StorageContainer>().Where(x => !x.IsDestroyed)) {
                storageContainer.Kill();
            }
            // 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);
                // Cleanup the hotspot beloning to the node.var ore = p as OreResourceEntity;
                if (ore != null) {
                    ore.CleanupBonus();
                }
                var io = p as IOEntity;
                if (io != null) {
                    io.ClearConnections();
                }
                var autoTurret = p as AutoTurret;
                if (autoTurret != null) {
                    AutoTurret.interferenceUpdateList.Remove(autoTurret);
                }
                if (p != null && !p.IsDestroyed) p.Kill();
            }
            );
            // 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;
            for (var i = 0; i < batchSize; i++) {
                if (checkFrom.Count == 0) break;
                var list = Pool.Get<List<BaseEntity>>();
                try {
                    Vis.Entities(checkFrom.Pop(), copyData.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.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()) {
                    data.Add("wallpaperID", buildingblock.wallpaperID);
                    data.Add("wallpaperHealth", buildingblock.wallpaperHealth);
                }
            }
            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 lights = entity as AdvancedChristmasLights;
            if (lights != null) {
                var lightsPointsList = new List<Dictionary<string, object>>();
                foreach (var lightsPoint in lights.points) {
                    lightsPointsList.Add(new Dictionary<string, object> {
                        {
                            "normal", lightsPoint.normal
                        }
                        , {
                            "point", NormalizePosition(copyData.SourcePos, lightsPoint.point, copyData.RotCor)
                        }
                        , {
                            "slack", lightsPoint.slack
                        }
                        ,
                    }
                    );
                }
                data.Add("points", lightsPointsList);
                data.Add("animationStyle", lights.animationStyle);
            }
            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.Select(y => y.userid).ToList()
                        }
                    }
                    );
                }
                var autoTurret = entity as AutoTurret;
                if (autoTurret != null) {
                    data.Add("autoturret", new Dictionary<string, object> {
                        {
                            "authorizedPlayers", autoTurret.authorizedPlayers.Select(p => p.userid).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 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 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
                        }
                    }
                    );
                }
                data.Add("vendingmachine", new Dictionary<string, object> {
                    {
                        "shopName", vendingMachine.shopName
                    }
                    , {
                        "isBroadcasting", vendingMachine.IsBroadcasting()
                    }
                    , {
                        "sellOrders", sellOrders
                    }
                }
                );
            }
            var ioEntity = entity as IOEntity;
            if (ioEntity.IsValid() && !ioEntity.IsDestroyed) {
                var ioData = new Dictionary<string, object>();
                var inputs = ioEntity.inputs.Select(input => new Dictionary<string, object> {
                    {
                        "connectedID", input.connectedTo.entityRef.uid.Value
                    }
                    , {
                        "connectedToSlot", input.connectedToSlot
                    }
                    , {
                        "niceName", input.niceName
                    }
                    , {
                        "wireColour", input.wireColour
                    }
                    , {
                        "type", (int)input.type
                    }
                }
                ).Cast<object>().ToList();
                ioData.Add("inputs", inputs);
                var outputs = new List<object>();
                foreach (var output in ioEntity.outputs) {
                    var ioConnection = new Dictionary<string, object> {
                        {
                            "connectedID", output.connectedTo.entityRef.uid.Value
                        }
                        , {
                            "connectedToSlot", output.connectedToSlot
                        }
                        , {
                            "niceName", output.niceName
                        }
                        , {
                            "wireColour", output.wireColour
                        }
                        , {
                            "type", (int)output.type
                        }
                        , {
                            "linePoints", output.linePoints?.ToList() ?? new List<Vector3>()
                        }
                        , {
                            "lineAnchors", output.lineAnchors != null ? GetLineAnchors(output.lineAnchors, ioEntity) : new List<object>()
                        }
                        , {
                            "slackLevels", output.slackLevels?.ToList() ?? new List<float>()
                        }
                        ,
                    }
                    ;
                    outputs.Add(ioConnection);
                }
                ioData.Add("outputs", outputs);
                ioData.Add("oldID", ioEntity.net.ID.Value);
                var electricalBranch = ioEntity as ElectricalBranch;
                if (electricalBranch != null) {
                    ioData.Add("branchAmount", electricalBranch.branchAmount);
                }
                var counter = ioEntity as PowerCounter;
                if (counter != null) {
                    ioData.Add("targetNumber", counter.GetTarget());
                    ioData.Add("counterNumber", counter.counterNumber);
                }
                var timerSwitch = ioEntity as TimerSwitch;
                if (timerSwitch != null) {
                    ioData.Add("timerLength", timerSwitch.timerLength);
                }
                var rfBroadcaster = ioEntity as IRFObject;
                if (rfBroadcaster != null) {
                    ioData.Add("frequency", rfBroadcaster.GetFrequency());
                }
                var seismicSensor = ioEntity as SeismicSensor;
                if (seismicSensor != null) {
                    ioData.Add("range", seismicSensor.range);
                }
                var conveyor = ioEntity as IndustrialConveyor;
                if (conveyor != null) {
                    ioData.Add("industrialconveyormode", (int)conveyor.mode);
                    ioData.Add("industrialconveyorfilteritems", SerializeConveyorFilter(conveyor.filterItems));
                }
                var digitalClock = ioEntity as DigitalClock;
                if (digitalClock != null) {
                    var alarms = new List<object>();
                    foreach (var alarm in digitalClock.alarms) {
                        alarms.Add(new Dictionary<string, object> {
                            {
                                "time", alarm.time
                            }
                            , {
                                "active", alarm.active
                            }
                            ,
                        }
                        );
                    }
                    ioData.Add("muted", digitalClock.muted);
                    ioData.Add("alarms", alarms);
                }
                data.Add("IOEntity", ioData);
            }
            if (entity is StorageContainer || entity is Door || (isChild && entity is not IOEntity)) {
                data.Add("oldID", entity.net.ID.Value);
            }
            return data;
        }
        private List<object> GetLineAnchors(IOEntity.LineAnchor[] lineAnchors, IOEntity ioEntity) {
            var anchors = new List<object>();
            foreach (var anchor in lineAnchors) {
                anchors.Add(new Dictionary<string, object> {
                    {
                        "position", new Dictionary<string, object> {
                            {
                                "x", anchor.position.x.ToString()
                            }
                            , {
                                "y", anchor.position.y.ToString()
                            }
                            , {
                                "z", anchor.position.z.ToString()
                            }
                        }
                    }
                    , {
                        "index", anchor.index
                    }
                    , {
                        "boneName", anchor.boneName
                    }
                    , {
                        "entityRefID", anchor.entityRef.uid.Value
                    }
                }
                );
            }
            return anchors;
        }
        private object FindBestHeight(HashSet<Dictionary<string, object>> entities, Vector3 startPos) {
            var maxHeight = 0f;
            foreach (var entity in entities) {
                var prefab = (string)entity["prefabname"];
                if (prefab.Contains("/foundation/") || prefab.Contains("/foundation.triangle/")) {
                    var foundHeight = GetGround((Vector3)entity["position"]);
                    if (foundHeight != null) {
                        var height = (Vector3)foundHeight;
                        if (height.y > maxHeight) maxHeight = height.y;
                    }
                }
            }
            maxHeight += 1f;
            return maxHeight;
        }
        private bool FindRayEntity(Vector3 sourcePos, Vector3 sourceDir, out Vector3 point, out BaseEntity entity, int rayLayer) {
            RaycastHit hitinfo;
            entity = null;
            point = Vector3.zero;
            if (!Physics.Raycast(sourcePos, sourceDir, out hitinfo, 1000f, rayLayer)) return false;
            entity = hitinfo.GetEntity();
            point = hitinfo.point;
            return true;
        }
        private byte[] FixSignage(ISignage iSignage, byte[] imageBytes) {
            var sign = iSignage as Signage;
            if (sign == null || !_signSizes.ContainsKey(sign.ShortPrefabName)) return imageBytes;
            var size = Math.Max(sign.paintableSources.Length, 1);
            if (sign.textureIDs == null || sign.textureIDs.Length != size) {
                Array.Resize(ref sign.textureIDs, size);
            }
            return ImageResize(imageBytes, _signSizes[sign.ShortPrefabName].Width, _signSizes[sign.ShortPrefabName].Height);
        }
        private object GetGround(Vector3 pos) {
            RaycastHit hitInfo;
            pos += new Vector3(0, 100, 0);
            if (Physics.Raycast(pos, Vector3.down, out hitInfo, 200, _groundLayer)) return hitInfo.point;
            return null;
        }
        private int GetItemId(int itemId) {
            if (ReplaceItemId.ContainsKey(itemId)) return ReplaceItemId[itemId];
            return itemId;
        }
        private bool HasAccess(IPlayer player, string permName) {
            return player.IsAdmin || player.HasPermission(permName);
        }
        private byte[] ImageResize(byte[] imageBytes, int width, int height) {
            Bitmap resizedImage = new Bitmap(width, height), sourceImage = new Bitmap(new MemoryStream(imageBytes));
            Graphics.FromImage(resizedImage).DrawImage(sourceImage, new Rectangle(0, 0, width, height), new Rectangle(0, 0, sourceImage.Width, sourceImage.Height), GraphicsUnit.Pixel);
            var ms = new MemoryStream();
            resizedImage.Save(ms, ImageFormat.Png);
            return ms.ToArray();
        }
        private string Lang(string key, string userId = null, params object[] args) => string.Format(lang.GetMessage(key, this, userId), args);
        private Vector3 NormalizePosition(Vector3 initialPos, Vector3 currentPos, float diffRot) {
            var transformedPos = currentPos - initialPos;
            var newX = transformedPos.x * (float)Math.Cos(-diffRot) + transformedPos.z * (float)Math.Sin(-diffRot);
            var newZ = transformedPos.z * (float)Math.Cos(-diffRot) - transformedPos.x * (float)Math.Sin(-diffRot);
            transformedPos.x = newX;
            transformedPos.z = newZ;
            return transformedPos;
        }
        private PasteData Paste(ICollection<Dictionary<string, object>> entities, Dictionary<string, object> protocol, bool ownership, Vector3 startPos, IPlayer player, bool stability, float rotationCorrection, float heightAdj, bool auth, Action callback, Action<BaseEntity> callbackSpawned, string filename, bool checkPlaced, bool enableSaving = true) {
            //Settings
            var isItemReplace = !protocol.ContainsKey("items");
            var eulerRotation = new Vector3(0f, rotationCorrection * Mathf.Rad2Deg, 0f);
            var quaternionRotation = Quaternion.Euler(eulerRotation);
            // Parse VersionNumber
            var version = protocol.ContainsKey("version") ? protocol["version"] as Dictionary<string, object> : null;
            VersionNumber vNumber = default;
            if (version != null) vNumber = new VersionNumber((int)version["Major"], (int)version["Minor"], (int)version["Patch"]);
            var pasteData = new PasteData {
                HeightAdj = heightAdj, IsItemReplace = isItemReplace, Entities = entities, Player = player, BasePlayer = player.Object as BasePlayer, QuaternionRotation = quaternionRotation, StartPos = startPos, Stability = stability, Auth = auth, Ownership = ownership, CallbackFinished = callback, CallbackSpawned = callbackSpawned, Filename = filename, CheckPlaced = checkPlaced, Version = vNumber, EnableSaving = enableSaving
            }
            ;
            NextTick(() => PasteLoop(pasteData));
            return pasteData;
        }
        private void PasteLoop(PasteData pasteData) {
            if (pasteData.Cancelled) {
                UndoLoop(new HashSet<BaseEntity>(pasteData.PastedEntities), pasteData.Player, pasteData.PastedEntities.Count);
                return;
            }
            var entities = pasteData.Entities;
            var todo = entities.Take(_config.PasteBatchSize).ToArray();
            foreach (var data in todo) {
                entities.Remove(data);
                PasteEntity(data, pasteData);
            }
            if (entities.Count > 0) NextTick(() => PasteLoop(pasteData));
            else {
                foreach (var ioData in pasteData.EntityLookup.Values.ToArray()) {
                    ProgressIOEntity(ioData, pasteData);
                }
                foreach (var 
// ... [Code preview truncated due to length. Full source in attached file] ...

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