PlatypusMuerte

counterTestCopyPasteNivexEdit

Nov 24th, 2020
796
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 114.07 KB | None | 0 0
  1. //If debug is defined it will add a stopwatch to the paste and copydata which can be used to profile copying and pasting.
  2. //#define DEBUG
  3.  
  4. using System;
  5. using System.Collections.Generic;
  6. using System.ComponentModel;
  7. using System.Diagnostics;
  8. using System.Drawing;
  9. using System.Drawing.Imaging;
  10. using System.IO;
  11. using System.Linq;
  12. using Facepunch;
  13. using Newtonsoft.Json;
  14. using Oxide.Core;
  15. using ProtoBuf;
  16. using UnityEngine;
  17. using Graphics = System.Drawing.Graphics;
  18.  
  19. /*
  20.  * CREDITS
  21.  *
  22.  * Orange - Saving ContainerIOEntity
  23.  * UIP88 - Turrets fix
  24.  * bsdinis - Wire fix
  25.  * nivex - Ownership option
  26.  *
  27.  */
  28.  
  29. namespace Oxide.Plugins
  30. {
  31.     [Info("Copy Paste", "Reneb & MiRror & Misstake & misticos", "4.1.23")]
  32.     [Description("Copy and paste buildings to save them or move them")]
  33.  
  34.     public class CopyPaste : RustPlugin
  35.     {
  36.         private int _copyLayer =
  37.                 LayerMask.GetMask("Construction", "Prevent Building", "Construction Trigger", "Trigger", "Deployed",
  38.                     "Default", "Ragdoll"),
  39.             _groundLayer = LayerMask.GetMask("Terrain", "Default"),
  40.             _rayCopy = LayerMask.GetMask("Construction", "Deployed", "Tree", "Resource", "Prevent Building"),
  41.             _rayPaste = LayerMask.GetMask("Construction", "Deployed", "Tree", "Terrain", "World", "Water",
  42.                 "Prevent Building");
  43.  
  44.         private string _copyPermission = "copypaste.copy",
  45.             _listPermission = "copypaste.list",
  46.             _pastePermission = "copypaste.paste",
  47.             _pastebackPermission = "copypaste.pasteback",
  48.             _undoPermission = "copypaste.undo",
  49.             _serverId = "Server",
  50.             _subDirectory = "copypaste/";
  51.  
  52.         private Dictionary<string, Stack<List<BaseEntity>>> _lastPastes =
  53.             new Dictionary<string, Stack<List<BaseEntity>>>();
  54.  
  55.         private Dictionary<string, SignSize> _signSizes = new Dictionary<string, SignSize>
  56.         {
  57.             //{"spinner.wheel.deployed", new SignSize(512, 512)},
  58.             {"sign.pictureframe.landscape", new SignSize(256, 128)},
  59.             {"sign.pictureframe.tall", new SignSize(128, 512)},
  60.             {"sign.pictureframe.portrait", new SignSize(128, 256)},
  61.             {"sign.pictureframe.xxl", new SignSize(1024, 512)},
  62.             {"sign.pictureframe.xl", new SignSize(512, 512)},
  63.             {"sign.small.wood", new SignSize(128, 64)},
  64.             {"sign.medium.wood", new SignSize(256, 128)},
  65.             {"sign.large.wood", new SignSize(256, 128)},
  66.             {"sign.huge.wood", new SignSize(512, 128)},
  67.             {"sign.hanging.banner.large", new SignSize(64, 256)},
  68.             {"sign.pole.banner.large", new SignSize(64, 256)},
  69.             {"sign.post.single", new SignSize(128, 64)},
  70.             {"sign.post.double", new SignSize(256, 256)},
  71.             {"sign.post.town", new SignSize(256, 128)},
  72.             {"sign.post.town.roof", new SignSize(256, 128)},
  73.             {"sign.hanging", new SignSize(128, 256)},
  74.             {"sign.hanging.ornate", new SignSize(256, 128)}
  75.         };
  76.  
  77.         private List<BaseEntity.Slot> _checkSlots = new List<BaseEntity.Slot>
  78.         {
  79.             BaseEntity.Slot.Lock,
  80.             BaseEntity.Slot.UpperModifier,
  81.             BaseEntity.Slot.MiddleModifier,
  82.             BaseEntity.Slot.LowerModifier
  83.         };
  84.  
  85.         public enum CopyMechanics
  86.         {
  87.             Building,
  88.             Proximity
  89.         }
  90.  
  91.         private class SignSize
  92.         {
  93.             public int Width;
  94.             public int Height;
  95.  
  96.             public SignSize(int width, int height)
  97.             {
  98.                 Width = width;
  99.                 Height = height;
  100.             }
  101.         }
  102.  
  103.         //Config
  104.  
  105.         private ConfigData _config;
  106.  
  107.         private class ConfigData
  108.         {
  109.             [JsonProperty(PropertyName = "Copy Options")]
  110.             public CopyOptions Copy { get; set; }
  111.  
  112.             [JsonProperty(PropertyName = "Paste Options")]
  113.             public PasteOptions Paste { get; set; }
  114.  
  115.             [JsonProperty(PropertyName =
  116.                 "Amount of entities to paste per batch. Use to tweak performance impact of pasting")]
  117.             [DefaultValue(15)]
  118.             public int PasteBatchSize = 15;
  119.  
  120.             [JsonProperty(PropertyName =
  121.                 "Amount of entities to copy per batch. Use to tweak performance impact of copying")]
  122.             [DefaultValue(100)]
  123.             public int CopyBatchSize = 100;
  124.  
  125.             [JsonProperty(PropertyName =
  126.                 "Amount of entities to undo per batch. Use to tweak performance impact of undoing")]
  127.             [DefaultValue(15)]
  128.             public int UndoBatchSize = 15;
  129.  
  130.             [JsonProperty(PropertyName = "Enable data saving feature")]
  131.             [DefaultValue(true)]
  132.             public bool DataSaving = true;
  133.  
  134.             public class CopyOptions
  135.             {
  136.                 [JsonProperty(PropertyName = "Check radius from each entity (true/false)")]
  137.                 [DefaultValue(true)]
  138.                 public bool EachToEach { get; set; } = true;
  139.  
  140.                 [JsonProperty(PropertyName = "Share (true/false)")]
  141.                 [DefaultValue(false)]
  142.                 public bool Share { get; set; } = false;
  143.  
  144.                 [JsonProperty(PropertyName = "Tree (true/false)")]
  145.                 [DefaultValue(false)]
  146.                 public bool Tree { get; set; } = false;
  147.  
  148.                 [JsonProperty(PropertyName = "Default radius to look for entities from block")]
  149.                 [DefaultValue(3.0f)]
  150.                 public float Radius { get; set; } = 3.0f;
  151.             }
  152.  
  153.             public class PasteOptions
  154.             {
  155.                 [JsonProperty(PropertyName = "Auth (true/false)")]
  156.                 [DefaultValue(false)]
  157.                 public bool Auth { get; set; } = false;
  158.  
  159.                 [JsonProperty(PropertyName = "Deployables (true/false)")]
  160.                 [DefaultValue(true)]
  161.                 public bool Deployables { get; set; } = true;
  162.  
  163.                 [JsonProperty(PropertyName = "Inventories (true/false)")]
  164.                 [DefaultValue(true)]
  165.                 public bool Inventories { get; set; } = true;
  166.  
  167.                 [JsonProperty(PropertyName = "Vending Machines (true/false)")]
  168.                 [DefaultValue(true)]
  169.                 public bool VendingMachines { get; set; } = true;
  170.  
  171.                 [JsonProperty(PropertyName = "Stability (true/false)")]
  172.                 [DefaultValue(true)]
  173.                 public bool Stability { get; set; } = true;
  174.  
  175.                 [JsonProperty(PropertyName = "EntityOwner (true/false)")]
  176.                 [DefaultValue(true)]
  177.                 public bool EntityOwner { get; set; } = true;
  178.             }
  179.         }
  180.  
  181.         private void LoadVariables()
  182.         {
  183.             Config.Settings.DefaultValueHandling = DefaultValueHandling.Populate;
  184.  
  185.             _config = Config.ReadObject<ConfigData>();
  186.  
  187.             Config.WriteObject(_config, true);
  188.         }
  189.  
  190.         protected override void LoadDefaultConfig()
  191.         {
  192.             var configData = new ConfigData
  193.             {
  194.                 Copy = new ConfigData.CopyOptions(),
  195.                 Paste = new ConfigData.PasteOptions()
  196.             };
  197.  
  198.             Config.WriteObject(configData, true);
  199.         }
  200.  
  201.         //Hooks
  202.  
  203.         private void Init()
  204.         {
  205.             permission.RegisterPermission(_copyPermission, this);
  206.             permission.RegisterPermission(_listPermission, this);
  207.             permission.RegisterPermission(_pastePermission, this);
  208.             permission.RegisterPermission(_pastebackPermission, this);
  209.             permission.RegisterPermission(_undoPermission, this);
  210.  
  211.             var compiledLangs = new Dictionary<string, Dictionary<string, string>>();
  212.  
  213.             foreach (var line in _messages)
  214.             {
  215.                 foreach (var translate in line.Value)
  216.                 {
  217.                     if (!compiledLangs.ContainsKey(translate.Key))
  218.                         compiledLangs[translate.Key] = new Dictionary<string, string>();
  219.  
  220.                     compiledLangs[translate.Key][line.Key] = translate.Value;
  221.                 }
  222.             }
  223.  
  224.             foreach (var cLangs in compiledLangs)
  225.             {
  226.                 lang.RegisterMessages(cLangs.Value, this, cLangs.Key);
  227.             }
  228.         }
  229.  
  230.         private void OnServerInitialized()
  231.         {
  232.             LoadVariables();
  233.  
  234.             Vis.colBuffer = new Collider[8192 * 16];
  235.  
  236.             JsonConvert.DefaultSettings = () => new JsonSerializerSettings
  237.             {
  238.                 Formatting = Formatting.Indented,
  239.                 ReferenceLoopHandling = ReferenceLoopHandling.Ignore
  240.             };
  241.         }
  242.  
  243.         #region API
  244.  
  245.         private object TryCopyFromSteamId(ulong userId, string filename, string[] args, Action callback = null)
  246.         {
  247.             var player = BasePlayer.FindByID(userId);
  248.  
  249.             if (player == null)
  250.                 return Lang("NOT_FOUND_PLAYER", userId.ToString());
  251.  
  252.             RaycastHit hit;
  253.  
  254.             if (!Physics.Raycast(player.eyes.HeadRay(), out hit, 1000f, _rayCopy))
  255.                 return Lang("NO_ENTITY_RAY", player.UserIDString);
  256.  
  257.             return TryCopy(hit.point, hit.GetEntity().GetNetworkRotation().eulerAngles, filename,
  258.                 DegreeToRadian(player.GetNetworkRotation().eulerAngles.y), args, player, callback);
  259.         }
  260.  
  261.         private object TryPasteFromSteamId(ulong userId, string filename, string[] args, Action callback = null)
  262.         {
  263.             var player = BasePlayer.FindByID(userId);
  264.  
  265.             if (player == null)
  266.                 return Lang("NOT_FOUND_PLAYER", player.UserIDString);
  267.  
  268.             RaycastHit hit;
  269.  
  270.             if (!Physics.Raycast(player.eyes.HeadRay(), out hit, 1000f, _rayPaste))
  271.                 return Lang("NO_ENTITY_RAY", player.UserIDString);
  272.  
  273.             return TryPaste(hit.point, filename, player, DegreeToRadian(player.GetNetworkRotation().eulerAngles.y),
  274.                 args, callback: callback);
  275.         }
  276.  
  277.         private object TryPasteFromVector3(Vector3 pos, float rotationCorrection, string filename, string[] args,
  278.             Action callback = null)
  279.         {
  280.             return TryPaste(pos, filename, null, rotationCorrection, args, callback: callback);
  281.         }
  282.  
  283.         #endregion
  284.  
  285.         //Other methods
  286.  
  287.         private object CheckCollision(HashSet<Dictionary<string, object>> entities, Vector3 startPos, float radius)
  288.         {
  289.             foreach (var entityobj in entities)
  290.             {
  291.                 if (Physics.CheckSphere((Vector3) entityobj["position"], radius, _copyLayer))
  292.                     return Lang("BLOCKING_PASTE");
  293.             }
  294.  
  295.             return true;
  296.         }
  297.  
  298.         private bool CheckPlaced(string prefabname, Vector3 pos, Quaternion rot)
  299.         {
  300.             const float maxDiff = 0.01f;
  301.  
  302.             var ents = new List<BaseEntity>();
  303.             Vis.Entities(pos, maxDiff, ents);
  304.  
  305.             foreach (var ent in ents)
  306.             {
  307.                 if (ent.PrefabName != prefabname)
  308.                     continue;
  309.  
  310.                 if (Vector3.Distance(ent.transform.position, pos) > maxDiff)
  311.                 {
  312.                     continue;
  313.                 }
  314.  
  315.                 if (Vector3.Distance(ent.transform.rotation.eulerAngles, rot.eulerAngles) > maxDiff)
  316.                 {
  317.                     continue;
  318.                 }
  319.  
  320.                 return true;
  321.             }
  322.  
  323.             return false;
  324.         }
  325.  
  326.         private object CmdPasteBack(BasePlayer player, string[] args)
  327.         {
  328.             var userIdString = (player == null) ? _serverId : player.UserIDString;
  329.  
  330.             if (args.Length < 1)
  331.                 return Lang("SYNTAX_PASTEBACK", userIdString);
  332.  
  333.             var success = TryPasteBack(args[0], player, args.Skip(1).ToArray());
  334.  
  335.             if (success is string)
  336.                 return (string) success;
  337.  
  338.             return true;
  339.         }
  340.  
  341.         private object CmdUndo(string userIdString, string[] args)
  342.         {
  343.             var player = BasePlayer.Find(userIdString);
  344.             if (!_lastPastes.ContainsKey(userIdString))
  345.                 return Lang("NO_PASTED_STRUCTURE", userIdString);
  346.  
  347.             var entities = new HashSet<BaseEntity>(_lastPastes[userIdString].Pop().ToList());
  348.  
  349.             UndoLoop(entities, player);
  350.  
  351.             return true;
  352.         }
  353.  
  354.         private void UndoLoop(HashSet<BaseEntity> entities, BasePlayer player, int count = 0)
  355.         {
  356.             foreach (var storageContainer in entities.OfType<StorageContainer>().Where(x => !x.IsDestroyed))
  357.             {
  358.                 storageContainer.Kill();
  359.             }
  360.  
  361.             // 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.
  362.             entities
  363.                 .Take(_config.UndoBatchSize)
  364.                 .ToList()
  365.                 .ForEach(p =>
  366.                 {
  367.                     entities.Remove(p);
  368.  
  369.                     // Cleanup the hotspot beloning to the node.
  370.                     var ore = p as OreResourceEntity;
  371.                     if (ore != null)
  372.                     {
  373.                         ore.CleanupBonus();
  374.                     }
  375.  
  376.                     if (p != null && !p.IsDestroyed)
  377.                         p.Kill();
  378.                 });
  379.  
  380.             // If it gets stuck in infinite loop break the loop.
  381.             if (count != 0 && entities.Count != 0 && entities.Count == count)
  382.             {
  383.                 if (player != null)
  384.                     SendReply(player, "Undo cancelled because of infinite loop.");
  385.                 else
  386.                     Puts("Undo cancelled because of infinite loop.");
  387.                 return;
  388.             }
  389.  
  390.             if (entities.Count > 0)
  391.                 NextTick(() => UndoLoop(entities, player, entities.Count));
  392.             else
  393.             {
  394.                 if (player != null)
  395.                     SendReply(player, Lang("UNDO_SUCCESS", player.UserIDString));
  396.                 else
  397.                     Puts(Lang("UNDO_SUCCESS"));
  398.  
  399.                 if (_lastPastes[player?.UserIDString ?? _serverId].Count == 0)
  400.                     _lastPastes.Remove(player?.UserIDString ?? _serverId);
  401.             }
  402.         }
  403.  
  404.         private void Copy(Vector3 sourcePos, Vector3 sourceRot, string filename, float rotationCorrection,
  405.             CopyMechanics copyMechanics, float range, bool saveTree, bool saveShare, bool eachToEach, BasePlayer player,
  406.             Action callback)
  407.         {
  408.             var currentLayer = _copyLayer;
  409.  
  410.             if (saveTree)
  411.                 currentLayer |= LayerMask.GetMask("Tree");
  412.  
  413.             var copyData = new CopyData
  414.             {
  415.                 FileName = filename,
  416.                 CurrentLayer = currentLayer,
  417.                 RotCor = rotationCorrection,
  418.                 Range = range,
  419.                 SaveShare = saveShare,
  420.                 SaveTree = saveTree,
  421.                 CopyMechanics = copyMechanics,
  422.                 EachToEach = eachToEach,
  423.                 SourcePos = sourcePos,
  424.                 SourceRot = sourceRot,
  425.                 Player = player,
  426.                 Callback = callback
  427.             };
  428.  
  429.             copyData.CheckFrom.Push(sourcePos);
  430.  
  431.             NextTick(() => CopyLoop(copyData));
  432.             ;
  433.         }
  434.  
  435.         // Main loop for copy, will fetch all the data needed. Is called every tick untill copy is done (can't find any entities)
  436.         private void CopyLoop(CopyData copyData)
  437.         {
  438.             var checkFrom = copyData.CheckFrom;
  439.             var houseList = copyData.HouseList;
  440.             var buildingId = copyData.BuildingId;
  441.             var copyMechanics = copyData.CopyMechanics;
  442.             var batchSize = checkFrom.Count < _config.CopyBatchSize ? checkFrom.Count : _config.CopyBatchSize;
  443.  
  444.             for (var i = 0; i < batchSize; i++)
  445.             {
  446.                 if (checkFrom.Count == 0)
  447.                     break;
  448.  
  449.                 var list = Pool.GetList<BaseEntity>();
  450.                 Vis.Entities(checkFrom.Pop(), copyData.Range, list, copyData.CurrentLayer);
  451.  
  452.                 foreach (var entity in list)
  453.                 {
  454.                     if (!houseList.Add(entity))
  455.                         continue;
  456.  
  457.                     if (copyMechanics == CopyMechanics.Building)
  458.                     {
  459.                         var buildingBlock = entity.GetComponentInParent<BuildingBlock>();
  460.  
  461.                         if (buildingBlock != null)
  462.                         {
  463.                             if (buildingId == 0)
  464.                                 buildingId = buildingBlock.buildingID;
  465.  
  466.                             if (buildingId != buildingBlock.buildingID)
  467.                                 continue;
  468.                         }
  469.                     }
  470.  
  471.                     if (copyData.EachToEach)
  472.                         checkFrom.Push(entity.transform.position);
  473.                     if (entity.GetComponent<BaseLock>() != null)
  474.                         continue;
  475.                     copyData.RawData.Add(EntityData(entity, entity.transform.position,
  476.                         entity.transform.rotation.eulerAngles / 57.29578f, copyData));
  477.                 }
  478.  
  479.                 copyData.BuildingId = buildingId;
  480.             }
  481.  
  482.             if (checkFrom.Count > 0)
  483.             {
  484.                 NextTick(() => CopyLoop(copyData));
  485.             }
  486.             else
  487.             {
  488.                 var path = _subDirectory + copyData.FileName;
  489.                 var datafile = Interface.Oxide.DataFileSystem.GetDatafile(path);
  490.  
  491.                 datafile.Clear();
  492.  
  493.                 var sourcePos = copyData.SourcePos;
  494.  
  495.                 datafile["default"] = new Dictionary<string, object>
  496.                 {
  497.                     {
  498.                         "position", new Dictionary<string, object>
  499.                         {
  500.                             {"x", sourcePos.x.ToString()},
  501.                             {"y", sourcePos.y.ToString()},
  502.                             {"z", sourcePos.z.ToString()}
  503.                         }
  504.                     },
  505.                     {"rotationy", copyData.SourceRot.y.ToString()},
  506.                     {"rotationdiff", copyData.RotCor.ToString()}
  507.                 };
  508.  
  509.                 datafile["entities"] = copyData.RawData;
  510.                 datafile["protocol"] = new Dictionary<string, object>
  511.                 {
  512.                     {"items", 2},
  513.                     {"version", Version}
  514.                 };
  515.  
  516.                 Interface.Oxide.DataFileSystem.SaveDatafile(path);
  517.  
  518.                 SendReply(copyData.Player, Lang("COPY_SUCCESS", copyData.Player.UserIDString, copyData.FileName));
  519.  
  520.                 copyData.Callback?.Invoke();
  521.  
  522.                 Interface.CallHook("OnCopyFinished", copyData.RawData);
  523.             }
  524.         }
  525.  
  526.         private float DegreeToRadian(float angle)
  527.         {
  528.             return (float) (Math.PI * angle / 180.0f);
  529.         }
  530.  
  531.         private Dictionary<string, object> EntityData(BaseEntity entity, Vector3 entPos, Vector3 entRot,
  532.             CopyData copyData)
  533.         {
  534.             var normalizedPos = NormalizePosition(copyData.SourcePos, entPos, copyData.RotCor);
  535.  
  536.             entRot.y -= copyData.RotCor;
  537.  
  538.             var data = new Dictionary<string, object>
  539.             {
  540.                 {"prefabname", entity.PrefabName},
  541.                 {"skinid", entity.skinID},
  542.                 {"flags", TryCopyFlags(entity)},
  543.                 {
  544.                     "pos", new Dictionary<string, object>
  545.                     {
  546.                         {"x", normalizedPos.x.ToString()},
  547.                         {"y", normalizedPos.y.ToString()},
  548.                         {"z", normalizedPos.z.ToString()}
  549.                     }
  550.                 },
  551.                 {
  552.                     "rot", new Dictionary<string, object>
  553.                     {
  554.                         {"x", entRot.x.ToString()},
  555.                         {"y", entRot.y.ToString()},
  556.                         {"z", entRot.z.ToString()}
  557.                     }
  558.                 },
  559.                 {"ownerid", entity.OwnerID}
  560.             };
  561.  
  562.             TryCopySlots(entity, data, copyData.SaveShare);
  563.  
  564.             var buildingblock = entity as BuildingBlock;
  565.  
  566.             if (buildingblock != null)
  567.             {
  568.                 data.Add("grade", buildingblock.grade);
  569.             }
  570.  
  571.             var box = entity as StorageContainer;
  572.             if (box?.inventory != null)
  573.             {
  574.                 var itemlist = new List<object>();
  575.  
  576.                 foreach (var item in box.inventory.itemList)
  577.                 {
  578.                     var itemdata = new Dictionary<string, object>
  579.                     {
  580.                         {"condition", item.condition.ToString()},
  581.                         {"id", item.info.itemid},
  582.                         {"amount", item.amount},
  583.                         {"skinid", item.skin},
  584.                         {"position", item.position},
  585.                         {"blueprintTarget", item.blueprintTarget}
  586.                     };
  587.  
  588.                     if (!string.IsNullOrEmpty(item.text))
  589.                         itemdata["text"] = item.text;
  590.  
  591.                     var heldEnt = item.GetHeldEntity();
  592.  
  593.                     if (heldEnt != null)
  594.                     {
  595.                         var projectiles = heldEnt.GetComponent<BaseProjectile>();
  596.  
  597.                         if (projectiles != null)
  598.                         {
  599.                             var magazine = projectiles.primaryMagazine;
  600.  
  601.                             if (magazine != null)
  602.                             {
  603.                                 itemdata.Add("magazine", new Dictionary<string, object>
  604.                                 {
  605.                                     {magazine.ammoType.itemid.ToString(), magazine.contents}
  606.                                 });
  607.                             }
  608.                         }
  609.                     }
  610.  
  611.                     if (item?.contents?.itemList != null)
  612.                     {
  613.                         var contents = new List<object>();
  614.  
  615.                         foreach (var itemContains in item.contents.itemList)
  616.                         {
  617.                             contents.Add(new Dictionary<string, object>
  618.                             {
  619.                                 {"id", itemContains.info.itemid},
  620.                                 {"amount", itemContains.amount}
  621.                             });
  622.                         }
  623.  
  624.                         itemdata["items"] = contents;
  625.                     }
  626.  
  627.                     itemlist.Add(itemdata);
  628.                 }
  629.  
  630.                 data.Add("items", itemlist);
  631.             }
  632.  
  633.             var box2 = entity as ContainerIOEntity;
  634.             if (box2 != null)
  635.             {
  636.                 var itemlist = new List<object>();
  637.  
  638.                 foreach (var item in box2.inventory.itemList)
  639.                 {
  640.                     var itemdata = new Dictionary<string, object>
  641.                     {
  642.                         {"condition", item.condition.ToString()},
  643.                         {"id", item.info.itemid},
  644.                         {"amount", item.amount},
  645.                         {"skinid", item.skin},
  646.                         {"position", item.position},
  647.                         {"blueprintTarget", item.blueprintTarget}
  648.                     };
  649.  
  650.                     if (!string.IsNullOrEmpty(item.text))
  651.                         itemdata["text"] = item.text;
  652.  
  653.                     var heldEnt = item.GetHeldEntity();
  654.  
  655.                     if (heldEnt != null)
  656.                     {
  657.                         var projectiles = heldEnt.GetComponent<BaseProjectile>();
  658.  
  659.                         if (projectiles != null)
  660.                         {
  661.                             var magazine = projectiles.primaryMagazine;
  662.  
  663.                             if (magazine != null)
  664.                             {
  665.                                 itemdata.Add("magazine", new Dictionary<string, object>
  666.                                 {
  667.                                     {magazine.ammoType.itemid.ToString(), magazine.contents}
  668.                                 });
  669.                             }
  670.                         }
  671.                     }
  672.  
  673.                     if (item?.contents?.itemList != null)
  674.                     {
  675.                         var contents = new List<object>();
  676.  
  677.                         foreach (var itemContains in item.contents.itemList)
  678.                         {
  679.                             contents.Add(new Dictionary<string, object>
  680.                             {
  681.                                 {"id", itemContains.info.itemid},
  682.                                 {"amount", itemContains.amount}
  683.                             });
  684.                         }
  685.  
  686.                         itemdata["items"] = contents;
  687.                     }
  688.  
  689.                     itemlist.Add(itemdata);
  690.                 }
  691.  
  692.                 data.Add("items", itemlist);
  693.             }
  694.  
  695.             var sign = entity as Signage;
  696.             if (sign != null)
  697.             {
  698.                 var imageByte = FileStorage.server.Get(sign.textureID, FileStorage.Type.png, sign.net.ID);
  699.  
  700.                 data.Add("sign", new Dictionary<string, object>
  701.                 {
  702.                     {"locked", sign.IsLocked()}
  703.                 });
  704.  
  705.                 if (sign.textureID > 0 && imageByte != null)
  706.                     ((Dictionary<string, object>) data["sign"]).Add("texture", Convert.ToBase64String(imageByte));
  707.             }
  708.  
  709.             if (copyData.SaveShare)
  710.             {
  711.                 var sleepingBag = entity as SleepingBag;
  712.  
  713.                 if (sleepingBag != null)
  714.                 {
  715.                     data.Add("sleepingbag", new Dictionary<string, object>
  716.                     {
  717.                         {"niceName", sleepingBag.niceName},
  718.                         {"deployerUserID", sleepingBag.deployerUserID},
  719.                         {"isPublic", sleepingBag.IsPublic()}
  720.                     });
  721.                 }
  722.  
  723.                 var cupboard = entity as BuildingPrivlidge;
  724.  
  725.                 if (cupboard != null)
  726.                 {
  727.                     data.Add("cupboard", new Dictionary<string, object>
  728.                     {
  729.                         {"authorizedPlayers", cupboard.authorizedPlayers.Select(y => y.userid).ToList()}
  730.                     });
  731.                 }
  732.  
  733.                 var autoTurret = entity as AutoTurret;
  734.  
  735.                 if (autoTurret != null)
  736.                 {
  737.                     data.Add("autoturret", new Dictionary<string, object>
  738.                     {
  739.                         {"authorizedPlayers", autoTurret.authorizedPlayers.Select(p => p.userid).ToList()}
  740.                     });
  741.                 }
  742.             }
  743.            
  744.             var cctvRC = entity as CCTV_RC;
  745.            
  746.             if (cctvRC != null)
  747.             {
  748.                 data.Add("cctv", new Dictionary<string, object>
  749.                 {
  750.                         {"yaw", cctvRC.yawAmount},
  751.                         {"pitch", cctvRC.pitchAmount},
  752.                         {"rcIdentifier", cctvRC.rcIdentifier}
  753.                 });
  754.             }
  755.  
  756.             var vendingMachine = entity as VendingMachine;
  757.  
  758.             if (vendingMachine != null)
  759.             {
  760.                 var sellOrders = new List<object>();
  761.  
  762.                 foreach (var vendItem in vendingMachine.sellOrders.sellOrders)
  763.                 {
  764.                     sellOrders.Add(new Dictionary<string, object>
  765.                     {
  766.                         {"itemToSellID", vendItem.itemToSellID},
  767.                         {"itemToSellAmount", vendItem.itemToSellAmount},
  768.                         {"currencyID", vendItem.currencyID},
  769.                         {"currencyAmountPerItem", vendItem.currencyAmountPerItem},
  770.                         {"inStock", vendItem.inStock},
  771.                         {"currencyIsBP", vendItem.currencyIsBP},
  772.                         {"itemToSellIsBP", vendItem.itemToSellIsBP}
  773.                     });
  774.                 }
  775.  
  776.                 data.Add("vendingmachine", new Dictionary<string, object>
  777.                 {
  778.                     {"shopName", vendingMachine.shopName},
  779.                     {"isBroadcasting", vendingMachine.IsBroadcasting()},
  780.                     {"sellOrders", sellOrders}
  781.                 });
  782.             }
  783.  
  784.             var ioEntity = entity as IOEntity;
  785.  
  786.             if (ioEntity != null)
  787.             {
  788.                 var ioData = new Dictionary<string, object>();
  789.                 var inputs = ioEntity.inputs.Select(input => new Dictionary<string, object>
  790.                     {
  791.                         {"connectedID", input.connectedTo.entityRef.uid},
  792.                         {"connectedToSlot", input.connectedToSlot},
  793.                         {"niceName", input.niceName},
  794.                         {"type", (int) input.type}
  795.                     })
  796.                     .Cast<object>()
  797.                     .ToList();
  798.  
  799.                 ioData.Add("inputs", inputs);
  800.  
  801.                 var outputs = new List<object>();
  802.                 foreach (var output in ioEntity.outputs)
  803.                 {
  804.                     var ioConnection = new Dictionary<string, object>
  805.                     {
  806.                         {"connectedID", output.connectedTo.entityRef.uid},
  807.                         {"connectedToSlot", output.connectedToSlot},
  808.                         {"niceName", output.niceName},
  809.                         {"type", (int) output.type},
  810.                         {"linePoints", output.linePoints?.ToList() ?? new List<Vector3>()}
  811.                     };
  812.  
  813.                     outputs.Add(ioConnection);
  814.                 }
  815.  
  816.                 ioData.Add("outputs", outputs);
  817.                 ioData.Add("oldID", ioEntity.net.ID);
  818.                 var electricalBranch = ioEntity as ElectricalBranch;
  819.                 if (electricalBranch != null)
  820.                 {
  821.                     ioData.Add("branchAmount", electricalBranch.branchAmount);
  822.                 }
  823.  
  824.                 var counter = ioEntity.GetComponent<PowerCounter>();
  825.                 if (counter != null)
  826.                 {
  827.                     ioData.Add("targetNumber", counter.GetTarget());
  828.                 }
  829.  
  830.                 var timerSwitch = ioEntity as TimerSwitch;
  831.                 if (timerSwitch != null)
  832.                 {
  833.                     ioData.Add("timerLength", timerSwitch.timerLength);
  834.                 }
  835.  
  836.                 var rfBroadcaster = ioEntity as IRFObject;
  837.                 if (rfBroadcaster != null)
  838.                 {
  839.                     ioData.Add("frequency", rfBroadcaster.GetFrequency());
  840.                 }
  841.  
  842.                 data.Add("IOEntity", ioData);
  843.             }
  844.  
  845.             return data;
  846.         }
  847.  
  848.         private object FindBestHeight(HashSet<Dictionary<string, object>> entities, Vector3 startPos)
  849.         {
  850.             var maxHeight = 0f;
  851.  
  852.             foreach (var entity in entities)
  853.             {
  854.                 if (((string) entity["prefabname"]).Contains("/foundation/"))
  855.                 {
  856.                     var foundHeight = GetGround((Vector3) entity["position"]);
  857.  
  858.                     if (foundHeight != null)
  859.                     {
  860.                         var height = (Vector3) foundHeight;
  861.  
  862.                         if (height.y > maxHeight)
  863.                             maxHeight = height.y;
  864.                     }
  865.                 }
  866.             }
  867.  
  868.             maxHeight += 1f;
  869.  
  870.             return maxHeight;
  871.         }
  872.  
  873.         private bool FindRayEntity(Vector3 sourcePos, Vector3 sourceDir, out Vector3 point, out BaseEntity entity,
  874.             int rayLayer)
  875.         {
  876.             RaycastHit hitinfo;
  877.             entity = null;
  878.             point = Vector3.zero;
  879.  
  880.             if (!Physics.Raycast(sourcePos, sourceDir, out hitinfo, 1000f, rayLayer))
  881.                 return false;
  882.  
  883.             entity = hitinfo.GetEntity();
  884.             point = hitinfo.point;
  885.  
  886.             return true;
  887.         }
  888.  
  889.         private void FixSignage(Signage sign, byte[] imageBytes)
  890.         {
  891.             if (!_signSizes.ContainsKey(sign.ShortPrefabName))
  892.                 return;
  893.  
  894.             var resizedImage = ImageResize(imageBytes, _signSizes[sign.ShortPrefabName].Width,
  895.                 _signSizes[sign.ShortPrefabName].Height);
  896.  
  897.             sign.textureID = FileStorage.server.Store(resizedImage, FileStorage.Type.png, sign.net.ID);
  898.         }
  899.  
  900.         private object GetGround(Vector3 pos)
  901.         {
  902.             RaycastHit hitInfo;
  903.             pos += new Vector3(0, 100, 0);
  904.  
  905.             if (Physics.Raycast(pos, Vector3.down, out hitInfo, 200, _groundLayer))
  906.                 return hitInfo.point;
  907.  
  908.             return null;
  909.         }
  910.  
  911.         private int GetItemId(int itemId)
  912.         {
  913.             if (ReplaceItemId.ContainsKey(itemId))
  914.                 return ReplaceItemId[itemId];
  915.  
  916.             return itemId;
  917.         }
  918.  
  919.         private bool HasAccess(BasePlayer player, string permName)
  920.         {
  921.             return player.IsAdmin || permission.UserHasPermission(player.UserIDString, permName);
  922.         }
  923.  
  924.         private byte[] ImageResize(byte[] imageBytes, int width, int height)
  925.         {
  926.             Bitmap resizedImage = new Bitmap(width, height),
  927.                 sourceImage = new Bitmap(new MemoryStream(imageBytes));
  928.  
  929.             Graphics.FromImage(resizedImage).DrawImage(sourceImage, new Rectangle(0, 0, width, height),
  930.                 new Rectangle(0, 0, sourceImage.Width, sourceImage.Height), GraphicsUnit.Pixel);
  931.  
  932.             var ms = new MemoryStream();
  933.             resizedImage.Save(ms, ImageFormat.Png);
  934.  
  935.             return ms.ToArray();
  936.         }
  937.  
  938.         private string Lang(string key, string userId = null, params object[] args) =>
  939.             string.Format(lang.GetMessage(key, this, userId), args);
  940.  
  941.         private Vector3 NormalizePosition(Vector3 initialPos, Vector3 currentPos, float diffRot)
  942.         {
  943.             var transformedPos = currentPos - initialPos;
  944.             var newX = (transformedPos.x * (float) Math.Cos(-diffRot)) +
  945.                        (transformedPos.z * (float) Math.Sin(-diffRot));
  946.             var newZ = (transformedPos.z * (float) Math.Cos(-diffRot)) -
  947.                        (transformedPos.x * (float) Math.Sin(-diffRot));
  948.  
  949.             transformedPos.x = newX;
  950.             transformedPos.z = newZ;
  951.  
  952.             return transformedPos;
  953.         }
  954.  
  955.         private void Paste(ICollection<Dictionary<string, object>> entities, Dictionary<string, object> protocol,
  956.             bool ownership, Vector3 startPos, BasePlayer player, bool stability, float rotationCorrection,
  957.             float heightAdj, bool auth, Action callback)
  958.         {
  959.  
  960.             var ioEntities = new Dictionary<uint, Dictionary<string, object>>();
  961.             uint buildingId = 0;
  962.  
  963.             //Settings
  964.  
  965.             var isItemReplace = !protocol.ContainsKey("items");
  966.  
  967.             var eulerRotation = new Vector3(0f, rotationCorrection * 57.2958f, 0f);
  968.             var quaternionRotation = Quaternion.Euler(eulerRotation);
  969.  
  970.             var pasteData = new PasteData
  971.             {
  972.                 HeightAdj = heightAdj,
  973.                 IsItemReplace = isItemReplace,
  974.                 Entities = entities,
  975.                 Player = player,
  976.                 QuaternionRotation = quaternionRotation,
  977.                 StartPos = startPos,
  978.                 Stability = stability,
  979.                 Auth = auth,
  980.                 Ownership = ownership,
  981.                 Callback = callback
  982.             };
  983.  
  984.             NextTick(() => PasteLoop(pasteData));
  985.         }
  986.  
  987.         private void PasteLoop(PasteData pasteData)
  988.         {
  989.             var entities = pasteData.Entities;
  990.             var todo = entities.Take(_config.PasteBatchSize).ToArray();
  991.             var player = pasteData.Player;
  992.  
  993.             foreach (var data in todo)
  994.             {
  995.                 entities.Remove(data);
  996.                 var prefabname = (string) data["prefabname"];
  997.                 var skinid = ulong.Parse(data["skinid"].ToString());
  998.                 var pos = (Vector3) data["position"];
  999.                 var rot = (Quaternion) data["rotation"];
  1000.  
  1001.                 var ownerId = player?.userID ?? 0;
  1002.                 if (data.ContainsKey("ownerid"))
  1003.                 {
  1004.                     ownerId = Convert.ToUInt64(data["ownerid"]);
  1005.                 }
  1006.  
  1007.                 if (CheckPlaced(prefabname, pos, rot))
  1008.                     continue;
  1009.  
  1010.                 if (prefabname.Contains("pillar"))
  1011.                     continue;
  1012.  
  1013.                 // Used to copy locks for no reason in previous versions (is included in the slots info so no need to copy locks) so just skipping them.
  1014.                 if (prefabname.Contains("locks"))
  1015.                     continue;
  1016.  
  1017.                 var entity = GameManager.server.CreateEntity(prefabname, pos, rot);
  1018.  
  1019.                 if (entity == null)
  1020.                     continue;
  1021.  
  1022.                 entity.transform.position = pos;
  1023.                 entity.transform.rotation = rot;
  1024.  
  1025.                 if (player != null)
  1026.                     entity.SendMessage("SetDeployedBy", player, SendMessageOptions.DontRequireReceiver);
  1027.  
  1028.                 if (pasteData.Ownership)
  1029.                     entity.OwnerID = ownerId;
  1030.  
  1031.                 var buildingBlock = entity as BuildingBlock;
  1032.  
  1033.                 if (buildingBlock != null)
  1034.                 {
  1035.                     buildingBlock.blockDefinition = PrefabAttribute.server.Find<Construction>(buildingBlock.prefabID);
  1036.                     buildingBlock.SetGrade((BuildingGrade.Enum) data["grade"]);
  1037.                     if (!pasteData.Stability)
  1038.                         buildingBlock.grounded = true;
  1039.  
  1040.                 }
  1041.  
  1042.                 var decayEntity = entity as DecayEntity;
  1043.  
  1044.                 if (decayEntity != null)
  1045.                 {
  1046.                     if (pasteData.BuildingId == 0)
  1047.                         pasteData.BuildingId = BuildingManager.server.NewBuildingID();
  1048.  
  1049.                     decayEntity.AttachToBuilding(pasteData.BuildingId);
  1050.                 }
  1051.  
  1052.                 var stabilityEntity = entity as StabilityEntity;
  1053.  
  1054.                 if (stabilityEntity != null)
  1055.                 {
  1056.                     if (!stabilityEntity.grounded)
  1057.                     {
  1058.                         stabilityEntity.grounded = true;
  1059.                         pasteData.StabilityEntities.Add(stabilityEntity);
  1060.                     }
  1061.                 }
  1062.  
  1063.                 entity.skinID = skinid;
  1064.                 entity.Spawn();
  1065.  
  1066.                 var baseCombat = entity as BaseCombatEntity;
  1067.  
  1068.                 if (baseCombat != null)
  1069.                     baseCombat.SetHealth(baseCombat.MaxHealth());
  1070.  
  1071.                 pasteData.PastedEntities.AddRange(TryPasteSlots(entity, data, pasteData));
  1072.  
  1073.                 var box = entity as StorageContainer;
  1074.                 if (box != null)
  1075.                 {
  1076.                     box.inventory.Clear();
  1077.  
  1078.                     var items = new List<object>();
  1079.  
  1080.                     if (data.ContainsKey("items"))
  1081.                         items = data["items"] as List<object>;
  1082.  
  1083.                     foreach (var itemDef in items)
  1084.                     {
  1085.                         var item = itemDef as Dictionary<string, object>;
  1086.                         var itemid = Convert.ToInt32(item["id"]);
  1087.                         var itemamount = Convert.ToInt32(item["amount"]);
  1088.                         var itemskin = ulong.Parse(item["skinid"].ToString());
  1089.                         var itemcondition = Convert.ToSingle(item["condition"]);
  1090.  
  1091.                         if (pasteData.IsItemReplace)
  1092.                             itemid = GetItemId(itemid);
  1093.  
  1094.                         var i = ItemManager.CreateByItemID(itemid, itemamount, itemskin);
  1095.  
  1096.                         if (i != null)
  1097.                         {
  1098.                             i.condition = itemcondition;
  1099.  
  1100.                             if (item.ContainsKey("text"))
  1101.                                 i.text = item["text"].ToString();
  1102.  
  1103.                             if (item.ContainsKey("blueprintTarget"))
  1104.                             {
  1105.                                 var blueprintTarget = Convert.ToInt32(item["blueprintTarget"]);
  1106.  
  1107.                                 if (pasteData.IsItemReplace)
  1108.                                     blueprintTarget = GetItemId(blueprintTarget);
  1109.  
  1110.                                 i.blueprintTarget = blueprintTarget;
  1111.                             }
  1112.  
  1113.                             if (item.ContainsKey("magazine"))
  1114.                             {
  1115.                                 var heldent = i.GetHeldEntity();
  1116.  
  1117.                                 if (heldent != null)
  1118.                                 {
  1119.                                     var projectiles = heldent.GetComponent<BaseProjectile>();
  1120.  
  1121.                                     if (projectiles != null)
  1122.                                     {
  1123.                                         var magazine = item["magazine"] as Dictionary<string, object>;
  1124.                                         var ammotype = int.Parse(magazine.Keys.ToArray()[0]);
  1125.                                         var ammoamount = int.Parse(magazine[ammotype.ToString()].ToString());
  1126.  
  1127.                                         if (pasteData.IsItemReplace)
  1128.                                             ammotype = GetItemId(ammotype);
  1129.  
  1130.                                         projectiles.primaryMagazine.ammoType = ItemManager.FindItemDefinition(ammotype);
  1131.                                         projectiles.primaryMagazine.contents = ammoamount;
  1132.                                     }
  1133.  
  1134.                                     //TODO Doesn't add water to some containers
  1135.  
  1136.                                     if (item.ContainsKey("items"))
  1137.                                     {
  1138.                                         var itemContainsList = item["items"] as List<object>;
  1139.  
  1140.                                         foreach (var itemContains in itemContainsList)
  1141.                                         {
  1142.                                             var contents = itemContains as Dictionary<string, object>;
  1143.  
  1144.                                             var contentsItemId = Convert.ToInt32(contents["id"]);
  1145.  
  1146.                                             if (pasteData.IsItemReplace)
  1147.                                                 contentsItemId = GetItemId(contentsItemId);
  1148.  
  1149.                                             i.contents.AddItem(ItemManager.FindItemDefinition(contentsItemId),
  1150.                                                 Convert.ToInt32(contents["amount"]));
  1151.                                         }
  1152.                                     }
  1153.                                 }
  1154.                             }
  1155.  
  1156.                             var targetPos = -1;
  1157.  
  1158.                             if (item.ContainsKey("position"))
  1159.                                 targetPos = Convert.ToInt32(item["position"]);
  1160.  
  1161.                             i.position = targetPos;
  1162.                             box.inventory.Insert(i);
  1163.                         }
  1164.                     }
  1165.                 }
  1166.  
  1167.                 var autoTurret = entity as AutoTurret;
  1168.                 if (autoTurret != null)
  1169.                 {
  1170.                     var authorizedPlayers = new List<ulong>();
  1171.  
  1172.                     if (data.ContainsKey("autoturret"))
  1173.                     {
  1174.                         var autoTurretData = data["autoturret"] as Dictionary<string, object>;
  1175.                         authorizedPlayers = (autoTurretData["authorizedPlayers"] as List<object>)
  1176.                             .Select(Convert.ToUInt64).ToList();
  1177.                     }
  1178.  
  1179.                     if (player != null && !authorizedPlayers.Contains(player.userID) && pasteData.Auth)
  1180.                         authorizedPlayers.Add(player.userID);
  1181.  
  1182.                     foreach (var userId in authorizedPlayers)
  1183.                     {
  1184.                         autoTurret.authorizedPlayers.Add(new PlayerNameID
  1185.                         {
  1186.                             userid = Convert.ToUInt64(userId),
  1187.                             username = "Player"
  1188.                         });
  1189.                     }
  1190.  
  1191.                     autoTurret.SendNetworkUpdate();
  1192.                 }
  1193.  
  1194.                 var containerIo = entity as ContainerIOEntity;
  1195.                 if (containerIo != null)
  1196.                 {
  1197.                     containerIo.inventory.Clear();
  1198.  
  1199.                     var items = new List<object>();
  1200.  
  1201.                     if (data.ContainsKey("items"))
  1202.                         items = data["items"] as List<object>;
  1203.  
  1204.                     foreach (var itemDef in items)
  1205.                     {
  1206.                         var itemJson = itemDef as Dictionary<string, object>;
  1207.                         var itemid = Convert.ToInt32(itemJson["id"]);
  1208.                         var itemamount = Convert.ToInt32(itemJson["amount"]);
  1209.                         var itemskin = ulong.Parse(itemJson["skinid"].ToString());
  1210.                         var itemcondition = Convert.ToSingle(itemJson["condition"]);
  1211.  
  1212.                         if (pasteData.IsItemReplace)
  1213.                             itemid = GetItemId(itemid);
  1214.  
  1215.                         var item = ItemManager.CreateByItemID(itemid, itemamount, itemskin);
  1216.  
  1217.                         if (item != null)
  1218.                         {
  1219.                             item.condition = itemcondition;
  1220.  
  1221.                             if (itemJson.ContainsKey("text"))
  1222.                                 item.text = itemJson["text"].ToString();
  1223.  
  1224.                             if (itemJson.ContainsKey("blueprintTarget"))
  1225.                             {
  1226.                                 var blueprintTarget = Convert.ToInt32(itemJson["blueprintTarget"]);
  1227.  
  1228.                                 if (pasteData.IsItemReplace)
  1229.                                     blueprintTarget = GetItemId(blueprintTarget);
  1230.  
  1231.                                 item.blueprintTarget = blueprintTarget;
  1232.                             }
  1233.  
  1234.                             if (itemJson.ContainsKey("magazine"))
  1235.                             {
  1236.                                 var heldent = item.GetHeldEntity();
  1237.  
  1238.                                 if (heldent != null)
  1239.                                 {
  1240.                                     var projectiles = heldent.GetComponent<BaseProjectile>();
  1241.  
  1242.                                     if (projectiles != null)
  1243.                                     {
  1244.                                         var magazine = itemJson["magazine"] as Dictionary<string, object>;
  1245.                                         var ammotype = int.Parse(magazine.Keys.ToArray()[0]);
  1246.                                         var ammoamount = int.Parse(magazine[ammotype.ToString()].ToString());
  1247.  
  1248.                                         if (pasteData.IsItemReplace)
  1249.                                             ammotype = GetItemId(ammotype);
  1250.  
  1251.                                         projectiles.primaryMagazine.ammoType = ItemManager.FindItemDefinition(ammotype);
  1252.                                         projectiles.primaryMagazine.contents = ammoamount;
  1253.                                     }
  1254.  
  1255.                                     //TODO Doesn't add water to some containers
  1256.  
  1257.                                     if (itemJson.ContainsKey("items"))
  1258.                                     {
  1259.                                         var itemContainsList = itemJson["items"] as List<object>;
  1260.  
  1261.                                         foreach (var itemContains in itemContainsList)
  1262.                                         {
  1263.                                             var contents = itemContains as Dictionary<string, object>;
  1264.  
  1265.                                             var contentsItemId = Convert.ToInt32(contents["id"]);
  1266.  
  1267.                                             if (pasteData.IsItemReplace)
  1268.                                                 contentsItemId = GetItemId(contentsItemId);
  1269.  
  1270.                                             item.contents.AddItem(ItemManager.FindItemDefinition(contentsItemId),
  1271.                                                 Convert.ToInt32(contents["amount"]));
  1272.                                         }
  1273.                                     }
  1274.                                 }
  1275.                             }
  1276.  
  1277.                             var targetPos = -1;
  1278.                             if (itemJson.ContainsKey("position"))
  1279.                                 targetPos = Convert.ToInt32(itemJson["position"]);
  1280.  
  1281.                             item.position = targetPos;
  1282.                             containerIo.inventory.Insert(item);
  1283.                         }
  1284.                     }
  1285.  
  1286.                     if (autoTurret != null)
  1287.                     {
  1288.                         autoTurret.Invoke(autoTurret.UpdateAttachedWeapon, 0.5f);
  1289.                     }
  1290.  
  1291.                     containerIo.SendNetworkUpdate();
  1292.                 }
  1293.  
  1294.                 var sign = entity as Signage;
  1295.                 if (sign != null && data.ContainsKey("sign"))
  1296.                 {
  1297.                     var signData = data["sign"] as Dictionary<string, object>;
  1298.  
  1299.                     if (signData.ContainsKey("texture"))
  1300.                     {
  1301.                         var imageBytes = Convert.FromBase64String(signData["texture"].ToString());
  1302.  
  1303.                         FixSignage(sign, imageBytes);
  1304.                     }
  1305.  
  1306.                     if (Convert.ToBoolean(signData["locked"]))
  1307.                         sign.SetFlag(BaseEntity.Flags.Locked, true);
  1308.  
  1309.                     sign.SendNetworkUpdate();
  1310.                 }
  1311.  
  1312.                 var sleepingBag = entity as SleepingBag;
  1313.                 if (sleepingBag != null && data.ContainsKey("sleepingbag"))
  1314.                 {
  1315.                     var bagData = data["sleepingbag"] as Dictionary<string, object>;
  1316.  
  1317.                     sleepingBag.niceName = bagData["niceName"].ToString();
  1318.                     sleepingBag.deployerUserID = ulong.Parse(bagData["deployerUserID"].ToString());
  1319.                     sleepingBag.SetPublic(Convert.ToBoolean(bagData["isPublic"]));
  1320.                 }
  1321.  
  1322.                 var cupboard = entity as BuildingPrivlidge;
  1323.                 if (cupboard != null)
  1324.                 {
  1325.                     var authorizedPlayers = new List<ulong>();
  1326.  
  1327.                     if (data.ContainsKey("cupboard"))
  1328.                     {
  1329.                         var cupboardData = data["cupboard"] as Dictionary<string, object>;
  1330.                         authorizedPlayers = (cupboardData["authorizedPlayers"] as List<object>).Select(Convert.ToUInt64)
  1331.                             .ToList();
  1332.                     }
  1333.  
  1334.                     if (player != null && !authorizedPlayers.Contains(player.userID) && pasteData.Auth)
  1335.                         authorizedPlayers.Add(player.userID);
  1336.  
  1337.                     foreach (var userId in authorizedPlayers)
  1338.                     {
  1339.                         cupboard.authorizedPlayers.Add(new PlayerNameID
  1340.                         {
  1341.                             userid = Convert.ToUInt64(userId),
  1342.                             username = "Player"
  1343.                         });
  1344.                     }
  1345.  
  1346.                     cupboard.SendNetworkUpdate();
  1347.                 }
  1348.                
  1349.                 var cctv_RC = entity as CCTV_RC;
  1350.  
  1351.                 if (cctv_RC != null && data.ContainsKey("cctv"))
  1352.                 {
  1353.                     var cctv = (Dictionary<string, object>)data["cctv"];
  1354.                     cctv_RC.yawAmount = Convert.ToSingle(cctv["yaw"]);
  1355.                     cctv_RC.pitchAmount = Convert.ToSingle(cctv["pitch"]);
  1356.                     cctv_RC.rcIdentifier = cctv["rcIdentifier"].ToString();
  1357.                     cctv_RC.SendNetworkUpdate(BasePlayer.NetworkQueue.Update);
  1358.                 }
  1359.  
  1360.                 var vendingMachine = entity as VendingMachine;
  1361.                 if (vendingMachine != null && data.ContainsKey("vendingmachine"))
  1362.                 {
  1363.                     var vendingData = data["vendingmachine"] as Dictionary<string, object>;
  1364.  
  1365.                     vendingMachine.shopName = vendingData["shopName"].ToString();
  1366.                     vendingMachine.SetFlag(BaseEntity.Flags.Reserved4,
  1367.                         Convert.ToBoolean(vendingData["isBroadcasting"]));
  1368.  
  1369.                     var sellOrders = vendingData["sellOrders"] as List<object>;
  1370.  
  1371.                     foreach (var orderPreInfo in sellOrders)
  1372.                     {
  1373.                         var orderInfo = orderPreInfo as Dictionary<string, object>;
  1374.  
  1375.                         if (!orderInfo.ContainsKey("inStock"))
  1376.                         {
  1377.                             orderInfo["inStock"] = 0;
  1378.                             orderInfo["currencyIsBP"] = false;
  1379.                             orderInfo["itemToSellIsBP"] = false;
  1380.                         }
  1381.  
  1382.                         int itemToSellId = Convert.ToInt32(orderInfo["itemToSellID"]),
  1383.                             currencyId = Convert.ToInt32(orderInfo["currencyID"]);
  1384.  
  1385.                         if (pasteData.IsItemReplace)
  1386.                         {
  1387.                             itemToSellId = GetItemId(itemToSellId);
  1388.                             currencyId = GetItemId(currencyId);
  1389.                         }
  1390.  
  1391.                         vendingMachine.sellOrders.sellOrders.Add(new ProtoBuf.VendingMachine.SellOrder
  1392.                         {
  1393.                             ShouldPool = false,
  1394.                             itemToSellID = itemToSellId,
  1395.                             itemToSellAmount = Convert.ToInt32(orderInfo["itemToSellAmount"]),
  1396.                             currencyID = currencyId,
  1397.                             currencyAmountPerItem = Convert.ToInt32(orderInfo["currencyAmountPerItem"]),
  1398.                             inStock = Convert.ToInt32(orderInfo["inStock"]),
  1399.                             currencyIsBP = Convert.ToBoolean(orderInfo["currencyIsBP"]),
  1400.                             itemToSellIsBP = Convert.ToBoolean(orderInfo["itemToSellIsBP"])
  1401.                         });
  1402.                     }
  1403.  
  1404.                     vendingMachine.FullUpdate();
  1405.                 }
  1406.  
  1407.                 var ioEntity = entity as IOEntity;
  1408.  
  1409.                 if (ioEntity != null)
  1410.                 {
  1411.                     var ioData = new Dictionary<string, object>();
  1412.  
  1413.                     if (data.ContainsKey("IOEntity"))
  1414.                     {
  1415.                         ioData = data["IOEntity"] as Dictionary<string, object> ?? new Dictionary<string, object>();
  1416.                     }
  1417.  
  1418.                     ioData.Add("entity", ioEntity);
  1419.                     ioData.Add("newId", ioEntity.net.ID);
  1420.  
  1421.                     object oldIdObject = 0;
  1422.                     if (ioData.TryGetValue("oldID", out oldIdObject))
  1423.                     {
  1424.                         var oldId = Convert.ToUInt32(oldIdObject);
  1425.                         pasteData.IoEntities.Add(oldId, ioData);
  1426.                     }
  1427.                 }
  1428.  
  1429.                 var flagsData = new Dictionary<string, object>();
  1430.  
  1431.                 if (data.ContainsKey("flags"))
  1432.                     flagsData = data["flags"] as Dictionary<string, object>;
  1433.  
  1434.                 var flags = new Dictionary<BaseEntity.Flags, bool>();
  1435.  
  1436.                 foreach (var flagData in flagsData)
  1437.                 {
  1438.                     BaseEntity.Flags baseFlag;
  1439.                     if (Enum.TryParse(flagData.Key, out baseFlag))
  1440.                         flags.Add(baseFlag, Convert.ToBoolean(flagData.Value));
  1441.                 }
  1442.  
  1443.                 foreach (var flag in flags)
  1444.                 {
  1445.                     entity.SetFlag(flag.Key, flag.Value);
  1446.                 }
  1447.  
  1448.                 pasteData.PastedEntities.Add(entity);
  1449.             }
  1450.  
  1451.             if (entities.Count > 0)
  1452.                 NextTick(() => PasteLoop(pasteData));
  1453.             else
  1454.             {
  1455.                 foreach (var ioData in pasteData.IoEntities.Values.ToArray())
  1456.                 {
  1457.                     if (!ioData.ContainsKey("entity"))
  1458.                         continue;
  1459.  
  1460.  
  1461.                     var ioEntity = ioData["entity"] as IOEntity;
  1462.  
  1463.                     List<object> inputs = null;
  1464.                     if (ioData.ContainsKey("inputs"))
  1465.                         inputs = ioData["inputs"] as List<object>;
  1466.  
  1467.                     var electricalBranch = ioEntity as ElectricalBranch;
  1468.                     if (electricalBranch != null && ioData.ContainsKey("branchAmount"))
  1469.                     {
  1470.                         electricalBranch.branchAmount = Convert.ToInt32(ioData["branchAmount"]);
  1471.                     }
  1472.  
  1473.                     // Realized counter.targetCounterNumber is private, leaving it in in case signature changes.
  1474.                     var counter = ioEntity.GetComponentInParent<PowerCounter>();
  1475.                     if (counter != null && ioData.ContainsKey("targetNumber"))
  1476.                     {
  1477.                         counter.targetCounterNumber = Convert.ToInt32(ioData["targetNumber"]);
  1478.                     }
  1479.  
  1480.                     var timer = ioEntity as TimerSwitch;
  1481.                     if (timer != null && ioData.ContainsKey("timerLength"))
  1482.                     {
  1483.                         timer.timerLength = Convert.ToInt32(ioData["timerLength"]);
  1484.                     }
  1485.  
  1486.                     var rfBroadcaster = ioEntity as RFBroadcaster;
  1487.                     if (rfBroadcaster != null && ioData.ContainsKey("frequency"))
  1488.                     {
  1489.                         rfBroadcaster.frequency = Convert.ToInt32(ioData["frequency"]);
  1490.                     }
  1491.  
  1492.                     var rfReceiver = ioEntity as RFReceiver;
  1493.                     if (rfReceiver != null && ioData.ContainsKey("frequency"))
  1494.                     {
  1495.                         rfReceiver.frequency = Convert.ToInt32(ioData["frequency"]);
  1496.                     }
  1497.  
  1498.                     var doorManipulator = ioEntity as CustomDoorManipulator;
  1499.                     if (doorManipulator != null)
  1500.                     {
  1501.                         var door = doorManipulator.FindDoor();
  1502.                         doorManipulator.SetTargetDoor(door);
  1503.                     }
  1504.  
  1505.                     if (inputs != null && inputs.Count > 0)
  1506.                     {
  1507.                         for (var index = 0; index < inputs.Count; index++)
  1508.                         {
  1509.                             var input = inputs[index] as Dictionary<string, object>;
  1510.                             object oldIdObject;
  1511.                             if (!input.TryGetValue("connectedID", out oldIdObject))
  1512.                                 continue;
  1513.  
  1514.                             var oldId = Convert.ToUInt32(oldIdObject);
  1515.  
  1516.                             if (oldId != 0 && pasteData.IoEntities.ContainsKey(oldId))
  1517.                             {
  1518.                                 if (ioEntity.inputs[index] == null)
  1519.                                     ioEntity.inputs[index] = new IOEntity.IOSlot();
  1520.  
  1521.                                 var ioConnection = pasteData.IoEntities[oldId];
  1522.  
  1523.                                 object temp;
  1524.  
  1525.                                 if (ioConnection.ContainsKey("newId"))
  1526.                                 {
  1527.                                     ioEntity.inputs[index].connectedTo.entityRef.uid =
  1528.                                         Convert.ToUInt32(ioConnection["newId"]);
  1529.                                 }
  1530.                             }
  1531.                         }
  1532.                     }
  1533.  
  1534.                     List<object> outputs = null;
  1535.                     if (ioData.ContainsKey("outputs"))
  1536.                         outputs = ioData["outputs"] as List<object>;
  1537.  
  1538.                     if (outputs != null && outputs.Count > 0)
  1539.                     {
  1540.                         for (var index = 0; index < outputs.Count; index++)
  1541.                         {
  1542.                             var output = outputs[index] as Dictionary<string, object>;
  1543.                             var oldId = Convert.ToUInt32(output["connectedID"]);
  1544.  
  1545.                             if (oldId != 0 && pasteData.IoEntities.ContainsKey(oldId))
  1546.                             {
  1547.                                 if (ioEntity.outputs[index] == null)
  1548.                                     ioEntity.outputs[index] = new IOEntity.IOSlot();
  1549.  
  1550.                                 var ioConnection = pasteData.IoEntities[oldId];
  1551.  
  1552.                                 if (ioConnection.ContainsKey("newId"))
  1553.                                 {
  1554.                                     var ioEntity2 = ioConnection["entity"] as IOEntity;
  1555.                                     var connectedToSlot = Convert.ToInt32(output["connectedToSlot"]);
  1556.                                     var ioOutput = ioEntity.outputs[index];
  1557.  
  1558.                                     ioOutput.connectedTo = new IOEntity.IORef();
  1559.                                     ioOutput.connectedTo.Set(ioEntity2);
  1560.                                     ioOutput.connectedToSlot = connectedToSlot;
  1561.                                     ioOutput.connectedTo.Init();
  1562.  
  1563.                                     ioEntity2.inputs[connectedToSlot].connectedTo = new IOEntity.IORef();
  1564.                                     ioEntity2.inputs[connectedToSlot].connectedTo.Set(ioEntity);
  1565.                                     ioEntity2.inputs[connectedToSlot].connectedToSlot = index;
  1566.                                     ioEntity2.inputs[connectedToSlot].connectedTo.Init();
  1567.  
  1568.                                     ioOutput.niceName = output["niceName"] as string;
  1569.  
  1570.                                     ioOutput.type = (IOEntity.IOType) Convert.ToInt32(output["type"]);
  1571.                                 }
  1572.  
  1573.                                 if (output.ContainsKey("linePoints"))
  1574.                                 {
  1575.                                     var linePoints = output["linePoints"] as List<object>;
  1576.                                     if (linePoints != null)
  1577.                                     {
  1578.                                         var lineList = new List<Vector3>();
  1579.                                         foreach (var point in linePoints)
  1580.                                         {
  1581.                                             var linePoint = point as Dictionary<string, object>;
  1582.                                             lineList.Add(new Vector3(
  1583.                                                 Convert.ToSingle(linePoint["x"]),
  1584.                                                 Convert.ToSingle(linePoint["y"]),
  1585.                                                 Convert.ToSingle(linePoint["z"])));
  1586.                                         }
  1587.  
  1588.                                         ioEntity.outputs[index].linePoints = lineList.ToArray();
  1589.                                     }
  1590.                                 }
  1591.                             }
  1592.                         }
  1593.                     }
  1594.  
  1595.                     ioEntity.MarkDirtyForceUpdateOutputs();
  1596.                     ioEntity.SendNetworkUpdate();
  1597.                 }
  1598.  
  1599.                 foreach (var entity in pasteData.StabilityEntities)
  1600.                 {
  1601.                     entity.grounded = false;
  1602.                     entity.InitializeSupports();
  1603.                     entity.UpdateStability();
  1604.                 }
  1605.  
  1606.                 if (player != null)
  1607.                 {
  1608.                     SendReply(player, Lang("PASTE_SUCCESS", player.UserIDString));
  1609. #if DEBUG
  1610.                     SendReply(player, $"Stopwatch took: {pasteData.Sw.Elapsed.TotalMilliseconds} ms");
  1611. #endif
  1612.                 }
  1613.                 else
  1614.                 {
  1615.                     Puts(Lang("PASTE_SUCCESS"));
  1616.                 }
  1617.  
  1618.                 if (!_lastPastes.ContainsKey(player?.UserIDString ?? _serverId))
  1619.                     _lastPastes[player?.UserIDString ?? _serverId] = new Stack<List<BaseEntity>>();
  1620.  
  1621.                 _lastPastes[player?.UserIDString ?? _serverId].Push(pasteData.PastedEntities);
  1622.  
  1623.                 pasteData.Callback?.Invoke();
  1624.  
  1625.                 Interface.CallHook("OnPasteFinished", pasteData.PastedEntities);
  1626.             }
  1627.         }
  1628.  
  1629.         private HashSet<Dictionary<string, object>> PreLoadData(List<object> entities, Vector3 startPos,
  1630.             float rotationCorrection, bool deployables, bool inventories, bool auth, bool vending)
  1631.         {
  1632.             var eulerRotation = new Vector3(0f, rotationCorrection, 0f);
  1633.             var quaternionRotation = Quaternion.EulerRotation(eulerRotation);
  1634.             var preloaddata = new HashSet<Dictionary<string, object>>();
  1635.  
  1636.             foreach (var entity in entities)
  1637.             {
  1638.                 var data = entity as Dictionary<string, object>;
  1639.  
  1640.                 if (!deployables && !data.ContainsKey("grade"))
  1641.                     continue;
  1642.  
  1643.                 var pos = (Dictionary<string, object>) data["pos"];
  1644.                 var rot = (Dictionary<string, object>) data["rot"];
  1645.  
  1646.                 data.Add("position",
  1647.                     quaternionRotation * (new Vector3(Convert.ToSingle(pos["x"]), Convert.ToSingle(pos["y"]),
  1648.                         Convert.ToSingle(pos["z"]))) + startPos);
  1649.                 data.Add("rotation",
  1650.                     Quaternion.EulerRotation(eulerRotation + new Vector3(Convert.ToSingle(rot["x"]),
  1651.                         Convert.ToSingle(rot["y"]), Convert.ToSingle(rot["z"]))));
  1652.  
  1653.                 if (!inventories && data.ContainsKey("items"))
  1654.                     data["items"] = new List<object>();
  1655.  
  1656.                 if (!vending && data["prefabname"].ToString().Contains("vendingmachine"))
  1657.                     data.Remove("vendingmachine");
  1658.  
  1659.                 preloaddata.Add(data);
  1660.             }
  1661.  
  1662.             return preloaddata;
  1663.         }
  1664.  
  1665.         private object TryCopy(Vector3 sourcePos, Vector3 sourceRot, string filename, float rotationCorrection,
  1666.             string[] args, BasePlayer player, Action callback)
  1667.         {
  1668.             bool saveShare = _config.Copy.Share, saveTree = _config.Copy.Tree, eachToEach = _config.Copy.EachToEach;
  1669.             var copyMechanics = CopyMechanics.Proximity;
  1670.             var radius = _config.Copy.Radius;
  1671.  
  1672.             for (var i = 0;; i = i + 2)
  1673.             {
  1674.                 if (i >= args.Length)
  1675.                     break;
  1676.  
  1677.                 var valueIndex = i + 1;
  1678.  
  1679.                 if (valueIndex >= args.Length)
  1680.                     return Lang("SYNTAX_COPY");
  1681.  
  1682.                 var param = args[i].ToLower();
  1683.  
  1684.                 switch (param)
  1685.                 {
  1686.                     case "e":
  1687.                     case "each":
  1688.                         if (!bool.TryParse(args[valueIndex], out eachToEach))
  1689.                             return Lang("SYNTAX_BOOL", null, param);
  1690.  
  1691.                         break;
  1692.  
  1693.                     case "m":
  1694.                     case "method":
  1695.                         switch (args[valueIndex].ToLower())
  1696.                         {
  1697.                             case "b":
  1698.                             case "building":
  1699.                                 copyMechanics = CopyMechanics.Building;
  1700.                                 break;
  1701.  
  1702.                             case "p":
  1703.                             case "proximity":
  1704.                                 copyMechanics = CopyMechanics.Proximity;
  1705.                                 break;
  1706.                         }
  1707.  
  1708.                         break;
  1709.  
  1710.                     case "r":
  1711.                     case "radius":
  1712.                         if (!float.TryParse(args[valueIndex], out radius))
  1713.                             return Lang("SYNTAX_RADIUS");
  1714.  
  1715.                         break;
  1716.  
  1717.                     case "s":
  1718.                     case "share":
  1719.                         if (!bool.TryParse(args[valueIndex], out saveShare))
  1720.                             return Lang("SYNTAX_BOOL", null, param);
  1721.  
  1722.                         break;
  1723.  
  1724.                     case "t":
  1725.                     case "tree":
  1726.                         if (!bool.TryParse(args[valueIndex], out saveTree))
  1727.                             return Lang("SYNTAX_BOOL", null, param);
  1728.  
  1729.                         break;
  1730.  
  1731.                     default:
  1732.                         return Lang("SYNTAX_COPY");
  1733.                 }
  1734.             }
  1735.  
  1736.             Copy(sourcePos, sourceRot, filename, rotationCorrection, copyMechanics, radius, saveTree, saveShare,
  1737.                 eachToEach, player, callback);
  1738.  
  1739.             return true;
  1740.         }
  1741.  
  1742.         private void TryCopySlots(BaseEntity ent, IDictionary<string, object> housedata, bool saveShare)
  1743.         {
  1744.             foreach (var slot in _checkSlots)
  1745.             {
  1746.                 if (!ent.HasSlot(slot))
  1747.                     continue;
  1748.  
  1749.                 var slotEntity = ent.GetSlot(slot);
  1750.  
  1751.                 if (slotEntity == null)
  1752.                     continue;
  1753.  
  1754.                 var codedata = new Dictionary<string, object>
  1755.                 {
  1756.                     {"prefabname", slotEntity.PrefabName},
  1757.                     {"flags", TryCopyFlags(ent)}
  1758.                 };
  1759.  
  1760.                 if (slotEntity.GetComponent<CodeLock>())
  1761.                 {
  1762.                     var codeLock = slotEntity.GetComponent<CodeLock>();
  1763.  
  1764.                     codedata.Add("code", codeLock.code);
  1765.  
  1766.                     if (saveShare)
  1767.                         codedata.Add("whitelistPlayers", codeLock.whitelistPlayers);
  1768.  
  1769.                     if (codeLock.guestCode != null && codeLock.guestCode.Length == 4)
  1770.                     {
  1771.                         codedata.Add("guestCode", codeLock.guestCode);
  1772.  
  1773.                         if (saveShare)
  1774.                             codedata.Add("guestPlayers", codeLock.guestPlayers);
  1775.                     }
  1776.                 }
  1777.                 else if (slotEntity.GetComponent<KeyLock>())
  1778.                 {
  1779.                     var keyLock = slotEntity.GetComponent<KeyLock>();
  1780.                     var code = keyLock.keyCode;
  1781.  
  1782.                     if (keyLock.firstKeyCreated)
  1783.                         code |= 0x80;
  1784.  
  1785.                     codedata.Add("ownerId", keyLock.OwnerID.ToString());
  1786.                     codedata.Add("code", code.ToString());
  1787.                 }
  1788.  
  1789.                 var slotName = slot.ToString().ToLower();
  1790.  
  1791.                 housedata.Add(slotName, codedata);
  1792.             }
  1793.         }
  1794.  
  1795.         private Dictionary<string, object> TryCopyFlags(BaseEntity entity)
  1796.         {
  1797.             var flags = new Dictionary<string, object>();
  1798.  
  1799.             foreach (BaseEntity.Flags flag in Enum.GetValues(typeof(BaseEntity.Flags)))
  1800.             {
  1801.                 if (!_config.DataSaving || entity.HasFlag(flag))
  1802.                     flags.Add(flag.ToString(), entity.HasFlag(flag));
  1803.             }
  1804.  
  1805.             return flags;
  1806.         }
  1807.  
  1808.         private object TryPaste(Vector3 startPos, string filename, BasePlayer player, float rotationCorrection,
  1809.             string[] args, bool autoHeight = true, Action callback = null)
  1810.         {
  1811.             var userId = player?.UserIDString;
  1812.  
  1813.             var path = _subDirectory + filename;
  1814.  
  1815.             if (!Interface.Oxide.DataFileSystem.ExistsDatafile(path))
  1816.                 return Lang("FILE_NOT_EXISTS", userId);
  1817.  
  1818.             var data = Interface.Oxide.DataFileSystem.GetDatafile(path);
  1819.  
  1820.             if (data["default"] == null || data["entities"] == null)
  1821.                 return Lang("FILE_BROKEN", userId);
  1822.  
  1823.             float heightAdj = 0f, blockCollision = 0f;
  1824.             bool auth = _config.Paste.Auth,
  1825.                 inventories = _config.Paste.Inventories,
  1826.                 deployables = _config.Paste.Deployables,
  1827.                 vending = _config.Paste.VendingMachines,
  1828.                 stability = _config.Paste.Stability,
  1829.                 ownership = _config.Paste.EntityOwner;
  1830.  
  1831.             for (var i = 0;; i = i + 2)
  1832.             {
  1833.                 if (i >= args.Length)
  1834.                     break;
  1835.  
  1836.                 var valueIndex = i + 1;
  1837.  
  1838.                 if (valueIndex >= args.Length)
  1839.                     return Lang("SYNTAX_PASTE_OR_PASTEBACK", userId);
  1840.  
  1841.                 var param = args[i].ToLower();
  1842.  
  1843.                 switch (param)
  1844.                 {
  1845.                     case "a":
  1846.                     case "auth":
  1847.                         if (!bool.TryParse(args[valueIndex], out auth))
  1848.                             return Lang("SYNTAX_BOOL", userId, param);
  1849.  
  1850.                         break;
  1851.  
  1852.                     case "b":
  1853.                     case "blockcollision":
  1854.                         if (!float.TryParse(args[valueIndex], out blockCollision))
  1855.                             return Lang("SYNTAX_BLOCKCOLLISION", userId);
  1856.  
  1857.                         break;
  1858.  
  1859.                     case "d":
  1860.                     case "deployables":
  1861.                         if (!bool.TryParse(args[valueIndex], out deployables))
  1862.                             return Lang("SYNTAX_BOOL", userId, param);
  1863.  
  1864.                         break;
  1865.  
  1866.                     case "h":
  1867.                     case "height":
  1868.                         if (!float.TryParse(args[valueIndex], out heightAdj))
  1869.                             return Lang("SYNTAX_HEIGHT", userId);
  1870.  
  1871.                         break;
  1872.  
  1873.                     case "i":
  1874.                     case "inventories":
  1875.                         if (!bool.TryParse(args[valueIndex], out inventories))
  1876.                             return Lang("SYNTAX_BOOL", userId, param);
  1877.  
  1878.                         break;
  1879.  
  1880.                     case "s":
  1881.                     case "stability":
  1882.                         if (!bool.TryParse(args[valueIndex], out stability))
  1883.                             return Lang("SYNTAX_BOOL", userId, param);
  1884.  
  1885.                         break;
  1886.  
  1887.                     case "v":
  1888.                     case "vending":
  1889.                         if (!bool.TryParse(args[valueIndex], out vending))
  1890.                             return Lang("SYNTAX_BOOL", userId, param);
  1891.  
  1892.                         break;
  1893.  
  1894.                     case "o":
  1895.                     case "entityowner":
  1896.                         if (!bool.TryParse(args[valueIndex], out ownership))
  1897.                             return Lang("SYNTAX_BOOL", userId, param);
  1898.  
  1899.                         break;
  1900.  
  1901.                     case "autoheight":
  1902.                         if (!bool.TryParse(args[valueIndex], out autoHeight))
  1903.                             return Lang("SYNTAX_BOOL", userId, param);
  1904.  
  1905.                         break;
  1906.  
  1907.                     default:
  1908.                         return Lang("SYNTAX_PASTE_OR_PASTEBACK", userId);
  1909.                 }
  1910.             }
  1911.  
  1912.             startPos.y += heightAdj;
  1913.  
  1914.             var preloadData = PreLoadData(data["entities"] as List<object>, startPos, rotationCorrection, deployables,
  1915.                 inventories, auth, vending);
  1916.  
  1917.             if (autoHeight)
  1918.             {
  1919.                 var bestHeight = FindBestHeight(preloadData, startPos);
  1920.  
  1921.                 if (bestHeight is string)
  1922.                     return bestHeight;
  1923.  
  1924.                 heightAdj += ((float) bestHeight - startPos.y);
  1925.  
  1926.                 foreach (var entity in preloadData)
  1927.                 {
  1928.                     var pos = ((Vector3) entity["position"]);
  1929.                     pos.y += heightAdj;
  1930.  
  1931.                     entity["position"] = pos;
  1932.                 }
  1933.             }
  1934.  
  1935.             if (blockCollision > 0f)
  1936.             {
  1937.                 var collision = CheckCollision(preloadData, startPos, blockCollision);
  1938.  
  1939.                 if (collision is string)
  1940.                     return collision;
  1941.             }
  1942.  
  1943.             var protocol = new Dictionary<string, object>();
  1944.  
  1945.             if (data["protocol"] != null)
  1946.                 protocol = data["protocol"] as Dictionary<string, object>;
  1947.  
  1948.             Paste(preloadData, protocol, ownership, startPos, player, stability, rotationCorrection,
  1949.                 autoHeight ? heightAdj : 0, auth, callback);
  1950.             return true;
  1951.         }
  1952.  
  1953.         private List<BaseEntity> TryPasteSlots(BaseEntity ent, Dictionary<string, object> structure,
  1954.             PasteData pasteData)
  1955.         {
  1956.             var entitySlots = new List<BaseEntity>();
  1957.  
  1958.             foreach (var slot in _checkSlots)
  1959.             {
  1960.                 var slotName = slot.ToString().ToLower();
  1961.  
  1962.                 if (!ent.HasSlot(slot) || !structure.ContainsKey(slotName))
  1963.                     continue;
  1964.  
  1965.                 var slotData = structure[slotName] as Dictionary<string, object>;
  1966.                 var slotEntity = GameManager.server.CreateEntity((string) slotData["prefabname"], Vector3.zero);
  1967.  
  1968.                 if (slotEntity == null)
  1969.                     continue;
  1970.  
  1971.                 slotEntity.gameObject.Identity();
  1972.                 slotEntity.SetParent(ent, slotName);
  1973.                 slotEntity.OnDeployed(ent, null);
  1974.                 slotEntity.Spawn();
  1975.  
  1976.                 ent.SetSlot(slot, slotEntity);
  1977.  
  1978.                 entitySlots.Add(slotEntity);
  1979.  
  1980.                 if (slotName != "lock" || !slotData.ContainsKey("code"))
  1981.                     continue;
  1982.  
  1983.                 if (slotEntity.GetComponent<CodeLock>())
  1984.                 {
  1985.                     var code = (string) slotData["code"];
  1986.  
  1987.                     if (!string.IsNullOrEmpty(code))
  1988.                     {
  1989.                         var codeLock = slotEntity.GetComponent<CodeLock>();
  1990.                         codeLock.code = code;
  1991.                         codeLock.hasCode = true;
  1992.  
  1993.                         if (pasteData.Auth && pasteData.Player != null)
  1994.                             codeLock.whitelistPlayers.Add(pasteData.Player.userID);
  1995.  
  1996.                         if (slotData.ContainsKey("whitelistPlayers"))
  1997.                         {
  1998.                             foreach (var userId in slotData["whitelistPlayers"] as List<object>)
  1999.                             {
  2000.                                 codeLock.whitelistPlayers.Add(Convert.ToUInt64(userId));
  2001.                             }
  2002.                         }
  2003.  
  2004.                         if (slotData.ContainsKey("guestCode"))
  2005.                         {
  2006.                             var guestCode = (string) slotData["guestCode"];
  2007.  
  2008.                             codeLock.guestCode = guestCode;
  2009.                             codeLock.hasGuestCode = true;
  2010.  
  2011.                             if (slotData.ContainsKey("guestPlayers"))
  2012.                             {
  2013.                                 foreach (var userId in slotData["guestPlayers"] as List<object>)
  2014.                                 {
  2015.                                     codeLock.guestPlayers.Add(Convert.ToUInt64(userId));
  2016.                                 }
  2017.                             }
  2018.                         }
  2019.  
  2020.                         codeLock.SetFlag(BaseEntity.Flags.Locked, true);
  2021.                     }
  2022.                 }
  2023.                 else if (slotEntity.GetComponent<KeyLock>())
  2024.                 {
  2025.                     var code = Convert.ToInt32(slotData["code"]);
  2026.                     var keyLock = slotEntity.GetComponent<KeyLock>();
  2027.  
  2028.                     if ((code & 0x80) != 0)
  2029.                     {
  2030.                         keyLock.keyCode = (code & 0x7F);
  2031.                         keyLock.firstKeyCreated = true;
  2032.                         keyLock.SetFlag(BaseEntity.Flags.Locked, true);
  2033.                     }
  2034.  
  2035.                     if (pasteData.Ownership && slotData.ContainsKey("ownerId"))
  2036.                     {
  2037.                         keyLock.OwnerID = Convert.ToUInt64(slotData["ownerId"]);
  2038.                     }
  2039.                 }
  2040.             }
  2041.  
  2042.             return entitySlots;
  2043.         }
  2044.  
  2045.         private object TryPasteBack(string filename, BasePlayer player, string[] args)
  2046.         {
  2047.             var path = _subDirectory + filename;
  2048.  
  2049.             if (!Interface.Oxide.DataFileSystem.ExistsDatafile(path))
  2050.                 return Lang("FILE_NOT_EXISTS", player?.UserIDString);
  2051.  
  2052.             var data = Interface.Oxide.DataFileSystem.GetDatafile(path);
  2053.  
  2054.             if (data["default"] == null || data["entities"] == null)
  2055.                 return Lang("FILE_BROKEN", player?.UserIDString);
  2056.  
  2057.             var defaultdata = data["default"] as Dictionary<string, object>;
  2058.             var pos = defaultdata["position"] as Dictionary<string, object>;
  2059.             var rotationCorrection = Convert.ToSingle(defaultdata["rotationdiff"]);
  2060.             var startPos = new Vector3(Convert.ToSingle(pos["x"]), Convert.ToSingle(pos["y"]),
  2061.                 Convert.ToSingle(pos["z"]));
  2062.  
  2063.             return TryPaste(startPos, filename, player, rotationCorrection, args, autoHeight: false);
  2064.         }
  2065.  
  2066.         //Сhat commands
  2067.  
  2068.         [ChatCommand("copy")]
  2069.         private void CmdChatCopy(BasePlayer player, string command, string[] args)
  2070.         {
  2071.             if (!HasAccess(player, _copyPermission))
  2072.             {
  2073.                 SendReply(player, Lang("NO_ACCESS", player.UserIDString));
  2074.                 return;
  2075.             }
  2076.  
  2077.             if (args.Length < 1)
  2078.             {
  2079.                 SendReply(player, Lang("SYNTAX_COPY", player.UserIDString));
  2080.                 return;
  2081.             }
  2082.  
  2083.             var savename = args[0];
  2084.             var success = TryCopyFromSteamId(player.userID, savename, args.Skip(1).ToArray());
  2085.  
  2086.             if (success is string)
  2087.             {
  2088.                 SendReply(player, (string) success);
  2089.             }
  2090.         }
  2091.  
  2092.         [ChatCommand("paste")]
  2093.         private void CmdChatPaste(BasePlayer player, string command, string[] args)
  2094.         {
  2095.             if (!HasAccess(player, _pastePermission))
  2096.             {
  2097.                 SendReply(player, Lang("NO_ACCESS", player.UserIDString));
  2098.                 return;
  2099.             }
  2100.  
  2101.             if (args.Length < 1)
  2102.             {
  2103.                 SendReply(player, Lang("SYNTAX_PASTE_OR_PASTEBACK", player.UserIDString));
  2104.                 return;
  2105.             }
  2106.  
  2107.             var success = TryPasteFromSteamId(player.userID, args[0], args.Skip(1).ToArray());
  2108.  
  2109.             if (success is string)
  2110.             {
  2111.                 SendReply(player, (string) success);
  2112.             }
  2113.         }
  2114.  
  2115.         [ChatCommand("copylist")]
  2116.         private void CmdChatList(BasePlayer player, string command, string[] args)
  2117.         {
  2118.             if (!HasAccess(player, _listPermission))
  2119.             {
  2120.                 SendReply(player, Lang("NO_ACCESS", player.UserIDString));
  2121.                 return;
  2122.             }
  2123.  
  2124.             var files = Interface.Oxide.DataFileSystem.GetFiles(_subDirectory);
  2125.  
  2126.             var fileList = new List<string>();
  2127.  
  2128.             foreach (var file in files)
  2129.             {
  2130.                 var strFileParts = file.Split('/');
  2131.                 var justfile = strFileParts[strFileParts.Length - 1].Replace(".json", "");
  2132.                 fileList.Add(justfile);
  2133.             }
  2134.  
  2135.             SendReply(player, Lang("AVAILABLE_STRUCTURES", player.UserIDString));
  2136.             SendReply(player, string.Join(", ", fileList.ToArray()));
  2137.         }
  2138.  
  2139.         [ChatCommand("pasteback")]
  2140.         private void CmdChatPasteBack(BasePlayer player, string command, string[] args)
  2141.         {
  2142.             if (!HasAccess(player, _pastebackPermission))
  2143.             {
  2144.                 SendReply(player, Lang("NO_ACCESS", player.UserIDString));
  2145.                 return;
  2146.             }
  2147.  
  2148.             var result = CmdPasteBack(player, args);
  2149.  
  2150.             if (result is string)
  2151.                 SendReply(player, (string) result);
  2152.         }
  2153.  
  2154.         [ChatCommand("undo")]
  2155.         private void CmdChatUndo(BasePlayer player, string command, string[] args)
  2156.         {
  2157.             if (!HasAccess(player, _undoPermission))
  2158.             {
  2159.                 SendReply(player, Lang("NO_ACCESS", player.UserIDString));
  2160.                 return;
  2161.             }
  2162.  
  2163.             CmdUndo(player.UserIDString, args);
  2164.         }
  2165.  
  2166.         //Console commands [From Server]
  2167.  
  2168.         [ConsoleCommand("pasteback")]
  2169.         private void CmdConsolePasteBack(ConsoleSystem.Arg arg)
  2170.         {
  2171.             if (!arg.IsAdmin)
  2172.                 return;
  2173.  
  2174.             var result = CmdPasteBack(arg.Player(), arg.Args);
  2175.  
  2176.             if (result is string)
  2177.                 SendReply(arg, (string) result);
  2178.         }
  2179.  
  2180.         [ConsoleCommand("undo")]
  2181.         private void CmdConsoleUndo(ConsoleSystem.Arg arg)
  2182.         {
  2183.             if (!arg.IsAdmin)
  2184.                 return;
  2185.  
  2186.             var player = arg.Player();
  2187.  
  2188.             CmdUndo(player == null ? _serverId : player.UserIDString, arg.Args);
  2189.         }
  2190.  
  2191.         //Replace between old ItemID to new ItemID
  2192. //Languages phrases
  2193.  
  2194.         private readonly Dictionary<string, Dictionary<string, string>> _messages =
  2195.             new Dictionary<string, Dictionary<string, string>>
  2196.             {
  2197.                 {
  2198.                     "FILE_NOT_EXISTS", new Dictionary<string, string>
  2199.                     {
  2200.                         {"en", "File does not exist"},
  2201.                         {"ru", "Файл не существует"},
  2202.                         {"nl", "Bestand bestaat niet."}
  2203.                     }
  2204.                 },
  2205.                 {
  2206.                     "FILE_BROKEN", new Dictionary<string, string>
  2207.                     {
  2208.                         {"en", "Something went wrong during pasting because of a error in the file."},
  2209.                         {"ru", "Файл поврежден, вставка невозможна"},
  2210.                         {"nl", "Er is iets misgegaan tijdens het plakken door een beschadigd bestand."}
  2211.                     }
  2212.                 },
  2213.                 {
  2214.                     "NO_ACCESS", new Dictionary<string, string>
  2215.                     {
  2216.                         {"en", "You don't have the permissions to use this command"},
  2217.                         {"ru", "У вас нет прав доступа к данной команде"},
  2218.                         {"nl", "U heeft geen toestemming/permissie om dit commando te gebruiken."}
  2219.                     }
  2220.                 },
  2221.                 {
  2222.                     "SYNTAX_PASTEBACK", new Dictionary<string, string>
  2223.                     {
  2224.                         {
  2225.                             "en", "Syntax: /pasteback <Target Filename> <options values>\n" +
  2226.                                   "height XX - Adjust the height\n" +
  2227.                                   "vending - Information and sellings in vending machine\n" +
  2228.                                   "stability <true/false> - Wether or not to disable stability\n" +
  2229.                                   "deployables <true/false> - Wether or not to copy deployables\n" +
  2230.                                   "auth <true/false> - Wether or not to copy lock and cupboard whitelists"
  2231.                         },
  2232.                         {
  2233.                             "ru", "Синтаксис: /pasteback <Название Объекта> <опция значение>\n" +
  2234.                                   "height XX - Высота от земли\n" +
  2235.                                   "vending - Информация и товары в торговом автомате"
  2236.                         },
  2237.                         {
  2238.                             "nl", "Syntax: /pasteback <Bestandsnaam> <opties waarden>\n" +
  2239.                                   "height XX - Pas de hoogte aan \n" +
  2240.                                   "vending <true/false> - Informatie en inventaris van \"vending machines\" kopiëren\n" +
  2241.                                   "stability <true/false> - of de stabiliteit van het gebouw uitgezet moet worden\n" +
  2242.                                   "deployables <true/false> - of de \"deployables\" gekopiërd moeten worden\n" +
  2243.                                   "auth <true/false> - Of authorisatie op sloten en tool cupboards gekopiërd moet worden"
  2244.                         }
  2245.                     }
  2246.                 },
  2247.                 {
  2248.                     "SYNTAX_PASTE_OR_PASTEBACK", new Dictionary<string, string>
  2249.                     {
  2250.                         {
  2251.                             "en", "Syntax: /paste or /pasteback <Target Filename> <options values>\n" +
  2252.                                   "height XX - Adjust the height\n" +
  2253.                                   "autoheight true/false - sets best height, carefull of the steep\n" +
  2254.                                   "blockcollision XX - blocks the entire paste if something the new building collides with something\n" +
  2255.                                   "deployables true/false - false to remove deployables\n" +
  2256.                                   "inventories true/false - false to ignore inventories\n" +
  2257.                                   "vending - Information and sellings in vending machine\n" +
  2258.                                   "stability <true/false> - Wether or not to disable stability on the building"
  2259.                         },
  2260.                         {
  2261.                             "ru", "Синтаксис: /paste or /pasteback <Название Объекта> <опция значение>\n" +
  2262.                                   "height XX - Высота от земли\n" +
  2263.                                   "autoheight true/false - автоматически подобрать высоту от земли\n" +
  2264.                                   "blockcollision XX - блокировать вставку, если что-то этому мешает\n" +
  2265.                                   "deployables true/false - false для удаления предметов\n" +
  2266.                                   "inventories true/false - false для игнорирования копирования инвентаря\n" +
  2267.                                   "vending - Информация и товары в торговом автомате"
  2268.                         },
  2269.                         {
  2270.                             "nl", "Syntax: /paste of /pasteback <Bestandsnaam> <opties waarden>\n" +
  2271.                                   "height XX - Pas de hoogte aan \n" +
  2272.                                   "autoheight true/false - probeert de optimale hoogte te vinden om gebouw te plaatsen. Werkt optimaal op vlakke grond.\n" +
  2273.                                   "vending true/false - Informatie en inventaris van \"vending machines\" kopiëren\n" +
  2274.                                   "stability <true/false> - of de stabiliteit van het gebouw uitgezet moet worden\n" +
  2275.                                   "deployables <true/false> - of de \"deployables\" gekopiërd moeten worden\n" +
  2276.                                   "auth <true/false> - Of authorisatie op sloten en tool cupboards gekopiërd moet worden"
  2277.                         }
  2278.                     }
  2279.                 },
  2280.                 {
  2281.                     "PASTEBACK_SUCCESS", new Dictionary<string, string>
  2282.                     {
  2283.                         {"en", "You've successfully placed back the structure"},
  2284.                         {"ru", "Постройка успешно вставлена на старое место"},
  2285.                         {"nl", "Het gebouw is succesvol teruggeplaatst."}
  2286.                     }
  2287.                 },
  2288.                 {
  2289.                     "PASTE_SUCCESS", new Dictionary<string, string>
  2290.                     {
  2291.                         {"en", "You've successfully pasted the structure"},
  2292.                         {"ru", "Постройка успешно вставлена"},
  2293.                         {"nl", "Het gebouw is succesvol geplaatst."}
  2294.                     }
  2295.                 },
  2296.                 {
  2297.                     "SYNTAX_COPY", new Dictionary<string, string>
  2298.                     {
  2299.                         {
  2300.                             "en", "Syntax: /copy <Target Filename> <options values>\n" +
  2301.                                   "radius XX (default 3) - The radius in which to search for the next object (performs this search from every other object)\n" +
  2302.                                   "method proximity/building (default proximity) - Building only copies objects which are part of the building, proximity copies everything (within the radius)\n" +
  2303.                                   "deployables true/false (saves deployables or not) - Wether to save deployables\n" +
  2304.                                   "inventories true/false (saves inventories or not) - Wether to save inventories of found objects with inventories."
  2305.                         },
  2306.                         {
  2307.                             "ru", "Синтаксис: /copy <Название Объекта> <опция значение>\n" +
  2308.                                   "radius XX (default 3)\n" +
  2309.                                   "method proximity/building (по умолчанию proximity)\n" +
  2310.                                   "deployables true/false (сохранять предметы или нет)\n" +
  2311.                                   "inventories true/false (сохранять инвентарь или нет)"
  2312.                         },
  2313.                         {
  2314.                             "nl", "Syntax: /copy <Bestandsnaam> <opties waarden>\n" +
  2315.                                   "radius XX (standaard 3) - De radius waarin copy paste naar het volgende object zoekt\n" +
  2316.                                   "method proximity/building (standaard proximity) - Building kopieërd alleen objecten die bij het gebouw horen, proximity kopieërd alles wat gevonden is\n" +
  2317.                                   "deployables true/false (saves deployables or not) - Of de data van gevonden \"deployables\" opgeslagen moet worden\n" +
  2318.                                   "inventories true/false (saves inventories or not) - Of inventarissen van objecten (kisten, tool cupboards, etc) opgeslagen moet worden"
  2319.                         }
  2320.                     }
  2321.                 },
  2322.                 {
  2323.                     "NO_ENTITY_RAY", new Dictionary<string, string>
  2324.                     {
  2325.                         {"en", "Couldn't ray something valid in front of you"},
  2326.                         {"ru", "Не удалось найти какой-либо объект перед вами"},
  2327.                         {"nl", "U kijkt niet naar een geschikt object om een kopie op te starten."}
  2328.                     }
  2329.                 },
  2330.                 {
  2331.                     "COPY_SUCCESS", new Dictionary<string, string>
  2332.                     {
  2333.                         {"en", "The structure was successfully copied as {0}"},
  2334.                         {"ru", "Постройка успешно скопирована под названием: {0}"},
  2335.                         {"nl", "Gebouw is succesvol gekopieërd"}
  2336.                     }
  2337.                 },
  2338.                 {
  2339.                     "NO_PASTED_STRUCTURE", new Dictionary<string, string>
  2340.                     {
  2341.                         {"en", "You must paste structure before undoing it"},
  2342.                         {"ru", "Вы должны вставить постройку перед тем, как отменить действие"},
  2343.                         {"nl", "U moet eerst een gebouw terugplaatsen alvorens deze ongedaan gemaakt kan worden (duhh)"}
  2344.                     }
  2345.                 },
  2346.                 {
  2347.                     "UNDO_SUCCESS", new Dictionary<string, string>
  2348.                     {
  2349.                         {"en", "You've successfully undid what you pasted"},
  2350.                         {"ru", "Вы успешно снесли вставленную постройку"},
  2351.                         {"nl", "Laatse geplaatste gebouw is succesvol ongedaan gemaakt."}
  2352.                     }
  2353.                 },
  2354.                 {
  2355.                     "NOT_FOUND_PLAYER", new Dictionary<string, string>
  2356.                     {
  2357.                         {"en", "Couldn't find the player"},
  2358.                         {"ru", "Не удалось найти игрока"},
  2359.                         {"nl", "Speler niet gevonden."}
  2360.                     }
  2361.                 },
  2362.                 {
  2363.                     "SYNTAX_BOOL", new Dictionary<string, string>
  2364.                     {
  2365.                         {"en", "Option {0} must be true/false"},
  2366.                         {"ru", "Опция {0} принимает значения true/false"},
  2367.                         {"nl", "Optie {0} moet true of false zijn"}
  2368.                     }
  2369.                 },
  2370.                 {
  2371.                     "SYNTAX_HEIGHT", new Dictionary<string, string>
  2372.                     {
  2373.                         {"en", "Option height must be a number"},
  2374.                         {"ru", "Опция height принимает только числовые значения"},
  2375.                         {"nl", "De optie height accepteert alleen nummers"}
  2376.                     }
  2377.                 },
  2378.                 {
  2379.                     "SYNTAX_BLOCKCOLLISION", new Dictionary<string, string>
  2380.                     {
  2381.                         {"en", "Option blockcollision must be a number, 0 will deactivate the option"},
  2382.                         {
  2383.                             "ru",
  2384.                             "Опция blockcollision принимает только числовые значения, 0 позволяет отключить проверку"
  2385.                         },
  2386.                         {"nl", "Optie blockcollision accepteert alleen nummers, 0 schakelt deze functionaliteit uit"}
  2387.                     }
  2388.                 },
  2389.                 {
  2390.                     "SYNTAX_RADIUS", new Dictionary<string, string>
  2391.                     {
  2392.                         {"en", "Option radius must be a number"},
  2393.                         {"ru", "Опция radius принимает только числовые значения"},
  2394.                         {"nl", "Optie height accepteert alleen nummers"}
  2395.                     }
  2396.                 },
  2397.                 {
  2398.                     "BLOCKING_PASTE", new Dictionary<string, string>
  2399.                     {
  2400.                         {"en", "Something is blocking the paste"},
  2401.                         {"ru", "Что-то препятствует вставке"},
  2402.                         {"nl", "Iets blokkeert het plaatsen van dit gebouw"}
  2403.                     }
  2404.                 },
  2405.                 {
  2406.                     "AVAILABLE_STRUCTURES", new Dictionary<string, string>
  2407.                     {
  2408.                         {"ru", "<color=orange>Доступные постройки:</color>"},
  2409.                         {"en", "<color=orange>Available structures:</color>"},
  2410.                         {"nl", "Beschikbare bestanden om te plaatsen zijn:"}
  2411.                     }
  2412.                 }
  2413.             };
  2414.  
  2415.         public class CopyData
  2416.         {
  2417.             public BasePlayer Player;
  2418.             public Stack<Vector3> CheckFrom = new Stack<Vector3>();
  2419.             public HashSet<BaseEntity> HouseList = new HashSet<BaseEntity>();
  2420.             public List<object> RawData = new List<object>();
  2421.             public Vector3 SourcePos;
  2422.             public Vector3 SourceRot;
  2423.             public Action Callback;
  2424.  
  2425.             public string FileName;
  2426.             public int CurrentLayer;
  2427.             public float RotCor;
  2428.             public float Range;
  2429.             public bool SaveTree;
  2430.             public bool SaveShare;
  2431.             public CopyMechanics CopyMechanics;
  2432.             public bool EachToEach;
  2433.             public uint BuildingId = 0;
  2434.  
  2435. #if DEBUG
  2436.             public Stopwatch Sw = new Stopwatch();
  2437. #endif
  2438.         }
  2439.  
  2440.         public class PasteData
  2441.         {
  2442.             public ICollection<Dictionary<string, object>> Entities;
  2443.             public List<BaseEntity> PastedEntities = new List<BaseEntity>();
  2444.  
  2445.             public Dictionary<uint, Dictionary<string, object>> IoEntities =
  2446.                 new Dictionary<uint, Dictionary<string, object>>();
  2447.  
  2448.             public BasePlayer Player;
  2449.             public List<StabilityEntity> StabilityEntities = new List<StabilityEntity>();
  2450.             public Quaternion QuaternionRotation;
  2451.             public Action Callback;
  2452.  
  2453.             public bool Auth;
  2454.             public Vector3 StartPos;
  2455.             public float HeightAdj;
  2456.             public bool Stability;
  2457.             public bool IsItemReplace;
  2458.             public bool Ownership;
  2459.  
  2460.             public uint BuildingId = 0;
  2461.  
  2462. #if DEBUG
  2463.             public Stopwatch Sw = new Stopwatch();
  2464. #endif
  2465.         }
  2466.     }
  2467. }
Add Comment
Please, Sign In to add comment