C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
// Reference: System.Drawing
//If debug is defined it will add a stopwatch to the paste and copydata which can be used to profile copying and pasting.//#define DEBUG
using Facepunch;
using Graphics = System.Drawing.Graphics;
using ImageFormat = System.Drawing.Imaging.ImageFormat;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Game.Rust;
using ProtoBuf;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using UnityEngine;
using Debug = System.Diagnostics.Debug;
namespace Oxide.Plugins {
[Info("Copy Paste", "Reneb & MiRror & Misstake", "4.1.9", ResourceId = 716)]
[Description("Copy and paste buildings to save them or move them")]
public class CopyPaste : RustPlugin {
private int copyLayer = LayerMask.GetMask("Construction", "Prevent Building", "Construction Trigger", "Trigger", "Deployed", "Default", "Ragdoll") , groundLayer = LayerMask.GetMask("Terrain", "Default") , rayCopy = LayerMask.GetMask("Construction", "Deployed", "Tree", "Resource", "Prevent Building") , rayPaste = LayerMask.GetMask("Construction", "Deployed", "Tree", "Terrain", "World", "Water", "Prevent Building");
private string copyPermission = "copypaste.copy" , listPermission = "copypaste.list" , pastePermission = "copypaste.paste" , pastebackPermission = "copypaste.pasteback" , undoPermission = "copypaste.undo" , serverID = "Server" , subDirectory = "copypaste/";
private Dictionary<string, Stack<List<BaseEntity>>> lastPastes = new Dictionary<string, Stack<List<BaseEntity>>>();
private Dictionary<string, SignSize> signSizes = new Dictionary<string, SignSize>() {
//{"spinner.wheel.deployed", new SignSize(512, 512)},
{
"sign.pictureframe.landscape", new SignSize(256, 128)
}
, {
"sign.pictureframe.tall", new SignSize(128, 512)
}
, {
"sign.pictureframe.portrait", new SignSize(128, 256)
}
, {
"sign.pictureframe.xxl", new SignSize(1024, 512)
}
, {
"sign.pictureframe.xl", new SignSize(512, 512)
}
, {
"sign.small.wood", new SignSize(128, 64)
}
, {
"sign.medium.wood", new SignSize(256, 128)
}
, {
"sign.large.wood", new SignSize(256, 128)
}
, {
"sign.huge.wood", new SignSize(512, 128)
}
, {
"sign.hanging.banner.large", new SignSize(64, 256)
}
, {
"sign.pole.banner.large", new SignSize(64, 256)
}
, {
"sign.post.single", new SignSize(128, 64)
}
, {
"sign.post.double", new SignSize(256, 256)
}
, {
"sign.post.town", new SignSize(256, 128)
}
, {
"sign.post.town.roof", new SignSize(256, 128)
}
, {
"sign.hanging", new SignSize(128, 256)
}
, {
"sign.hanging.ornate", new SignSize(256, 128)
}
,
}
;
private List<BaseEntity.Slot> checkSlots = new List<BaseEntity.Slot>() {
BaseEntity.Slot.Lock, BaseEntity.Slot.UpperModifier, BaseEntity.Slot.MiddleModifier, BaseEntity.Slot.LowerModifier
}
;
public enum CopyMechanics {
Building, Proximity
}
private class SignSize {
public int width;
public int height;
public SignSize(int width, int height) {
this.width = width;
this.height = height;
}
}
//Config
private ConfigData config;
private class ConfigData {
[JsonProperty(PropertyName = "Copy Options")]
public CopyOptions Copy {
get;
set;
}
[JsonProperty(PropertyName = "Paste Options")]
public PasteOptions Paste {
get;
set;
}
[JsonProperty(PropertyName = "Amount of entities to paste per batch.Use to tweak performance impact of pasting")]
[DefaultValue(15)]
public int PasteBatchSize = 15;
[JsonProperty(PropertyName = "Amount of entities to copy per batch.Use to tweak performance impact of copying")]
[DefaultValue(100)]
public int CopyBatchSize = 100;
[JsonProperty(PropertyName = "Amount of entities to undo per batch.Use to tweak performance impact of undoing")]
[DefaultValue(15)]
public int UndoBatchSize = 15;
public class CopyOptions {
[JsonProperty(PropertyName = "Check radius from each entity (true/false)")]
[DefaultValue(true)]
public bool EachToEach {
get;
set;
}
= true;
[JsonProperty(PropertyName = "Share (true/false)")]
[DefaultValue(false)]
public bool Share {
get;
set;
}
= false;
[JsonProperty(PropertyName = "Tree (true/false)")]
[DefaultValue(false)]
public bool Tree {
get;
set;
}
= false;
}
public class PasteOptions {
[JsonProperty(PropertyName = "Auth (true/false)")]
[DefaultValue(false)]
public bool Auth {
get;
set;
}
= false;
[JsonProperty(PropertyName = "Deployables (true/false)")]
[DefaultValue(true)]
public bool Deployables {
get;
set;
}
= true;
[JsonProperty(PropertyName = "Inventories (true/false)")]
[DefaultValue(true)]
public bool Inventories {
get;
set;
}
= true;
[JsonProperty(PropertyName = "Vending Machines (true/false)")]
[DefaultValue(true)]
public bool VendingMachines {
get;
set;
}
= true;
[JsonProperty(PropertyName = "Stability (true/false)")]
[DefaultValue(true)]
public bool Stability {
get;
set;
}
= true;
[JsonProperty(PropertyName = "EntityOwner (true/false)")]
[DefaultValue(true)]
public bool EntityOwner {
get;
set;
}
= true;
}
}
private void LoadVariables() {
Config.Settings.DefaultValueHandling = DefaultValueHandling.Populate;
config = Config.ReadObject<ConfigData>();
Config.WriteObject(config, true);
}
protected override void LoadDefaultConfig() {
var configData = new ConfigData {
Copy = new ConfigData.CopyOptions(), Paste = new ConfigData.PasteOptions()
}
;
Config.WriteObject(configData, true);
}
//Hooks
private void Init() {
permission.RegisterPermission(copyPermission, this);
permission.RegisterPermission(listPermission, this);
permission.RegisterPermission(pastePermission, this);
permission.RegisterPermission(pastebackPermission, this);
permission.RegisterPermission(undoPermission, this);
Dictionary<string, Dictionary<string, string>> compiledLangs = new Dictionary<string, Dictionary<string, string>>();
foreach (var line in messages) {
foreach (var translate in line.Value) {
if (!compiledLangs.ContainsKey(translate.Key)) compiledLangs[translate.Key] = new Dictionary<string, string>();
compiledLangs[translate.Key][line.Key] = translate.Value;
}
}
foreach (var cLangs in compiledLangs) {
lang.RegisterMessages(cLangs.Value, this, cLangs.Key);
}
}
private void OnServerInitialized() {
LoadVariables();
Vis.colBuffer = new Collider[8192 * 16];
JsonConvert.DefaultSettings = () => new JsonSerializerSettings {
Formatting = Newtonsoft.Json.Formatting.Indented, ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
}
;
}
#region API
private object TryCopyFromSteamID(ulong userID, string filename, string[] args, Action callback = null) {
var player = BasePlayer.FindByID(userID);
if (player == null) return Lang("NOT_FOUND_PLAYER", player.UserIDString);
RaycastHit hit;
if (!Physics.Raycast(player.eyes.HeadRay(), out hit, 1000f, rayCopy)) return Lang("NO_ENTITY_RAY", player.UserIDString);
return TryCopy(hit.point, hit.GetEntity().GetNetworkRotation().eulerAngles, filename, DegreeToRadian(player.GetNetworkRotation().eulerAngles.y), args, player, callback);
}
private object TryPasteFromSteamID(ulong userID, string filename, string[] args, Action callback = null) {
var player = BasePlayer.FindByID(userID);
if (player == null) return Lang("NOT_FOUND_PLAYER", player.UserIDString);
RaycastHit hit;
if (!Physics.Raycast(player.eyes.HeadRay(), out hit, 1000f, rayPaste)) return Lang("NO_ENTITY_RAY", player.UserIDString);
return TryPaste(hit.point, filename, player, DegreeToRadian(player.GetNetworkRotation().eulerAngles.y), args, callback : callback);
}
private object TryPasteFromVector3(Vector3 pos, float rotationCorrection, string filename, string[] args, Action callback = null) {
return TryPaste(pos, filename, null, rotationCorrection, args, callback : callback);
}
#endregion
//Other methods
private object CheckCollision(HashSet<Dictionary<string, object>> entities, Vector3 startPos, float radius) {
foreach (var entityobj in entities) {
if (Physics.CheckSphere((Vector3)entityobj["position"], radius, copyLayer)) return Lang("BLOCKING_PASTE", null);
}
return true;
}
private bool CheckPlaced(string prefabname, Vector3 pos, Quaternion rot) {
List<BaseEntity> ents = new List<BaseEntity>();
Vis.Entities<BaseEntity>(pos, 2f, ents);
foreach (BaseEntity ent in ents) {
if (ent.PrefabName == prefabname && ent.transform.position == pos && ent.transform.rotation == rot) return true;
}
return false;
}
private object cmdPasteBack(BasePlayer player, string[] args) {
string userIDString = (player == null) ? serverID : player.UserIDString;
if (args.Length < 1) return Lang("SYNTAX_PASTEBACK", userIDString);
var success = TryPasteBack(args[0], player, args.Skip(1).ToArray());
if (success is string) return (string)success;
return true;
}
private object cmdUndo(string userIDString, string[] args) {
var player = BasePlayer.Find(userIDString);
if (!lastPastes.ContainsKey(userIDString)) return Lang("NO_PASTED_STRUCTURE", userIDString);
HashSet<BaseEntity> entities = new HashSet<BaseEntity>(lastPastes[userIDString].Pop().ToList());
UndoLoop(entities, player);
return true;
}
private void UndoLoop(HashSet<BaseEntity> entities, BasePlayer player, int count = 0) {
entities.Take(config.UndoBatchSize).ToList().ForEach(p => {
entities.Remove(p);
// Cleanup the hotspot beloning to the node.var ore = p as OreResourceEntity;
if (ore != null) {
ore.CleanupBonus();
}
if (p != null && !p.IsDestroyed) p.Kill();
}
);
// If it gets stuck in infinite loop break the loop.if (entities.Count == count)
{
if (player != null) SendReply(player, "Undo cancelled because of infinite loop.");
else Puts("Undo cancelled because of infinite loop.");
return;
}
if(entities.Count > 0) NextTick(() => UndoLoop(entities, player, entities.Count));
else {
if (player != null) SendReply(player, Lang("UNDO_SUCCESS", player.UserIDString));
else Puts(Lang("UNDO_SUCCESS"));
if (lastPastes[player?.UserIDString ?? serverID].Count == 0) lastPastes.Remove(player?.UserIDString ?? serverID);
}
}
private void Copy(Vector3 sourcePos, Vector3 sourceRot, string filename, float RotationCorrection, CopyMechanics copyMechanics, float range, bool saveTree, bool saveShare, bool eachToEach, BasePlayer player, Action callback) {
int currentLayer = copyLayer;
if (saveTree) currentLayer |= LayerMask.GetMask("Tree");
var copyData = new CopyData() {
FileName = filename, CurrentLayer = currentLayer, RotCor = RotationCorrection, Range = range, SaveShare = saveShare, SaveTree = saveTree, CopyMechanics = copyMechanics, EachToEach = eachToEach, SourcePos = sourcePos, SourceRot = sourceRot, Player = player, callback = callback
}
;
copyData.CheckFrom.Push(sourcePos);
NextTick(() => CopyLoop(copyData));
;
}
private void CopyLoop(CopyData copyData) {
var checkFrom = copyData.CheckFrom;
var houseList = copyData.HouseList;
var buildingID = copyData.BuildingID;
var copyMechanics = copyData.CopyMechanics;
var batchSize = checkFrom.Count < config.CopyBatchSize ? checkFrom.Count : config.CopyBatchSize;
for(int i = 0; i < batchSize; i++) {
if (checkFrom.Count == 0) break;
List<BaseEntity> list = Pool.GetList<BaseEntity>();
Vis.Entities<BaseEntity>(checkFrom.Pop(), copyData.Range, list, copyData.CurrentLayer);
foreach (var entity in list) {
if (!houseList.Add(entity)) continue;
if (copyMechanics == CopyMechanics.Building) {
BuildingBlock buildingBlock = entity.GetComponentInParent<BuildingBlock>();
if (buildingBlock != null) {
if (buildingID == 0) buildingID = buildingBlock.buildingID;
if (buildingID != buildingBlock.buildingID) continue;
}
}
if (copyData.EachToEach) checkFrom.Push(entity.transform.position);
copyData.RawData.Add(EntityData(entity, entity.transform.position, entity.transform.rotation.eulerAngles / 57.29578f, copyData));
}
copyData.BuildingID = buildingID;
}
if (checkFrom.Count > 0) {
NextTick(() => CopyLoop(copyData));
}
else {
string path = subDirectory + copyData.FileName;
var datafile = Interface.Oxide.DataFileSystem.GetDatafile(path);
datafile.Clear();
var sourcePos = copyData.SourcePos;
datafile["default"] = new Dictionary<string, object> {
{
"position", new Dictionary<string, object> {
{
"x", sourcePos.x.ToString()
}
, {
"y", sourcePos.y.ToString()
}
, {
"z", sourcePos.z.ToString()
}
}
}
, {
"rotationy", copyData.SourceRot.y.ToString()
}
, {
"rotationdiff", copyData.RotCor.ToString()
}
}
;
datafile["entities"] = copyData.RawData;
datafile["protocol"] = new Dictionary<string, object> {
{
"items", 2
}
, {
"version", Version
}
}
;
Interface.Oxide.DataFileSystem.SaveDatafile(path);
SendReply(copyData.Player, Lang("COPY_SUCCESS", copyData.Player.UserIDString, copyData.FileName));
copyData.callback?.Invoke();
Interface.CallHook("OnCopyFinished", copyData.RawData);
}
}
private float DegreeToRadian(float angle) {
return (float)(Math.PI * angle / 180.0f);
}
private Dictionary<string, object> EntityData(BaseEntity entity, Vector3 entPos, Vector3 entRot, CopyData copyData) {
var normalizedPos = NormalizePosition(copyData.SourcePos, entPos, copyData.RotCor);
entRot.y -= copyData.RotCor;
var data = new Dictionary<string, object> {
{
"prefabname", entity.PrefabName
}
, {
"skinid", entity.skinID
}
, {
"flags", TryCopyFlags(entity)
}
, {
"pos", new Dictionary<string, object> {
{
"x", normalizedPos.x.ToString()
}
, {
"y", normalizedPos.y.ToString()
}
, {
"z", normalizedPos.z.ToString()
}
}
}
, {
"rot", new Dictionary<string, object> {
{
"x", entRot.x.ToString()
}
, {
"y", entRot.y.ToString()
}
, {
"z", entRot.z.ToString()
}
,
}
}
, {
"ownerid", entity.OwnerID
}
}
;
TryCopySlots(entity, data, copyData.SaveShare);
var buildingblock = entity as BuildingBlock;
if (buildingblock != null) {
data.Add("grade", buildingblock.grade);
}
var box = entity as StorageContainer;
if (box != null) {
var itemlist = new List<object>();
foreach (Item item in box.inventory.itemList) {
var itemdata = new Dictionary<string, object> {
{
"condition", item.condition.ToString()
}
, {
"id", item.info.itemid
}
, {
"amount", item.amount
}
, {
"skinid", item.skin
}
, {
"position", item.position
}
, {
"blueprintTarget", item.blueprintTarget
}
,
}
;
if (!string.IsNullOrEmpty(item.text)) itemdata["text"] = item.text;
var heldEnt = item.GetHeldEntity();
if (heldEnt != null) {
var projectiles = heldEnt.GetComponent<BaseProjectile>();
if (projectiles != null) {
var magazine = projectiles.primaryMagazine;
if (magazine != null) {
itemdata.Add("magazine", new Dictionary<string, object> {
{
magazine.ammoType.itemid.ToString(), magazine.contents
}
}
);
}
}
}
if (item?.contents?.itemList != null) {
var contents = new List<object>();
foreach (Item itemContains in item.contents.itemList) {
contents.Add(new Dictionary<string, object> {
{
"id", itemContains.info.itemid
}
, {
"amount", itemContains.amount
}
,
}
);
}
itemdata["items"] = contents;
}
itemlist.Add(itemdata);
}
data.Add("items", itemlist);
}
var sign = entity as Signage;
if (sign != null) {
var imageByte = FileStorage.server.Get(sign.textureID, FileStorage.Type.png, sign.net.ID);
data.Add("sign", new Dictionary<string, object> {
{
"locked", sign.IsLocked()
}
}
);
if (sign.textureID > 0 && imageByte != null) ((Dictionary<string, object>)data["sign"]).Add("texture", Convert.ToBase64String(imageByte));
}
if (copyData.SaveShare) {
var sleepingBag = entity as SleepingBag;
if (sleepingBag != null) {
data.Add("sleepingbag", new Dictionary<string, object> {
{
"niceName", sleepingBag.niceName
}
, {
"deployerUserID", sleepingBag.deployerUserID
}
, {
"isPublic", sleepingBag.IsPublic()
}
,
}
);
}
var cupboard = entity as BuildingPrivlidge;
if (cupboard != null) {
data.Add("cupboard", new Dictionary<string, object> {
{
"authorizedPlayers", cupboard.authorizedPlayers.Select(y => y.userid).ToList()
}
}
);
}
var autoTurret = entity as AutoTurret;
if (autoTurret != null) {
data.Add("autoturret", new Dictionary<string, object> {
{
"authorizedPlayers", autoTurret.authorizedPlayers.Select(p => p.userid).ToList()
}
}
);
}
}
var vendingMachine = entity as VendingMachine;
if (vendingMachine != null) {
var sellOrders = new List<object>();
foreach (var vendItem in vendingMachine.sellOrders.sellOrders) {
sellOrders.Add(new Dictionary<string, object> {
{
"itemToSellID", vendItem.itemToSellID
}
, {
"itemToSellAmount", vendItem.itemToSellAmount
}
, {
"currencyID", vendItem.currencyID
}
, {
"currencyAmountPerItem", vendItem.currencyAmountPerItem
}
, {
"inStock", vendItem.inStock
}
, {
"currencyIsBP", vendItem.currencyIsBP
}
, {
"itemToSellIsBP", vendItem.itemToSellIsBP
}
,
}
);
}
data.Add("vendingmachine", new Dictionary<string, object> {
{
"shopName", vendingMachine.shopName
}
, {
"isBroadcasting", vendingMachine.IsBroadcasting()
}
, {
"sellOrders", sellOrders
}
}
);
}
var ioEntity = entity as IOEntity;
if (ioEntity != null) {
var ioData = new Dictionary<string, object>();
List<object> inputs = ioEntity.inputs.Select(input => new Dictionary<string, object> {
{
"connectedID", input.connectedTo.entityRef.uid
}
, {
"connectedToSlot", input.connectedToSlot
}
, {
"niceName", input.niceName
}
, {
"type", (int) input.type
}
,
}
).Cast<object>().ToList();
ioData.Add("inputs", inputs);
List<object> outputs = new List<object>();
foreach (IOEntity.IOSlot output in ioEntity.outputs) {
Dictionary<string, object> ioConnection = new Dictionary<string, object> {
{
"connectedID", output.connectedTo.entityRef.uid
}
, {
"connectedToSlot", output.connectedToSlot
}
, {
"niceName", output.niceName
}
, {
"type", (int)output.type
}
,
}
;
var linePoints = new List<Vector3>();
if (output.linePoints != null) {
// Since Vector3 is struct should be able to simply save the Vecot directly.foreach (Vector3 linePoint in output.linePoints)
{
linePoints.Add(NormalizePosition(copyData.SourcePos, linePoint, copyData.RotCor));
}
}
ioConnection.Add("linePoints", linePoints);
outputs.Add(ioConnection);
}
ioData.Add("outputs", outputs);
ioData.Add("oldID", ioEntity.net.ID);
var electricalBranch = ioEntity.GetComponentInParent<ElectricalBranch>();
if (electricalBranch != null) {
ioData.Add("branchAmount", electricalBranch.branchAmount);
}
/*var counter = ioEntity.GetComponentInParent<PowerCounter>();
if (counter != null)
{
ioData.Add("targetNumber", counter.GetTarget());
}*/
var timer = ioEntity.GetComponentInParent<TimerSwitch>();
if (timer != null) {
ioData.Add("timerLength", timer.timerLength);
}
data.Add("IOEntity", ioData);
}
return data;
}
private object FindBestHeight(HashSet<Dictionary<string, object>> entities, Vector3 startPos) {
float maxHeight = 0f;
foreach (var entity in entities) {
if (((string)entity["prefabname"]).Contains("/foundation/")) {
var foundHeight = GetGround((Vector3)entity["position"]);
if (foundHeight != null) {
var height = (Vector3)foundHeight;
if (height.y > maxHeight) maxHeight = height.y;
}
}
}
maxHeight += 1f;
return maxHeight;
}
private bool FindRayEntity(Vector3 sourcePos, Vector3 sourceDir, out Vector3 point, out BaseEntity entity, int rayLayer) {
RaycastHit hitinfo;
entity = null;
point = Vector3.zero;
if (!Physics.Raycast(sourcePos, sourceDir, out hitinfo, 1000f, rayLayer)) return false;
entity = hitinfo.GetEntity();
point = hitinfo.point;
return true;
}
private void FixSignage(Signage sign, byte[] imageBytes) {
if (!signSizes.ContainsKey(sign.ShortPrefabName)) return;
byte[] resizedImage = ImageResize(imageBytes, signSizes[sign.ShortPrefabName].width, signSizes[sign.ShortPrefabName].height);
sign.textureID = FileStorage.server.Store(resizedImage, FileStorage.Type.png, sign.net.ID);
}
private object GetGround(Vector3 pos) {
RaycastHit hitInfo;
if (Physics.Raycast(pos, Vector3.up, out hitInfo, groundLayer)) return hitInfo.point;
if (Physics.Raycast(pos, Vector3.down, out hitInfo, groundLayer)) return hitInfo.point;
return null;
}
private int GetItemID(int itemID) {
if(replaceItemID.ContainsKey(itemID)) return replaceItemID[itemID];
return itemID;
}
private bool HasAccess(BasePlayer player, string permName) {
return player.IsAdmin || permission.UserHasPermission(player.UserIDString, permName);
}
private byte[] ImageResize(byte[] imageBytes, int width, int height) {
Bitmap resizedImage = new Bitmap(width, height), sourceImage = new Bitmap(new MemoryStream(imageBytes));
Graphics.FromImage(resizedImage).DrawImage(sourceImage, new Rectangle(0, 0, width, height), new Rectangle(0, 0, sourceImage.Width, sourceImage.Height), GraphicsUnit.Pixel);
MemoryStream ms = new MemoryStream();
resizedImage.Save(ms, ImageFormat.Png);
return ms.ToArray();
}
private string Lang(string key, string userID = null, params object[] args) => string.Format(lang.GetMessage(key, this, userID), args);
private Vector3 NormalizePosition(Vector3 InitialPos, Vector3 CurrentPos, float diffRot) {
var transformedPos = CurrentPos - InitialPos;
var newX = (transformedPos.x * (float)System.Math.Cos(-diffRot)) + (transformedPos.z * (float)System.Math.Sin(-diffRot));
var newZ = (transformedPos.z * (float)System.Math.Cos(-diffRot)) - (transformedPos.x * (float)System.Math.Sin(-diffRot));
transformedPos.x = newX;
transformedPos.z = newZ;
return transformedPos;
}
private void Paste(ICollection<Dictionary<string, object>> entities, Dictionary<string, object> protocol, Vector3 startPos, BasePlayer player, bool stability, float RotationCorrection, float heightAdj, bool auth, Action callback) {
var ioEntities = new Dictionary<uint, Dictionary<string, object>>();
uint buildingID = 0;
//Settings
bool isItemReplace = !protocol.ContainsKey("items");
var eulerRotation = new Vector3(0f, RotationCorrection * 57.2958f, 0f);
var quaternionRotation = Quaternion.Euler(eulerRotation);
var pasteData = new PasteData() {
HeightAdj = heightAdj, IsItemReplace = isItemReplace, Entities = entities, Player = player, QuaternionRotation = quaternionRotation, StartPos = startPos, Stability = stability, Auth = auth, callback = callback
}
;
NextTick(() => PasteLoop(pasteData));
}
private void PasteLoop(PasteData pasteData) {
var entities = pasteData.Entities;
var todo = entities.Take(config.PasteBatchSize).ToArray();
var player = pasteData.Player;
foreach (var data in todo) {
entities.Remove(data);
var prefabname = (string)data["prefabname"];
ulong skinid = ulong.Parse(data["skinid"].ToString());
var pos = (Vector3)data["position"];
var rot = (Quaternion)data["rotation"];
ulong ownerId = player?.userID ?? 0;
if (data.ContainsKey("ownerid")) {
ownerId = Convert.ToUInt64(data["ownerid"]);
}
if (CheckPlaced(prefabname, pos, rot)) continue;
if (prefabname.Contains("pillar")) continue;
var entity = GameManager.server.CreateEntity(prefabname, pos, rot, true);
if (entity == null) continue;
entity.transform.position = pos;
entity.transform.rotation = rot;
if (player != null) entity.SendMessage("SetDeployedBy", player, SendMessageOptions.DontRequireReceiver);
entity.OwnerID = ownerId;
BuildingBlock buildingBlock = entity as BuildingBlock;
if (buildingBlock != null) {
buildingBlock.blockDefinition = PrefabAttribute.server.Find<Construction>(buildingBlock.prefabID);
buildingBlock.SetGrade((BuildingGrade.Enum)data["grade"]);
if(!pasteData.Stability) buildingBlock.grounded = true;
}
DecayEntity decayEntity = entity as DecayEntity;
if (decayEntity != null) {
if (pasteData.BuildingID == 0) pasteData.BuildingID = BuildingManager.server.NewBuildingID();
decayEntity.AttachToBuilding(pasteData.BuildingID);
}
StabilityEntity stabilityEntity = entity as StabilityEntity;
if (stabilityEntity != null) {
if (!stabilityEntity.grounded) {
stabilityEntity.grounded = true;
pasteData.StabilityEntities.Add(stabilityEntity);
}
}
entity.skinID = skinid;
entity.Spawn();
var baseCombat = entity as BaseCombatEntity;
if (baseCombat != null) baseCombat.ChangeHealth(baseCombat.MaxHealth());
pasteData.PastedEntities.AddRange(TryPasteSlots(entity, data, pasteData));
var box = entity as StorageContainer;
if (box != null) {
Locker locker = box as Locker;
if (locker != null) locker.equippingActive = true;
box.inventory.Clear();
var items = new List<object>();
if (data.ContainsKey("items")) items = data["items"] as List<object>;
foreach (var itemDef in items) {
var item = itemDef as Dictionary<string, object>;
var itemid = Convert.ToInt32(item["id"]);
var itemamount = Convert.ToInt32(item["amount"]);
var itemskin = ulong.Parse(item["skinid"].ToString());
var itemcondition = Convert.ToSingle(item["condition"]);
if (pasteData.IsItemReplace) itemid = GetItemID(itemid);
var i = ItemManager.CreateByItemID(itemid, itemamount, itemskin);
if (i != null) {
i.condition = itemcondition;
if (item.ContainsKey("text")) i.text = item["text"].ToString();
if (item.ContainsKey("blueprintTarget")) {
int blueprintTarget = Convert.ToInt32(item["blueprintTarget"]);
if (pasteData.IsItemReplace) blueprintTarget = GetItemID(blueprintTarget);
i.blueprintTarget = blueprintTarget;
}
if (item.ContainsKey("magazine")) {
var heldent = i.GetHeldEntity();
if (heldent != null) {
var projectiles = heldent.GetComponent<BaseProjectile>();
if (projectiles != null) {
var magazine = item["magazine"] as Dictionary<string, object>;
var ammotype = int.Parse(magazine.Keys.ToArray()[0]);
var ammoamount = int.Parse(magazine[ammotype.ToString()].ToString());
if (pasteData.IsItemReplace) ammotype = GetItemID(ammotype);
projectiles.primaryMagazine.ammoType = ItemManager.FindItemDefinition(ammotype);
projectiles.primaryMagazine.contents = ammoamount;
}
//TODO Doesn't add water to some containers
if (item.ContainsKey("items")) {
var itemContainsList = item["items"] as List<object>;
foreach (var itemContains in itemContainsList) {
var contents = itemContains as Dictionary<string, object>;
int contentsItemID = Convert.ToInt32(contents["id"]);
if (pasteData.IsItemReplace) contentsItemID = GetItemID(contentsItemID);
i.contents.AddItem(ItemManager.FindItemDefinition(contentsItemID), Convert.ToInt32(contents["amount"]));
}
}
}
}
int targetPos = -1;
if (item.ContainsKey("position")) targetPos = Convert.ToInt32(item["position"]);
i.MoveToContainer(box.inventory, targetPos);
}
}
if (locker != null) locker.equippingActive = false;
}
var sign = entity as Signage;
if (sign != null && data.ContainsKey("sign")) {
var signData = data["sign"] as Dictionary<string, object>;
if (signData.ContainsKey("texture")) {
byte[] imageBytes = Convert.FromBase64String(signData["texture"].ToString());
FixSignage(sign, imageBytes);
}
if (Convert.ToBoolean(signData["locked"])) sign.SetFlag(BaseEntity.Flags.Locked, true);
sign.SendNetworkUpdate();
}
var sleepingBag = entity as SleepingBag;
if (sleepingBag != null && data.ContainsKey("sleepingbag")) {
var bagData = data["sleepingbag"] as Dictionary<string, object>;
sleepingBag.niceName = bagData["niceName"].ToString();
sleepingBag.deployerUserID = ulong.Parse(bagData["deployerUserID"].ToString());
sleepingBag.SetPublic(Convert.ToBoolean(bagData["isPublic"]));
}
var autoturret = entity as AutoTurret;
if (autoturret != null) {
List<ulong> authorizedPlayers = new List<ulong>();
if (data.ContainsKey("autoturret")) {
var autoTurretData = data["autoturret"] as Dictionary<string, object>;
authorizedPlayers = (autoTurretData["authorizedPlayers"] as List<object>).Select(Convert.ToUInt64).ToList();
}
if (player != null && !authorizedPlayers.Contains(player.userID) && pasteData.Auth) authorizedPlayers.Add(player.userID);
foreach (var userID in authorizedPlayers) {
autoturret.authorizedPlayers.Add(new PlayerNameID() {
userid = Convert.ToUInt64(userID), username = "Player"
}
);
}
autoturret.SendNetworkUpdate(BasePlayer.NetworkQueue.Update);
}
var cupboard = entity as BuildingPrivlidge;
if (cupboard != null) {
List<ulong> authorizedPlayers = new List<ulong>();
if (data.ContainsKey("cupboard")) {
var cupboardData = data["cupboard"] as Dictionary<string, object>;
authorizedPlayers = (cupboardData["authorizedPlayers"] as List<object>).Select(Convert.ToUInt64).ToList();
}
if (player != null && !authorizedPlayers.Contains(player.userID) && pasteData.Auth) authorizedPlayers.Add(player.userID);
foreach (var userID in authorizedPlayers) {
cupboard.authorizedPlayers.Add(new PlayerNameID() {
userid = Convert.ToUInt64(userID), username = "Player"
}
);
}
cupboard.SendNetworkUpdate(BasePlayer.NetworkQueue.Update);
}
var vendingMachine = entity as VendingMachine;
if (vendingMachine != null && data.ContainsKey("vendingmachine")) {
var vendingData = data["vendingmachine"] as Dictionary<string, object>;
vendingMachine.shopName = vendingData["shopName"].ToString();
vendingMachine.SetFlag(BaseEntity.Flags.Reserved4, Convert.ToBoolean(vendingData["isBroadcasting"]));
var sellOrders = vendingData["sellOrders"] as List<object>;
foreach (var orderPreInfo in sellOrders) {
var orderInfo = orderPreInfo as Dictionary<string, object>;
if (!orderInfo.ContainsKey("inStock")) {
orderInfo["inStock"] = 0;
orderInfo["currencyIsBP"] = false;
orderInfo["itemToSellIsBP"] = false;
}
int itemToSellID = Convert.ToInt32(orderInfo["itemToSellID"]), currencyID = Convert.ToInt32(orderInfo["currencyID"]);
if (pasteData.IsItemReplace) {
itemToSellID = GetItemID(itemToSellID);
currencyID = GetItemID(currencyID);
}
vendingMachine.sellOrders.sellOrders.Add(new ProtoBuf.VendingMachine.SellOrder() {
ShouldPool = false, itemToSellID = itemToSellID, itemToSellAmount = Convert.ToInt32(orderInfo["itemToSellAmount"]), currencyID = currencyID, currencyAmountPerItem = Convert.ToInt32(orderInfo["currencyAmountPerItem"]), inStock = Convert.ToInt32(orderInfo["inStock"]), currencyIsBP = Convert.ToBoolean(orderInfo["currencyIsBP"]), itemToSellIsBP = Convert.ToBoolean(orderInfo["itemToSellIsBP"]),
}
);
}
vendingMachine.FullUpdate();
}
var ioEntity = entity as IOEntity;
if (ioEntity != null) {
var ioData = new Dictionary<string, object>();
if (data.ContainsKey("IOEntity")) {
ioData = data["IOEntity"] as Dictionary<string, object> ?? new Dictionary<string, object>();
}
ioData.Add("entity", ioEntity);
ioData.Add("newId", ioEntity.net.ID);
object oldIdObject = 0;
if (ioData.TryGetValue("oldID", out oldIdObject)) {
var oldId = Convert.ToUInt32(oldIdObject);
pasteData.IoEntities.Add(oldId, ioData);
}
}
var flagsData = new Dictionary<string, object>();
if (data.ContainsKey("flags")) flagsData = data["flags"] as Dictionary<string, object>;
var flags = new Dictionary<BaseEntity.Flags, bool>();
foreach (var flagData in flagsData) {
BaseEntity.Flags baseFlag;
if(Enum.TryParse(flagData.Key, out baseFlag)) flags.Add(baseFlag, Convert.ToBoolean(flagData.Value));
}
foreach (var flag in flags) {
entity.SetFlag(flag.Key, flag.Value);
}
pasteData.PastedEntities.Add(entity);
}
if (entities.Count > 0) NextTick(() => PasteLoop(pasteData));
else {
foreach (var ioData in pasteData.IoEntities.Values.ToArray()) {
if (!ioData.ContainsKey("entity")) continue;
var ioEntity = ioData["entity"] as IOEntity;
List<object> inputs = null;
if (ioData.ContainsKey("inputs")) inputs = ioData["inputs"] as List<object>;
var electricalBranch = ioEntity as ElectricalBranch;
if (electricalBranch != null && ioData.ContainsKey("branchAmount")) {
electricalBranch.branchAmount = Convert.ToInt32(ioData["branchAmount"]);
}
// Realized counter.targetCounterNumber is
// ... [Code preview truncated due to length. Full source in attached file] ...