C#:
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.5")]
[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
using (NetWrite write = Net.sv.StartWrite()) {
write.PacketID(Message.Type.EntityDestroy);
write.UInt64(selectedEntity.net.ID.Value);
write.UInt8(0);
write.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
using (NetWrite write = Net.sv.StartWrite()) {
write.PacketID(Message.Type.EntityDestroy);
write.UInt64(selectedEntity.net.ID.Value);
write.UInt8(0);
write.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 = new ItemContainerId(Net.sv.TakeUID());
foreach (Item item in container.itemList) {
SetupItem(item);
}
}
private void SetupItem(Item item) {
item.uid = new ItemId(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;
// ... [Code preview truncated due to length. Full source in attached file] ...