C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
// Reference: System.Drawing
using Facepunch;
using Graphics = System.Drawing.Graphics;
using ImageFormat = System.Drawing.Imaging.ImageFormat;
using Oxide.Core;
using Oxide.Core.Libraries;
using Newtonsoft.Json;
using ProtoBuf;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using UnityEngine;
namespace Oxide.Plugins {
[Info("Copy Paste", "Reneb", "3.5.7", ResourceId = 716)]
[Description("Copy and paste your buildings to save them or move them")]
class CopyPaste : RustPlugin {
private int copyLayer = LayerMask.GetMask("Construction", "Construction Trigger", "Trigger", "Deployed", "Default");
private int groundLayer = LayerMask.GetMask("Terrain", "Default");
private int rayCopy = LayerMask.GetMask("Construction", "Deployed", "Tree", "Resource", "Prevent Building");
private int rayPaste = LayerMask.GetMask("Construction", "Deployed", "Tree", "Terrain", "World", "Water", "Prevent Building");
private string copyPermission = "copypaste.copy";
private string pastePermission = "copypaste.paste";
private string undoPermission = "copypaste.undo";
private string serverID = "Server";
private string 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
}
;
private enum CopyMechanics {
Building, Proximity
}
private FieldInfo _equippingActive = typeof(Locker).GetField("equippingActive", BindingFlags.Instance | BindingFlags.NonPublic);
private FieldInfo _colBuffer = typeof(Vis).GetField("colBuffer", BindingFlags.NonPublic | BindingFlags.Static);
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;
}
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;
}
}
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(pastePermission, 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();
_colBuffer.SetValue(null, new Collider[8192 * 16]);
}
//API
object TryCopyFromSteamID(ulong userID, string filename, string[] args) {
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().transform.rotation.ToEulerAngles(), filename, Quaternion.Euler(player.GetNetworkRotation()).ToEulerAngles().y, args);
}
object TryPasteFromSteamID(ulong userID, string filename, string[] args) {
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, Quaternion.Euler(player.GetNetworkRotation()).ToEulerAngles().y, args);
}
object TryPasteFromVector3(Vector3 pos, float rotationCorrection, string filename, string[] args) {
return TryPaste(pos, filename, null, rotationCorrection, args);
}
//Other methods
private object CheckCollision(List<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;
if(!lastPastes.ContainsKey(userIDString)) lastPastes[userIDString] = new Stack<List<BaseEntity>>();
lastPastes[userIDString].Push((List<BaseEntity>)success);
return true;
}
private object cmdUndo(string userIDString, string[] args) {
if(!lastPastes.ContainsKey(userIDString)) return Lang("NO_PASTED_STRUCTURE", userIDString);
foreach(var entity in lastPastes[userIDString].Pop()) {
if(entity == null || entity.IsDestroyed) continue;
entity.Kill();
}
if(lastPastes[userIDString].Count == 0) lastPastes.Remove(userIDString);
return true;
}
private object Copy(Vector3 sourcePos, Vector3 sourceRot, string filename, float RotationCorrection, CopyMechanics copyMechanics, float range, bool saveTree, bool saveShare, bool eachToEach) {
var copy = CopyProcess(sourcePos, sourceRot, RotationCorrection, range, saveTree, saveShare, copyMechanics, eachToEach);
if(copy is string) return copy;
var defaultData = new Dictionary<string, object> {
{
"position", new Dictionary<string, object> {
{
"x", sourcePos.x.ToString()
}
, {
"y", sourcePos.y.ToString()
}
, {
"z", sourcePos.z.ToString()
}
}
}
, {
"rotationy", sourceRot.y.ToString()
}
, {
"rotationdiff", RotationCorrection.ToString()
}
}
;
string path = subDirectory + filename;
var CopyData = Interface.Oxide.DataFileSystem.GetDatafile(path);
CopyData.Clear();
CopyData["default"] = defaultData;
CopyData["entities"] = copy as List<object>;
Interface.Oxide.DataFileSystem.SaveDatafile(path);
return true;
}
private object CopyProcess(Vector3 sourcePos, Vector3 sourceRot, float RotationCorrection, float range, bool saveTree, bool saveShare, CopyMechanics copyMechanics, bool eachToEach) {
List<object> rawData = new List<object>();
HashSet<BaseEntity> houseList = new HashSet<BaseEntity>();
List<Vector3> checkFrom = new List<Vector3> {
sourcePos
}
;
int currentLayer = copyLayer, current = 0;
uint buildingID = 0;
if(saveTree) currentLayer |= LayerMask.GetMask("Tree");
while(current < checkFrom.Count) {
List<BaseEntity> list = Pool.GetList<BaseEntity>();
Vis.Entities<BaseEntity>(checkFrom[current], range, list, 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(eachToEach && !checkFrom.Contains(entity.transform.position)) checkFrom.Add(entity.transform.position);
rawData.Add(EntityData(entity, sourcePos, sourceRot, entity.transform.position, entity.transform.rotation.ToEulerAngles(), RotationCorrection, saveShare));
}
Pool.FreeList(ref list);
current++;
}
return rawData;
}
private Dictionary<string, object> EntityData(BaseEntity entity, Vector3 sourcePos, Vector3 sourceRot, Vector3 entPos, Vector3 entRot, float diffRot, bool saveShare) {
var normalizedPos = NormalizePosition(sourcePos, entPos, diffRot);
entRot.y -= diffRot;
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()
}
,
}
}
}
;
TryCopySlots(entity, data, saveShare);
var buildingblock = entity.GetComponentInParent<BuildingBlock>();
if(buildingblock != null ) {
data.Add("grade", buildingblock.grade);
}
var box = entity.GetComponentInParent<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
}
,
}
;
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.GetComponentInParent<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(saveShare) {
var sleepingBag = entity.GetComponentInParent<SleepingBag>();
if(sleepingBag != null) {
data.Add("sleepingbag", new Dictionary<string, object> {
{
"niceName", sleepingBag.niceName
}
, {
"deployerUserID", sleepingBag.deployerUserID
}
, {
"isPublic", sleepingBag.IsPublic()
}
,
}
);
}
var cupboard = entity.GetComponentInParent<BuildingPrivlidge>();
if(cupboard != null) {
data.Add("cupboard", new Dictionary<string, object> {
{
"authorizedPlayers", cupboard.authorizedPlayers.Select(y => y.userid).ToList()
}
}
);
}
}
var vendingMachine = entity.GetComponentInParent<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
}
,
}
);
}
data.Add("vendingmachine", new Dictionary<string, object> {
{
"shopName", vendingMachine.shopName
}
, {
"isBroadcasting", vendingMachine.IsBroadcasting()
}
, {
"sellOrders", sellOrders
}
}
);
}
return data;
}
private object FindBestHeight(List<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 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 List<BaseEntity> Paste(List<Dictionary<string, object>> entities, Vector3 startPos, BasePlayer player, bool stability) {
uint buildingID = 0;
var pastedEntities = new List<BaseEntity>();
foreach(var data in entities) {
string prefabname = (string)data["prefabname"];
ulong skinid = ulong.Parse(data["skinid"].ToString());
Vector3 pos = (Vector3)data["position"];
Quaternion rot = (Quaternion)data["rotation"];
if(CheckPlaced(prefabname, pos, rot)) 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 = player.userID;
}
BuildingBlock buildingBlock = entity.GetComponentInParent<BuildingBlock>();
if(buildingBlock != null) {
buildingBlock.blockDefinition = PrefabAttribute.server.Find<Construction>(buildingBlock.prefabID);
buildingBlock.SetGrade((BuildingGrade.Enum)data["grade"]);
if(!stability) buildingBlock.grounded = true;
}
DecayEntity decayEntity = entity.GetComponentInParent<DecayEntity>();
if(decayEntity != null) {
if(buildingID == 0) buildingID = BuildingManager.server.NewBuildingID();
decayEntity.AttachToBuilding(buildingID);
}
entity.skinID = skinid;
entity.Spawn();
var baseCombat = entity.GetComponentInParent<BaseCombatEntity>();
if(baseCombat != null) baseCombat.ChangeHealth(baseCombat.MaxHealth());
pastedEntities.AddRange(TryPasteSlots(entity, data));
var box = entity.GetComponentInParent<StorageContainer>();
if(box != null) {
Locker locker = box as Locker;
if(locker != null) _equippingActive.SetValue(locker, 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"]);
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("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());
projectiles.primaryMagazine.ammoType = ItemManager.FindItemDefinition(ammotype);
projectiles.primaryMagazine.contents = ammoamount;
}
//TODO Не добавляет капли воды в некоторые контейнеры
if(item.ContainsKey("items")) {
var itemContainsList = item["items"] as List<object>;
foreach(var itemContains in itemContainsList) {
var contents = itemContains as Dictionary<string, object>;
i.contents.AddItem(ItemManager.FindItemDefinition(Convert.ToInt32(contents["id"])), Convert.ToInt32(contents["amount"]));
}
}
}
}
int targetPos = -1;
if(item.ContainsKey("position")) targetPos = Convert.ToInt32(item["position"]);
i.MoveToContainer(box.inventory, targetPos);
}
}
if(locker != null) _equippingActive.SetValue(locker, false);
}
var sign = entity.GetComponentInParent<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.GetComponentInParent<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.GetComponentInParent<AutoTurret>();
if(autoturret != null) {
if(player != null) {
autoturret.authorizedPlayers.Add(new PlayerNameID() {
userid = Convert.ToUInt64(player.userID), username = "Player"
}
);
}
autoturret.SendNetworkUpdate(BasePlayer.NetworkQueue.Update);
}
var cupboard = entity.GetComponentInParent<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(y => Convert.ToUInt64(y)).ToList();
}
if(data.ContainsKey("auth") && player != null && !authorizedPlayers.Contains(player.userID)) 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.GetComponentInParent<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>;
vendingMachine.sellOrders.sellOrders.Add(new ProtoBuf.VendingMachine.SellOrder() {
ShouldPool = false, itemToSellID = Convert.ToInt32(orderInfo["itemToSellID"]), itemToSellAmount = Convert.ToInt32(orderInfo["itemToSellAmount"]), currencyID = Convert.ToInt32(orderInfo["currencyID"]), currencyAmountPerItem = Convert.ToInt32(orderInfo["currencyAmountPerItem"])
}
);
}
vendingMachine.FullUpdate();
}
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) {
try //Enum.TryParse?
{
BaseEntity.Flags baseFlag = (BaseEntity.Flags)Enum.Parse(typeof(BaseEntity.Flags), flagData.Key);
flags.Add(baseFlag, Convert.ToBoolean(flagData.Value));
}
catch (Exception ex) {
}
}
foreach(var flag in flags) {
entity.SetFlag(flag.Key, flag.Value);
}
pastedEntities.Add(entity);
}
return pastedEntities;
}
private List<Dictionary<string, object>> PreLoadData(List<object> entities, Vector3 startPos, float RotationCorrection, bool deployables, bool inventories, bool auth, bool vending) {
var eulerRotation = new Vector3(0f, RotationCorrection, 0f);
var quaternionRotation = Quaternion.EulerRotation(eulerRotation);
var preloaddata = new List<Dictionary<string, object>>();
foreach(var entity in entities) {
var data = entity as Dictionary<string, object>;
if(!deployables && !data.ContainsKey("grade")) continue;
var pos = (Dictionary<string, object>)data["pos"];
var rot = (Dictionary<string, object>)data["rot"];
data.Add("position", quaternionRotation * (new Vector3(Convert.ToSingle(pos["x"]), Convert.ToSingle(pos["y"]), Convert.ToSingle(pos["z"]))) + startPos);
data.Add("rotation", Quaternion.EulerRotation(eulerRotation + new Vector3(Convert.ToSingle(rot["x"]), Convert.ToSingle(rot["y"]), Convert.ToSingle(rot["z"]))));
if(!inventories && data.ContainsKey("items")) data["items"] = new List<object>();
if(auth && data["prefabname"].ToString().Contains("cupboard.tool")) data["auth"] = true;
if(!vending && data["prefabname"].ToString().Contains("vendingmachine")) data.Remove("vendingmachine");
preloaddata.Add(data);
}
return preloaddata;
}
private object TryCopy(Vector3 sourcePos, Vector3 sourceRot, string filename, float RotationCorrection, string[] args) {
bool saveShare = config.Copy.Share, saveTree = config.Copy.Tree, eachToEach = config.Copy.EachToEach;
CopyMechanics copyMechanics = CopyMechanics.Proximity;
float radius = 3f;
for(int i = 0; ; i = i + 2) {
if(i >= args.Length) break;
int valueIndex = i + 1;
if(valueIndex >= args.Length) return Lang("SYNTAX_COPY", null);
string param = args[i].ToLower();
switch(param) {
case "e" : case "each" : if(!bool.TryParse(args[valueIndex], out eachToEach)) return Lang("SYNTAX_BOOL", null, param);
break;
case "m" : case "method" : switch(args[valueIndex].ToLower()) {
case "b" : case "building" : copyMechanics = CopyMechanics.Building;
break;
case "p" : case "proximity" : copyMechanics = CopyMechanics.Proximity;
break;
}
break;
case "r" : case "radius" : if(!float.TryParse(args[valueIndex], out radius)) return Lang("SYNTAX_RADIUS", null);
break;
case "s" : case "share" : if(!bool.TryParse(args[valueIndex], out saveShare)) return Lang("SYNTAX_BOOL", null, param);
break;
case "t" : case "tree" : if(!bool.TryParse(args[valueIndex], out saveTree)) return Lang("SYNTAX_BOOL", null, param);
break;
default : return Lang("SYNTAX_COPY", null);
}
}
return Copy(sourcePos, sourceRot, filename, RotationCorrection, copyMechanics, radius, saveTree, saveShare, eachToEach);
}
private void TryCopySlots(BaseEntity ent, IDictionary<string, object> housedata, bool saveShare) {
foreach(BaseEntity.Slot slot in checkSlots) {
if(!ent.HasSlot(slot)) continue;
var slotEntity = ent.GetSlot(slot);
if(slotEntity == null) continue;
var codedata = new Dictionary<string, object> {
{
"prefabname", slotEntity.PrefabName
}
, {
"flags", TryCopyFlags(ent)
}
}
;
if(slotEntity.GetComponent<CodeLock>()) {
CodeLock codeLock = slotEntity.GetComponent<CodeLock>();
codedata.Add("code", codeLock.code);
if(saveShare) codedata.Add("whitelistPlayers", codeLock.whitelistPlayers);
if(codeLock.guestCode != null && codeLock.guestCode.Length == 4) {
codedata.Add("guestCode", codeLock.guestCode);
if(saveShare) codedata.Add("guestPlayers", codeLock.guestPlayers);
}
}
else if(slotEntity.GetComponent<KeyLock>()) {
KeyLock keyLock = slotEntity.GetComponent<KeyLock>();
var code = keyLock.keyCode;
if(keyLock.firstKeyCreated) code |= 0x80;
codedata.Add("code", code.ToString());
}
string slotName = slot.ToString().ToLower();
housedata.Add(slotName, codedata);
}
}
private Dictionary<string, object> TryCopyFlags(BaseEntity entity) {
var flags = new Dictionary<string, object>();
foreach(BaseEntity.Flags flag in Enum.GetValues(typeof(BaseEntity.Flags))) {
flags.Add(flag.ToString(), entity.HasFlag(flag));
}
return flags;
}
private object TryPaste(Vector3 startPos, string filename, BasePlayer player, float RotationCorrection, string[] args, bool autoHeight = true) {
var userID = player?.UserIDString;
string path = subDirectory + filename;
if(!Interface.Oxide.DataFileSystem.ExistsDatafile(path)) return Lang("FILE_NOT_EXISTS", userID);
var data = Interface.Oxide.DataFileSystem.GetDatafile(path);
if(data["default"] == null || data["entities"] == null) return Lang("FILE_BROKEN", userID);
float heightAdj = 0f, blockCollision = 0f;
bool auth = config.Paste.Auth, inventories = config.Paste.Inventories, deployables = config.Paste.Deployables, vending = config.Paste.VendingMachines, stability = config.Paste.Stability;
for(int i = 0; ; i = i + 2) {
if(i >= args.Length) break;
int valueIndex = i + 1;
if(valueIndex >= args.Length) return Lang("SYNTAX_PASTE_OR_PASTEBACK", userID);
string param = args[i].ToLower();
switch(param) {
case "a" : case "auth" : if(!bool.TryParse(args[valueIndex], out auth)) return Lang("SYNTAX_BOOL", userID, param);
break;
case "b" : case "blockcollision" : if(!float.TryParse(args[valueIndex], out blockCollision)) return Lang("SYNTAX_BLOCKCOLLISION", userID);
break;
case "d" : case "deployables" : if(!bool.TryParse(args[valueIndex], out deployables)) return Lang("SYNTAX_BOOL", userID, param);
break;
case "height" : if(!float.TryParse(args[valueIndex], out heightAdj)) return Lang("SYNTAX_HEIGHT", userID);
autoHeight = false;
break;
case "i" : case "inventories" : if(!bool.TryParse(args[valueIndex], out inventories)) return Lang("SYNTAX_BOOL", userID, param);
break;
case "s" : case "stability" : if(!bool.TryParse(args[valueIndex], out stability)) return Lang("SYNTAX_BOOL", userID, param);
break;
case "v" : case "vending" : if(!bool.TryParse(args[valueIndex], out vending)) return Lang("SYNTAX_BOOL", userID, param);
break;
default : return Lang("SYNTAX_PASTE_OR_PASTEBACK", userID);
}
}
startPos.y += heightAdj;
var preloadData = PreLoadData(data["entities"] as List<object>, startPos, RotationCorrection, deployables, inventories, auth, vending);
if(autoHeight) {
var bestHeight = FindBestHeight(preloadData, startPos);
if(bestHeight is string) return bestHeight;
heightAdj = (float)bestHeight - startPos.y;
foreach(var entity in preloadData) {
var pos = ((Vector3)entity["position"]);
pos.y += heightAdj;
entity["position"] = pos;
}
}
if(blockCollision > 0f) {
var collision = CheckCollision(preloadData, startPos, blockCollision);
if(collision is string) return collision;
}
return Paste(preloadData, startPos, player, stability);
}
private List<BaseEntity> TryPasteSlots(BaseEntity ent, Dictionary<string, object> structure) {
List<BaseEntity> entitySlots = new List<BaseEntity>();
foreach(BaseEntity.Slot slot in checkSlots) {
string slotName = slot.ToString().ToLower();
if(!ent.HasSlot(slot) || !structure.ContainsKey(slotName)) continue;
var slotData = structure[slotName] as Dictionary<string, object>;
BaseEntity slotEntity = GameManager.server.CreateEntity((string)slotData["prefabname"], Vector3.zero, new Quaternion(), true);
if(slotEntity == null) continue;
slotEntity.gameObject.Identity();
slotEntity.SetParent(ent, slotName);
slotEntity.OnDeployed(ent);
slotEntity.Spawn();
ent.SetSlot(slot, slotEntity);
entitySlots.Add(slotEntity);
if(slotName != "lock" || !slotData.ContainsKey("code")) continue;
if(slotEntity.GetComponent<CodeLock>()) {
string code = (string)slotData["code"];
if(!string.IsNullOrEmpty(code)) {
CodeLock codeLock = slotEntity.GetComponent<CodeLock>();
codeLock.code = code;
codeLock.hasCode = true;
if(slotData.ContainsKey("whitelistPlayers")) {
foreach(var userID in slotData["whitelistPlayers"] as List<object>) {
codeLock.whitelistPlayers.Add(Convert.ToUInt64(userID));
}
}
if(slotData.ContainsKey("guestCode")) {
string guestCode = (string)slotData["guestCode"];
codeLock.guestCode = guestCode;
codeLock.hasGuestCode = true;
if(slotData.ContainsKey("guestPlayers")) {
foreach(var userID in slotData["guestPlayers"] as List<object>) {
codeLock.guestPlayers.Add(Convert.ToUInt64(userID));
}
}
}
codeLock.SetFlag(BaseEntity.Flags.Locked, true);
}
}
else if(slotEntity.GetComponent<KeyLock>()) {
int code = Convert.ToInt32(slotData["code"]);
KeyLock keyLock = slotEntity.GetComponent<KeyLock>();
if((code & 0x80) != 0) {
keyLock.keyCode = (code & 0x7F);
keyLock.firstKeyCreated = true;
keyLock.SetFlag(BaseEntity.Flags.Locked, true);
}
}
}
return entitySlots;
}
private object TryPasteBack(string filename, BasePlayer player, string[] args) {
string path = subDirectory + filename;
if(!Interface.Oxide.DataFileSystem.ExistsDatafile(path)) return Lang("FILE_NOT_EXISTS", player?.UserIDString);
var data = Interface.Oxide.DataFileSystem.GetDatafile(path);
// ... [Code preview truncated due to length. Full source in attached file] ...