Open you .cs file and replace all code with this code:
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Text;
using Network;
using Newtonsoft.Json;
using Oxide.Core.Configuration;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using ProtoBuf;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Edit Tool", "JakeRich", "1.0.4")]
[Description("Modify entities in a map")]
public class EditTool : RustPlugin
{
public static ulong ToolSkinID = 1175592586;
public static string ToolItemShortname = "coal";
public static string ToolName = "Edit Tool";
public static EditTool _plugin;
public static float EditToolDistance = 50f;
public static UIManager UI;
public static PlayerDataController<ToolPlayerData> PlayerData;
private const string permUse = "edittool.use";
private void Init()
{
_plugin = this;
UI = new UIManager();
PlayerData = new PlayerDataController<ToolPlayerData>();
permission.RegisterPermission(permUse, this);
for (ToolMode mode = ToolMode.Transform; mode < ToolMode.Last; mode++)
{
permission.RegisterPermission($"edittool.{mode.ToString().ToLower()}", this);
}
}
private void Unload()
{
UI.Unload();
}
private void OnPlayerInput(BasePlayer player, InputState input)
{
if (!player.IsAdmin)
{
if (!permission.UserHasPermission(player.UserIDString, permUse))
{
return;
}
}
if (!HasEditTool(player))
{
UI.ToolUI.Hide(player);
UI.EntityInfoLabel.Text = "";
UI.EntityInfoLabel.Refresh(player);
return;
}
UI.ToolUI.Show(player);
ToolPlayerData data = PlayerData.Get(player);
if (input.WasJustPressed(BUTTON.FIRE_THIRD))
{
data.SwitchMode();
}
BaseEntity entity;
Vector3 hitPoint;
if (!GetEntityLookingAt(player, out entity, out hitPoint, EditToolDistance))
{
NotLookingAtEntity(player);
}
if (entity == null)
{
NotLookingAtEntity(player);
}
else
{
LookingAtEntity(player, entity);
UI.EntityInfoLabel.Refresh(player);
}
if (input.WasJustPressed(BUTTON.FIRE_PRIMARY))
{
if (input.IsDown(BUTTON.SPRINT))
{
data.OnShiftLeftClick(entity, hitPoint);
}
else if (input.IsDown(BUTTON.RELOAD))
{
data.OnReloadClick(entity, hitPoint);
}
else
{
data.OnLeftClick(entity, hitPoint);
}
}
if (input.WasJustPressed(BUTTON.FIRE_SECONDARY))
{
if (input.IsDown(BUTTON.SPRINT))
{
data.OnShiftRightClick(entity, hitPoint);
}
else
{
data.OnRightClick(entity, hitPoint);
}
}
if (input.WasJustReleased(BUTTON.FIRE_PRIMARY))
{
data.OnLeftRelease();
}
if (input.WasJustReleased(BUTTON.FIRE_SECONDARY))
{
data.OnRightRelease();
}
data.OnPlayerInput(entity, input);
}
private void OnEntityKill(BaseNetworkable entity)
{
OreResourceEntity node = entity as OreResourceEntity;
if (node == null)
{
return;
}
node._hotSpot?.Kill();
}
private void NotLookingAtEntity(BasePlayer player)
{
UI.EntityInfoLabel.Text = "";
UI.EntityInfoLabel.Refresh(player);
}
private void LookingAtEntity(BasePlayer player, BaseEntity entity)
{
UI.EntityInfoLabel.Text = $"{entity.ShortPrefabName}";
}
public static bool IsEditTool(Item item)
{
if (item == null)
{
return false;
}
return item.skin == ToolSkinID;
}
public static bool HasEditTool(BasePlayer player)
{
Item item = player.GetActiveItem();
if (item == null)
{
return false;
}
return IsEditTool(item);
}
#region Entity Raycast
//public static int EditToolLayer = LayerMask.GetMask("AI", "Construction", "Deployed", "Default", "Debris", "Ragdoll", "Tree", "Terrain", "World", "Vehicle Movement");
public static int EditToolLayer = int.MaxValue;
public static bool GetEntityLookingAt(BasePlayer player, out BaseEntity entity, out Vector3 hitPoint, float distance = 5f, bool announceOnNotFound = false)
{
entity = null;
RaycastHit raycastHit;
Ray ray = player.eyes.BodyRay();
if (!Physics.Raycast(ray, out raycastHit, distance, EditToolLayer))
{
hitPoint = Vector3.zero;
return false;
}
else
{
hitPoint = raycastHit.point;
entity = raycastHit.GetEntity();
if (entity != null)
{
return true;
}
}
if (announceOnNotFound)
{
player.IPlayer.Message(GetLangMessage("NotLookingAtEntity", player));
}
return true;
}
#endregion Entity Raycast
[ChatCommand("edittool")]
private void GiveEditTool_Command(BasePlayer player, string command, string[] args)
{
if (!player.IsAdmin)
{
return;
}
GiveEditTool(player);
}
[ConsoleCommand("edittool.switchmode")]
private void SwitchEditToolMode_ConsoleCommand(ConsoleSystem.Arg args)
{
ToolPlayerData data = PlayerData.Get(args.Player());
if (data == null)
{
return;
}
data.SwitchMode();
}
public void GiveEditTool(BasePlayer player)
{
Item item = ItemManager.CreateByPartialName(ToolItemShortname, 1);
if (item == null)
{
PrintError("WARNING! Failed to create edit tool!");
return;
}
item.skin = ToolSkinID;
item.name = ToolName;
player.GiveItem(item);
}
public enum ToolMode
{
None = 0,
Transform = 1,
Clone = 2,
EditData = 3,
Spawn = 4,
Diguise = 5,
Last
}
public class ToolPlayerData : PlayerDataBase
{
public ToolMode Mode = ToolMode.None;
//public string SavedPrefabName = "";
//private Vector3 SavedPrefabPosition;
//private Quaternion SavedPrefabRotation;
//private byte[] savedBytes;
//private BuildingGrade grade;
private BaseEntity selectedEntity;
private Vector3 lastTransformPosition;
private Vector3 transformOffset;
private float TranslateDistance;
private EntitySaver _entitySaver = new EntitySaver();
private Quaternion _lastRotation;
public void SwitchMode()
{
if (!Player.IsAdmin)
{
if (!_plugin.permission.UserHasPermission(Player.UserIDString, permUse))
{
Mode = ToolMode.None;
return;
}
}
OnLeaveMode(Mode);
int loops = 0;
while (loops < (int)ToolMode.Last * 2)
{
Mode++;
loops++;
if (Mode >= ToolMode.Last)
{
Mode = ToolMode.Transform;
}
if (Mode == ToolMode.EditData)
{
if (EntityPropertiesLoaded() == false)
{
continue;
}
}
if (Mode == ToolMode.Spawn)
{
continue;
}
if (Mode == ToolMode.Diguise)
{
if (DisguiseLoaded() == false)
{
continue;
}
}
//Permission check
if (!Player.IsAdmin)
{
if (!_plugin.permission.UserHasPermission(Player.UserIDString, $"edittool.{Mode.ToString().ToLower()}"))
{
continue;
}
}
OnEnterMode(Mode);
break;
}
}
public void OnLeaveMode(ToolMode mode)
{
DeselectEntity();
}
public void OnEnterMode(ToolMode mode)
{
UI.SwitchToolMode(Player, Mode);
}
public void OnShiftRightClick(BaseEntity entity, Vector3 hitPoint)
{
switch (Mode)
{
case ToolMode.Clone:
{
if (entity == null)
{
return;
}
SavePrefabName(entity, true);
break;
}
case ToolMode.EditData:
{
selectedEntity = entity;
break;
}
}
}
public void OnShiftLeftClick(BaseEntity entity, Vector3 hitPoint)
{
switch (Mode)
{
case ToolMode.Clone:
{
SpawnPrefab(hitPoint, true);
break;
}
case ToolMode.EditData:
{
if (entity == null)
{
return;
}
CloneEntityData(selectedEntity, entity);
break;
}
}
}
public void OnLeftClick(BaseEntity entity, Vector3 hitPoint)
{
switch (Mode)
{
case ToolMode.Clone:
{
SpawnPrefab(hitPoint, false);
break;
}
case ToolMode.Transform:
{
if (entity == null)
{
return;
}
SelectEntity(entity);
TranslateDistance = Vector3.Distance(hitPoint, Player.eyes.position);
transformOffset = hitPoint - selectedEntity.transform.position;
break;
}
case ToolMode.EditData:
{
if (entity == null)
{
return;
}
GameObject obj = new GameObject();
//obj.Identity();
//obj.SetActive(true);
//collider.bounds.SetMinMax(-bounds, bounds);
obj.layer = (int)Rust.Layer.Construction;
obj.transform.position = Player.transform.position;
//var rigid = obj.AddComponent<Rigidbody>();
//rigid.isKinematic = true;
//rigid.useGravity = false;
//rigid.detectCollisions = true;
BoxCollider collider = obj.AddComponent<BoxCollider>();
collider.size = new Vector3(3f, 3f, 3f);
//collider.isTrigger = false;
//collider.enabled = true;
obj.SetActive(false);
Debug(string.Join(",", obj.GetComponents<Component>().Select(x => x.GetType().ToString()).ToArray()));
//Vector3 bounds = new Vector3(3f,3f,3f);
//_plugin.Puts($"Added collider! {obj.transform.position} {Player.transform.position} {obj.transform.localScale}");
break;
}
}
}
public void OnLeftRelease()
{
switch (Mode)
{
case ToolMode.Transform:
{
if (selectedEntity == null)
{
return;
}
if (selectedEntity.GetComponent<Rigidbody>() != null)
{
Vector3 velocity = (selectedEntity.transform.position - lastTransformPosition);
Debug($"Setting release velocity {velocity}");
selectedEntity.SetVelocity(velocity * 20);
selectedEntity.GetComponent<Rigidbody>().useGravity = true;
}
Debug(string.Join(",", selectedEntity.GetComponents<Component>().Select(x => x.GetType().ToString()).ToArray()));
DeselectEntity();
break;
}
}
}
public void OnRightRelease()
{
}
public void OnRightClick(BaseEntity entity, Vector3 hitPoint)
{
switch (Mode)
{
case ToolMode.Clone:
{
if (entity == null)
{
return;
}
SavePrefabName(entity, false);
break;
}
case ToolMode.EditData:
{
if (entity == null)
{
return;
}
StartEditingEntityData(Player, entity);
break;
}
}
}
public void OnReloadClick(BaseEntity entity, Vector3 hitPoint)
{
}
public void OnPlayerInput(BaseEntity entity, InputState input)
{
switch (Mode)
{
case ToolMode.Transform:
{
if (input.WasJustPressed(BUTTON.FIRE_SECONDARY))
{
_lastRotation = entity.transform.rotation;
SelectEntity(entity);
}
if (input.WasJustReleased(BUTTON.FIRE_SECONDARY))
{
DeselectEntity();
}
float translateSpeed = 0.4f;
if (input.IsDown(BUTTON.SPRINT))
{
translateSpeed = 1.2f;
}
if (input.IsDown(BUTTON.USE))
{
TranslateDistance = Mathf.MoveTowards(TranslateDistance, 0, translateSpeed);
}
if (input.IsDown(BUTTON.RELOAD))
{
TranslateDistance = Mathf.MoveTowards(TranslateDistance, EditToolDistance, translateSpeed);
}
if (input.IsDown(BUTTON.FIRE_SECONDARY))
{
RotationTick(input);
}
else
{
TransformTick();
}
break;
}
}
}
private void SelectEntity(BaseEntity entity)
{
selectedEntity = entity;
}
private void DeselectEntity()
{
//Handling in TransformTick and RotationTick as performance impact isn't too bad
//TryUpdateBuildingBlock(selectedEntity);
selectedEntity = null;
lastTransformPosition = default(Vector3);
}
private void TryUpdateBuildingBlock(BaseEntity entity)
{
BuildingBlock block = entity as BuildingBlock;
if (block == null)
{
return;
}
block.UpdateSkin(true);
}
private void TransformTick()
{
if (selectedEntity == null)
{
return;
}
//_plugin.Puts($"SyncPosition: {selectedEntity.syncPosition}");
Rigidbody rigid = selectedEntity.GetComponent<Rigidbody>();
//Disable rigid body's gravity, as they keep trying to fall when moved around
if (rigid != null)
{
rigid.useGravity = false;
}
lastTransformPosition = selectedEntity.transform.position;
selectedEntity.transform.position = Player.eyes.BodyRay().origin + Player.eyes.BodyRay().direction * TranslateDistance - transformOffset;
//Have to manually trigger building blocks to update their collider serverside
TryUpdateBuildingBlock(selectedEntity);
if (selectedEntity is AnimatedBuildingBlock)
{
//Have to change entity flags for doors to update their position on client
//So just change a useless flag
//selectedEntity.SetFlag(BaseEntity.Flags.Open, !selectedEntity.HasFlag(BaseEntity.Flags.Open));
}
//Manually kill and respawn entities to make them update their position
{
NetWrite nw = Net.sv.StartWrite();
nw.PacketID(Message.Type.EntityDestroy);
nw.UInt32(selectedEntity.net.ID);
nw.UInt8(0);
nw.Send(new SendInfo(selectedEntity.net.group.subscribers));
}
selectedEntity.SendNetworkUpdateImmediate();
if (selectedEntity is BuildingBlock)
{
//Have to tell the client to update building block's position on client
//selectedEntity.ClientRPC(null, "RefreshSkin");
}
}
private void RotationTick(InputState input)
{
float multiplier = 8f;
if (selectedEntity == null)
{
return;
}
Vector3 center = selectedEntity.CenterPoint();
//This will be used to fix the entity rotating on the players look angle
Vector3 eyeLeveled = Player.eyes.position;
Vector3 centerLeveled = center;
eyeLeveled.y = 0;
centerLeveled.y = 0;
Ray ray = new Ray(eyeLeveled, eyeLeveled - centerLeveled);
Vector3 difference = (new Vector3((input.previous.aimAngles.x - input.current.aimAngles.x) * -1f,
(input.previous.aimAngles.y - input.current.aimAngles.y),
0)) * multiplier;
selectedEntity.transform.RotateAround(center, Player.eyes.BodyRight(), (input.previous.aimAngles.x - input.current.aimAngles.x) * multiplier);
selectedEntity.transform.RotateAround(center, Player.eyes.BodyUp(), (input.previous.aimAngles.y - input.current.aimAngles.y) * multiplier);
float rollRotate = 0f;
if (input.IsDown(BUTTON.USE))
{
rollRotate = 2f;
}
if (input.IsDown(BUTTON.RELOAD))
{
rollRotate = -2f;
}
if (input.IsDown(BUTTON.SPRINT))
{
rollRotate *= 4f;
}
selectedEntity.transform.RotateAround(center, Player.eyes.BodyForward(), rollRotate);
if (input.IsDown(BUTTON.DUCK))
{
float rotMuli = 9f;
selectedEntity.transform.rotation = Quaternion.Euler(Mathf.Round(selectedEntity.transform.rotation.x * rotMuli) / rotMuli,
Mathf.Round(selectedEntity.transform.rotation.y * rotMuli) / rotMuli,
Mathf.Round(selectedEntity.transform.rotation.z * rotMuli) / rotMuli);
}
TryUpdateBuildingBlock(selectedEntity);
//Manually kill and respawn entities to make them update their position
{
NetWrite nw = Net.sv.StartWrite();
nw.PacketID(Message.Type.EntityDestroy);
nw.UInt32(selectedEntity.net.ID);
nw.UInt8(0);
nw.Send(new SendInfo(selectedEntity.net.group.subscribers));
}
selectedEntity.SendNetworkUpdateImmediate();
}
private void SavePrefabName(BaseEntity entity, bool fullClone)
{
_entitySaver.SaveEntity(entity, fullClone);
}
private void SpawnPrefab(Vector3 position, bool fullClone)
{
_entitySaver.SpawnEntity(position, fullClone);
}
}
public class EntitySaver
{
//public bool FullClone = false;
private ulong _ownerID = 0;
private string _prefabName = "";
private Vector3 lastPos;
private Quaternion _rotation;
private byte[] savedBytes = null;
private BuildingGrade.Enum _grade = BuildingGrade.Enum.None;
private Vector3 velocity;
public void SaveEntity(BaseEntity entity, bool fullClone)
{
_prefabName = entity.PrefabName;
_rotation = entity.transform.rotation;
lastPos = entity.transform.position;
if (entity is BuildingBlock)
{
_grade = (entity as BuildingBlock).grade;
}
if (!fullClone)
{
savedBytes = null;
return;
}
savedBytes = entity.GetSaveCache().ToArray();
if (entity.GetComponent<ServerProjectile>() != null)
{
velocity = (Vector3)typeof(ServerProjectile).GetField("_currentVelocity", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public).GetValue(entity.GetComponent<ServerProjectile>());
}
}
public void SpawnEntity(Vector3 position, bool fullClone)
{
if (_prefabName == "")
{
return;
}
BaseEntity entity = GameManager.server.CreateEntity(_prefabName, position, _rotation);
if (entity == null)
{
_plugin.PrintError("SpawnPrefab Failed!");
}
if (fullClone)
{
entity.PreServerLoad();
}
GameObject.Destroy(entity.GetComponent<Spawnable>());
if (entity is BuildingBlock && _grade > BuildingGrade.Enum.None)
{
(entity as BuildingBlock).grade = _grade;
}
entity.Spawn();
if (entity is BuildingBlock && _grade > BuildingGrade.Enum.None)
{
(entity as BuildingBlock).SetGrade(_grade);
(entity as BuildingBlock).Heal(entity.MaxHealth());
}
if (!fullClone)
{
return;
}
if (savedBytes == null)
{
return;
}
Entity entityData = Entity.Deserialize(savedBytes);
BaseNetworkable.LoadInfo loadInfo = new BaseNetworkable.LoadInfo() { fromDisk = true };
loadInfo.msg = entityData;
entity.Load(loadInfo);
entity.PostServerLoad();
entity.transform.position = position;
SetupEntityIDs(entity);
if (entity.GetComponent<ServerProjectile>() != null)
{
entity.GetComponent<ServerProjectile>().InitializeVelocity(velocity);
}
if (entity is Signage)
{
entity.SendNetworkUpdate();
}
}
private void SetupEntityIDs(BaseEntity entity)
{
if (entity is StorageContainer)
{
SetupItemContainerIDs((entity as StorageContainer).inventory);
}
else if (entity is BasePlayer)
{
BasePlayer player = entity as BasePlayer;
SetupItemContainerIDs(player.inventory.containerBelt);
SetupItemContainerIDs(player.inventory.containerMain);
SetupItemContainerIDs(player.inventory.containerWear);
}
else if (entity is DroppedItemContainer)
{
SetupItemContainerIDs((entity as DroppedItemContainer).inventory);
}
}
private void SetupItemContainerIDs(ItemContainer container)
{
container.uid = Net.sv.TakeUID();
foreach (Item item in container.itemList)
{
SetupItem(item);
}
}
private void SetupItem(Item item)
{
item.uid = Net.sv.TakeUID();
if (item.contents != null)
{
SetupItemContainerIDs(item.contents);
}
foreach (ItemMod mod in item.info.itemMods)
{
mod.OnItemCreated(item);
}
}
}
public class UIManager
{
private UIImage Crosshair;
public UILabel EntityInfoLabel;
public UIBaseElement ToolUI;
private UILabel ToolMode;
public UIManager()
{
SetupUI_ToolUI();
SetupUI_Crosshair();
}
public void Unload()
{
Crosshair?.HideAll();
EntityInfoLabel?.HideAll();
ToolMode?.HideAll();
}
private void SetupUI_Crosshair()
{
float dotSize = 0.007f * 0.20f;
Crosshair = new UIImage(new Vector2(0.5f - dotSize, 0.5f - dotSize * 2), new Vector2(0.5f + dotSize, 0.5f + dotSize * 2), ToolUI);
Crosshair.Image.Sprite = "assets/icons/circle_closed.png";
EntityInfoLabel = new UILabel(new Vector2(0.4f, 0.50f), new Vector2(0.6f, 0.60f), "Entity", 12, "1 1 1 1", ToolUI, TextAnchor.MiddleCenter);
EntityInfoLabel.AddOutline();
}
private void SetupUI_ToolUI()
{
ToolUI = new UIBaseElement(new Vector2(0, 0), new Vector2(1, 1));
ToolUI.conditionalShow = delegate (BasePlayer player)
{
Item item = player.GetActiveItem();
if (item == null)
{
return false;
}
return item.skin == ToolSkinID;
};
ToolMode = new UILabel(new Vector2(0.29f, 0.02f), new Vector2(0.39f, 0.12f), "Inactive", 16, "1 1 1 1", ToolUI, TextAnchor.MiddleRight);
ToolMode.variableText = delegate (BasePlayer player)
{
return $"{PlayerData.Get(player).Mode}";
};
ToolMode.AddOutline();
}
public void SwitchToolMode(BasePlayer player, ToolMode mode)
{
ToolMode.Refresh(player);
}
}
#region Lang API
public Dictionary<string, string> lang_en = new Dictionary<string, string>()
{
{"NotLookingAtEntity", "You aren't looking at an entity!" },
};
public static string GetLangMessage(string key, BasePlayer player)
{
return _plugin.lang.GetMessage(key, _plugin, player.UserIDString);
}
public static string GetLangMessage(string key, ulong player)
{
return _plugin.lang.GetMessage(key, _plugin, player.ToString());
}
public static string GetLangMessage(string key, string player)
{
return _plugin.lang.GetMessage(key, _plugin, player);
}
#endregion Lang API
#region Entity Properties Integration
[PluginReference]
private RustPlugin EntityProperties;
public static bool EntityPropertiesLoaded()
{
if (_plugin.EntityProperties == null)
{
return false;
}
return _plugin.EntityProperties.IsLoaded;
}
public static void StartEditingEntityData(BasePlayer player, BaseEntity entity)
{
if (!EntityPropertiesLoaded())
{
return;
}
_plugin.EntityProperties.CallHook("StartEditingEntity", player, entity);
}
public static void StopEditingEntityData(BasePlayer player)
{
if (!EntityPropertiesLoaded())
{
return;
}
_plugin.EntityProperties.CallHook("StopEditingEntity", player);
}
public static void CloneEntityData(BaseEntity source, BaseEntity target)
{
if (!EntityPropertiesLoaded())
{
return;
}
_plugin.EntityProperties.CallHook("CloneEntitySettings", source, target);
}
#endregion Entity Properties Integration
#region Disguise Integration
[PluginReference]
private RustPlugin Disguise;
public static bool DisguiseLoaded()
{
if (_plugin.Disguise == null)
{
return false;
}
return _plugin.Disguise.IsLoaded;
}
#endregion Disguise Integration
#region Error Printing
public static bool Debugging = true;
public static void Debug(string format, params object[] args)
{
if (!Debugging)
{
return;
}
_plugin.Puts(format, args);
}
public static void Debug(object obj)
{
if (!Debugging)
{
return;
}
_plugin.Puts(obj.ToString());
}
public static void Error(string format, params object[] args)
{
_plugin.PrintError(format, args);
}
#endregion Error Printing
#region PlayerData
public class PlayerDataBase
{
[JsonIgnore]
public BasePlayer Player { get; set; }
public string UserID { get; set; } = "";
public PlayerDataBase()
{
}
public PlayerDataBase(BasePlayer player)
{
UserID = player.UserIDString;
Player = player;
}
}
public class PlayerDataController<T> where T : PlayerDataBase
{
[JsonProperty(Required = Required.Always)]
private Dictionary<string, T> playerData { get; set; } = new Dictionary<string, T>();
public T Get(string identifer)
{
T data;
if (!playerData.TryGetValue(identifer, out data))
{
data = Activator.CreateInstance<T>();
playerData[identifer] = data;
}
return data;
}
public T Get(ulong userID)
{
return Get(userID.ToString());
}
public T Get(BasePlayer player)
{
T data = Get(player.UserIDString);
data.Player = player;
return data;
}
}
#endregion PlayerData
#region Rust Classes In JSON
public class JSONSpawnPoint
{
public float xPos { get; set; }
public float yPos { get; set; }
public float zPos { get; set; }
public float xRot { get; set; }
public float yRot { get; set; }
public float zRot { get; set; }
public float wRot { get; set; }
public BasePlayer.SpawnPoint ToSpawnPoint()
{
BasePlayer.SpawnPoint newSpawn = new BasePlayer.SpawnPoint();
newSpawn.pos.x = xPos;
newSpawn.pos.y = yPos;
newSpawn.pos.z = zPos;
newSpawn.rot.x = xRot;
newSpawn.rot.y = yRot;
newSpawn.rot.z = zRot;
newSpawn.rot.w = wRot;
return newSpawn;
}
[JsonIgnore]
public Vector3 Position
{
get { return new Vector3(xPos, yPos, zPos); }
set { xPos = value.x; yPos = value.y; zPos = value.z; }
}
[JsonIgnore]
public Quaternion Rotation
{
get { return new Quaternion(xRot, yRot, zRot, wRot); }
set { xRot = value.x; yRot = value.y; zRot = value.z; wRot = value.w; }
}
public JSONSpawnPoint()
{
}
public JSONSpawnPoint(Vector3 position, Quaternion rot)
{
Position = position;
Rotation = rot;
}
}
public class JSONEntity
{
public float xPos { get; set; }
public float yPos { get; set; }
public float zPos { get; set; }
public float xRot { get; set; }
public float yRot { get; set; }
public float zRot { get; set; }
public float wRot { get; set; }
public string prefabName { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public BuildingGrade.Enum grade { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public int AssignedBaseID;
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public ulong OwnerID = 0;
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public JSONStorageContainer Inventory;
[JsonIgnore]
public Vector3 Position
{
get { return new Vector3(xPos, yPos, zPos); }
}
[JsonIgnore]
public Quaternion Rotation
{
get { return new Quaternion(xRot, yRot, zRot, wRot); }
}
[JsonIgnore]
public BaseEntity Entity;
public JSONEntity(BaseEntity entity) : this(entity, entity.transform.position, entity.transform.rotation)
{
}
public JSONEntity(BaseEntity entity, Vector3 position, Quaternion rotation)
{
this.xPos = position.x;
this.yPos = position.y;
this.zPos = position.z;
this.xRot = rotation.x;
this.yRot = rotation.y;
this.zRot = rotation.z;
this.wRot = rotation.w;
this.prefabName = entity.PrefabName;
OwnerID = entity.OwnerID;
if (entity.GetType() == typeof(BuildingBlock))
{
grade = ((BuildingBlock)entity).grade;
}
}
public JSONEntity()
{
}
private BaseEntity CreateEntity(bool floating = true)
{
GameObject obj = GameManager.server.CreatePrefab(prefabName, Position, Rotation, false);
if (obj == null)
{
return null;
}
BaseEntity entity = obj.GetComponent<BaseEntity>();
GameObject.Destroy(obj.GetComponent<Spawnable>());
obj.AwakeFromInstantiate();
entity.OwnerID = OwnerID;
Entity = entity;
PreSpawn(entity);
return entity;
}
public void PreSpawn(BaseEntity entity)
{
if (entity is BuildingBlock)
{
(entity as BuildingBlock).grade = grade;
}
}
public void PostSpawn(BaseEntity entity)
{
BaseCombatEntity combat = entity as BaseCombatEntity;
if (combat != null)
{
if (combat.healthFraction < 1f)
{
combat.SetHealth(entity.MaxHealth());
}
}
}
public BaseEntity Spawn()
{
BaseEntity ent = CreateEntity(false);
ent.Spawn();
PostSpawn(ent);
return ent;
}
public bool IsEntity(BaseEntity entity)
{
if (entity.transform.position != Position)
{
return false;
}
if (entity.transform.rotation != Rotation)
{
return false;
}
if (entity.PrefabName != prefabName)
{
return false;
}
if (entity.OwnerID != OwnerID)
{
return false;
}
return true;
}
}
public class JSONStorageContainer
{
public int MaxRefills = -1; //-1 For unlimited
public bool Locked = true;
public bool PerPlayer = false;
public JSONItemContainer SavedInventory = new JSONItemContainer();
}
public class JSONItemAmount
{
public string shortname = "";
public int amount = 0;
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public ulong skinID = 0;
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public int slot = 0;
public JSONItemAmount()
{
}
public JSONItemAmount(string shortname, int amount = 1, ulong skinID = 0)
{
this.shortname = shortname;
this.amount = amount;
this.skinID = skinID;
}
public JSONItemAmount(ItemAmount itemAmount) : this(itemAmount.itemDef.shortname, (int)itemAmount.amount)
{
}
public JSONItemAmount(Item item, int slot = 0) : this(item.info.shortname, item.amount, item.skin)
{
this.slot = slot + 1;
}
public int ItemID()
{
ItemDefinition item = ItemManager.itemList.FirstOrDefault(x => x.shortname == shortname);
if (item == null)
{
return -1;
}
return item.itemid;
}
public Item CreateItem()
{
Item item = ItemManager.CreateByPartialName(shortname, amount);
if (item == null)
{
return null;
}
item.skin = skinID;
return item;
}
public void GiveToPlayer(BasePlayer player)
{
Item item = CreateItem();
if (item != null)
{
player.GiveItem(item);
}
}
public void AddToContainer(ItemContainer container)
{
Item item = CreateItem();
item.MoveToContainer(container, slot - 1, false);
}
}
public class JSONItemContainer
{
public List<JSONItemAmount> Items = new List<JSONItemAmount>();
public JSONItemContainer()
{
}
public JSONItemContainer(ItemContainer container)
{
List<JSONItemAmount> items = new List<JSONItemAmount>();
for (int i = 0; i < container.capacity; i++)
{
Item item = container.GetSlot(i);
items.Add(new JSONItemAmount(item, i));
}
Items = items;
}
public void Load(ItemContainer container)
{
container.Clear();
foreach (JSONItemAmount item in Items)
{
item.AddToContainer(container);
}
}
}
#endregion Rust Classes In JSON
#region Configuration Files
public enum ConfigLocation
{
Data = 0,
Config = 1,
Logs = 2,
Plugins = 3,
Lang = 4,
Custom = 5,
}
public class JSONFile<Type> where Type : class
{
private DynamicConfigFile _file;
public string _name { get; set; }
public Type Instance { get; set; }
private ConfigLocation _location { get; set; }
private string _path { get; set; }
public bool SaveOnUnload = false;
public bool Compressed = false;
public JSONFile(string name, ConfigLocation location = ConfigLocation.Data, string path = null, string extension = ".json", bool saveOnUnload = false)
{
SaveOnUnload = saveOnUnload;
_name = name.Replace(".json", "");
_location = location;
switch (location)
{
case ConfigLocation.Data:
{
_path = $"{Oxide.Core.Interface.Oxide.DataDirectory}/{name}{extension}";
break;
}
case ConfigLocation.Config:
{
_path = $"{Oxide.Core.Interface.Oxide.ConfigDirectory}/{name}{extension}";
break;
}
case ConfigLocation.Logs:
{
_path = $"{Oxide.Core.Interface.Oxide.LogDirectory}/{name}{extension}";
break;
}
case ConfigLocation.Lang:
{
_path = $"{Oxide.Core.Interface.Oxide.LangDirectory}/{name}{extension}";
break;
}
case ConfigLocation.Custom:
{
_path = $"{path}/{name}{extension}";
break;
}
}
_file = new DynamicConfigFile(_path);
Init();
}
public virtual void Init()
{
_plugin.OnRemovedFromManager.Add(new Action<Plugin, PluginManager>(Unload));
Load();
}
public virtual void Load()
{
if (Compressed)
{
LoadCompressed();
return;
}
if (!_file.Exists())
{
Save();
}
Instance = _file.ReadObject<Type>();
if (Instance == null)
{
Instance = Activator.CreateInstance<Type>();
Save();
}
return;
}
private void LoadCompressed()
{
string str = _file.ReadObject<string>();
if (str == null || str == "")
{
Instance = Activator.CreateInstance<Type>();
return;
}
using (MemoryStream compressedStream = new MemoryStream(Convert.FromBase64String(str)))
using (GZipStream zipStream = new GZipStream(compressedStream, CompressionMode.Decompress))
using (MemoryStream resultStream = new MemoryStream())
{
byte[] buffer = new byte[4096];
int read;
while ((read = zipStream.Read(buffer, 0, buffer.Length)) > 0)
{
resultStream.Write(buffer, 0, read);
}
Instance = JsonConvert.DeserializeObject<Type>(Encoding.UTF8.GetString(resultStream.ToArray()));
}
}
public virtual void Save()
{
if (Compressed)
{
SaveCompressed();
return;
}
_file.WriteObject(Instance);
return;
}
private void SaveCompressed()
{
using (MemoryStream stream = new MemoryStream())
{
using (GZipStream zipStream = new GZipStream(stream, CompressionMode.Compress))
{
byte[] bytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(Instance));
zipStream.Write(bytes, 0, bytes.Length);
zipStream.Close();
_file.WriteObject(Convert.ToBase64String(stream.ToArray()));
}
}
}
public virtual void Reload()
{
Load();
}
private void Unload(Plugin sender, PluginManager manager)
{
if (SaveOnUnload)
{
Save();
}
}
}
#endregion Configuration Files
#region Jake's UI Framework
private Dictionary<string, UICallbackComponent> UIButtonCallBacks { get; set; } = new Dictionary<string, UICallbackComponent>();
private void OnButtonClick(ConsoleSystem.Arg arg)
{
UICallbackComponent button;
if (UIButtonCallBacks.TryGetValue(arg.cmd.Name, out button))
{
button.InvokeCallback(arg);
return;
}
Puts("Unknown button command: {0}", arg.cmd.Name);
}
public class UIElement : UIBaseElement
{
public CuiElement Element { get; protected set; }
public UIOutline Outline { get; set; }
public CuiRectTransformComponent transform { get; protected set; }
public float FadeOut
{
get
{
return Element == null ? _fadeOut : Element.FadeOut;
}
set
{
if (Element != null)
{
Element.FadeOut = value;
}
_fadeOut = value;
}
}
private float _fadeOut = 0f;
public string Name { get { return Element.Name; } }
public UIElement(UIBaseElement parent = null) : base(parent)
{
}
public UIElement(Vector2 position, float width, float height, UIBaseElement parent = null) : this(position, new Vector2(position.x + width, position.y + height), parent)
{
}
public UIElement(Vector2 min, Vector2 max, UIBaseElement parent = null) : base(min, max, parent)
{
transform = new CuiRectTransformComponent();
Element = new CuiElement
{
Name = CuiHelper.GetGuid(),
Parent = this._parent == null ? this.Parent : this._parent.Parent,
Components =
{
transform,
},
FadeOut = _fadeOut,
};
UpdatePlacement();
Init();
}
public void AddOutline(string color = "0 0 0 1", string distance = "1 -1")
{
Outline = new UIOutline(color, distance);
Element.Components.Add(Outline.component);
}
public virtual void Init()
{
}
public override void Show(BasePlayer player, bool children = true)
{
if (this is UIElement)
{
if (!CanShow(player))
{
_shouldShow = false;
return;
}
_shouldShow = true;
if (conditionalSize != null)
{
Vector2 returnSize = conditionalSize.Invoke(player);
if (returnSize != null)
{
SetSize(returnSize.x, returnSize.y);
}
}
if (conditionalPosition != null)
{
Vector2 returnPos = conditionalPosition.Invoke(player);
if (returnPos != null)
{
SetPosition(returnPos.x, returnPos.y);
}
}
}
if (AddPlayer(player))
{
SafeAddUi(player, Element);
}
base.Show(player, children);
}
public override void Hide(BasePlayer player, bool children = true)
{
base.Hide(player, children);
if (RemovePlayer(player))
{
SafeDestroyUi(player, Element);
}
}
public override void UpdatePlacement()
{
base.UpdatePlacement();
if (transform != null)
{
transform.AnchorMin = $"{globalPosition.x} {globalPosition.y}";
transform.AnchorMax = $"{globalPosition.x + globalSize.x} {globalPosition.y + globalSize.y}";
}
//RefreshAll();
}
public void SetPositionAndSize(CuiRectTransformComponent trans)
{
transform.AnchorMin = trans.AnchorMin;
transform.AnchorMax = trans.AnchorMax;
//_plugin.Puts($"POSITION [{transform.AnchorMin},{transform.AnchorMax}]");
RefreshAll();
}
public void SetParent(UIElement element)
{
Element.Parent = element.Element.Name;
UpdatePlacement();
}
public void SetParent(string parent)
{
Element.Parent = parent;
Parent = parent;
}
}
public class UIButton : UIElement, UICallbackComponent
{
public CuiButtonComponent buttonComponent { get; private set; }
public CuiTextComponent textComponent { get; private set; }
public UILabel Label { get; set; }
private string _textColor { get; set; }
private string _buttonText { get; set; }
public string Text { set { textComponent.Text = value; } }
public Func<BasePlayer, string> variableText { get; set; }
public Action<ConsoleSystem.Arg> onCallback;
private int _fontSize;
public UIButton(Vector2 min = default(Vector2), Vector2 max = default(Vector2), string buttonText = "", string buttonColor = "0 0 0 0.85", string textColor = "1 1 1 1", int fontSize = 15, UIBaseElement parent = null) : base(min, max, parent)
{
buttonComponent = new CuiButtonComponent();
_fontSize = fontSize;
_textColor = textColor;
_buttonText = buttonText;
buttonComponent.Command = CuiHelper.GetGuid();
buttonComponent.Color = buttonColor;
Element.Components.Insert(0, buttonComponent);
_plugin.cmd.AddConsoleCommand(buttonComponent.Command, _plugin, "OnButtonClick");
_plugin.UIButtonCallBacks[buttonComponent.Command] = this;
Label = new UILabel(new Vector2(0, 0), new Vector2(1, 1), fontSize: _fontSize, parent: this);
textComponent = Label.text;
Label.text.Align = TextAnchor.MiddleCenter;
Label.text.Color = _textColor;
Label.Text = _buttonText;
Label.text.FontSize = _fontSize;
}
public UIButton(Vector2 position, float width, float height, string buttonText = "", string buttonColor = "0 0 0 0.85", string textColor = "1 1 1 1", int fontSize = 15, UIBaseElement parent = null) : this(position, new Vector2(position.x + width, position.y + height), buttonText, buttonColor, textColor, fontSize, parent)
{
}
public override void Init()
{
base.Init();
}
public void AddChatCommand(string fullCommand)
{
if (fullCommand == null)
{
return;
}
onCallback += (arg) =>
{
arg.Player().IPlayer.Command($"chat.say \"/{fullCommand}\"");
};
}
public void AddCallback(Action<BasePlayer> callback)
{
if (callback == null)
{
return;
}
onCallback += (args) => { callback(args.Player()); };
}
public override void Show(BasePlayer player, bool children = true)
{
if (variableText != null)
{
try
{
Text = variableText.Invoke(player);
}
catch (Exception ex)
{
_plugin.Puts($"UIButton.variableText failed!\n{ex}");
}
}
base.Show(player, children);
}
public void InvokeCallback(ConsoleSystem.Arg args)
{
if (onCallback == null)
{
return;
}
onCallback.Invoke(args);
}
}
public class UIBackgroundText : UIPanel
{
public UILabel Label;
public UIBackgroundText(Vector2 min = default(Vector2), Vector2 max = default(Vector2), UIBaseElement parent = null, string backgroundColor = "0 0 0 0.85", string labelText = "", int fontSize = 12, string fontColor = "1 1 1 1", TextAnchor alignment = TextAnchor.MiddleCenter) : base(min, max, parent)
{
Label = new UILabel(new Vector2(0, 0), new Vector2(1, 1), labelText, fontSize, fontColor, parent, alignment);
}
}
public class UILabel : UIElement
{
public CuiTextComponent text { get; private set; }
public UILabel(Vector2 min = default(Vector2), Vector2 max = default(Vector2), string labelText = "", int fontSize = 12, string fontColor = "1 1 1 1", UIBaseElement parent = null, TextAnchor alignment = TextAnchor.MiddleCenter) : base(min, max, parent)
{
if (min == Vector2.zero && max == Vector2.zero)
{
max = Vector2.one;
}
text = new CuiTextComponent();
text.Text = labelText;
ColorString = fontColor;
text.Align = alignment;
text.FontSize = fontSize;
Element.Components.Insert(0, text);
}
public UILabel(Vector2 min, float width, float height, string labelText = "", int fontSize = 12, string fontColor = "1 1 1 1", UIBaseElement parent = null, TextAnchor alignment = TextAnchor.MiddleCenter) : this(min, new Vector2(min.x + width, min.y + height), labelText, fontSize, fontColor, parent, alignment)
{
}
public string Text { set { if (value == null) { text.Text = ""; } else { text.Text = value; } text.Text = value; } } //I love single line statments
public TextAnchor Allign { set { text.Align = value; } }
public Color Color { set { text.Color = value.ToString(); } }
public string ColorString { set { text.Color = value.Replace("f", ""); } } //Prevent me from breaking UI with 0.1f instead of 0.1
public Func<BasePlayer, string> variableText { get; set; }
public Func<BasePlayer, string> variableFontColor { get; set; }
public override void Show(BasePlayer player, bool children = true)
{
if (variableText != null)
{
try
{
Text = variableText.Invoke(player);
}
catch (Exception ex)
{
_plugin.Puts($"UILabel.variableText failed!\n{ex}");
}
}
if (variableFontColor != null)
{
try
{
ColorString = variableFontColor.Invoke(player);
}
catch (Exception ex)
{
_plugin.Puts($"UILabel.variableFontColor failed!\n{ex}");
}
}
base.Show(player, children);
}
public override void Init()
{
base.Init();
if (_parent != null)
{
if (_parent is UIButton)
{
Element.Parent = (_parent as UIButton).Name;
transform.AnchorMin = $"{localPosition.x} {localPosition.y}";
transform.AnchorMax = $"{localPosition.x + localSize.x} {localPosition.y + localSize.y}";
}
}
}
}
public class UIImageBase : UIElement
{
public UIImageBase(Vector2 min, Vector2 max, UIBaseElement parent) : base(min, max, parent)
{
}
private CuiNeedsCursorComponent needsCursor { get; set; }
private bool requiresFocus { get; set; }
public bool CursorEnabled
{
get
{
return requiresFocus;
}
set
{
if (value)
{
needsCursor = new CuiNeedsCursorComponent();
Element.Components.Add(needsCursor);
}
else
{
Element.Components.Remove(needsCursor);
}
requiresFocus = value;
}
}
}
public class UIPanel : UIImageBase
{
private CuiImageComponent panel;
public string Color { get { return panel.Color; } set { panel.Color = value; } }
public string Material { get { return panel.Material; } set { panel.Material = value; } }
public Func<BasePlayer, string> variableColor { get; set; }
public UIPanel(Vector2 min, Vector2 max, UIBaseElement parent = null, string color = "0 0 0 0.85") : base(min, max, parent)
{
panel = new CuiImageComponent
{
Color = color,