C#:
using Oxide.Game.Rust.Cui;
using ProtoBuf;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Oxide.Plugins {
[Info("Personal Vault Door", "bmgjet", "1.0.2")]
[Description("Lets you place a vault door")]
public class PersonalVaultDoor : RustPlugin {
#region Vars
//Starting Health of vault door
public static float VaultMaxHealth = 2000;
//Sec delay between taking damage and being able to fix
public float RepairDelay = 60;
//Repair per hammer hit
public int RepairAmmount = 25;
//Items and quanity needed per repair hit
public Dictionary<string, int> RepairCost = new Dictionary<string, int> {
{
"scrap", 1
}
, {
"metal.fragments", 100
}
, {
"metal.refined", 10
}
,
}
;
public bool craftcosts = false;
public Dictionary<string, int> CraftCost = new Dictionary<string, int> {
{
"scrap", 10
}
, {
"metal.fragments", 1000
}
, {
"metal.refined", 100
}
,
}
;
//Offset from door slot position to move lock.
Vector3 codeoffset = new Vector3(0.71f, -0.1f, -0.3f);
//Puts it on flat pannel, On handles was too far for it to trigger on door still.
//Skin of Icon
private const ulong skinID = 2643584466;
//Replacement prefab
private const string prefab = "assets/bundled/prefabs/modding/asset_store/bankheist_package/bankheist_vol03/prefabs/door.vault.static.prefab";
//Permission
private const string permUse = "PersonalVaultDoor.use";
//Show Debug Info
private bool showDebug = false;
//Sound Effects to play on vault break.
static List<string> effects = new List<string> {
"assets/bundled/prefabs/fx/entities/loot_barrel/gib.prefab", "assets/bundled/prefabs/fx/building/metal_sheet_gib.prefab"
}
;
private List<Vector3> REPlaced = new List<Vector3>();
private static PersonalVaultDoor plugin;
#endregion
#region Language
protected override void LoadDefaultMessages() {
lang.RegisterMessages(new Dictionary<string, string> {
{
"Name", "Vault Door"
}
, {
"Pickup", "You picked up Vault Door!"
}
, {
"Receive", "You received Vault Door!"
}
, {
"Repair", "You need more resources:\n{0}"
}
, {
"Wait", "You must wait: {0} before you can repair."
}
, {
"Permission", "You need permission to do that!"
}
}
, this);
}
//Send player message
private void message(BasePlayer player, string key, params object[] args) {
if (player == null) {
return;
}
var message = string.Format(lang.GetMessage(key, this, player.UserIDString), args);
player.ChatMessage(message);
}
#endregion
#region Oxide Hooks
private void OnServerInitialized(bool initial) {
plugin = this;
//Readd Component
if (initial) {
if (showDebug) Puts("First Start Detected");
Fstartup();
}
else {
CheckVaultDoor();
;
}
}
private void Fstartup() {
//Wait until a player has connected before starting up vault door componant for slow servers.
timer.Once(10f, () => {
if (Rust.Application.isLoading) {
Fstartup();
return;
}
covalence.Server.Command("o.reload", this.Name);
}
);
}
private void Init() {
//Setup Permissions
permission.RegisterPermission(permUse, this);
}
private void Unload() {
//Clear Vault Door Health CUI
foreach (BasePlayer player in BasePlayer.activePlayerList.ToArray()) {
CuiHelper.DestroyUi(player, "VaultHealth");
}
int VDS = DestroyVaultDoorScript();
if (showDebug) Puts("Destroyed " + VDS.ToString() + " VaultDoor Scripts");
//Unload Statics
effects = null;
plugin = null;
}
void OnEntityKill(BaseNetworkable entity) {
if (entity == null) return;
//Check if vault door
if (entity.ShortPrefabName == "door.vault.static") {
VaultDoor VD = entity.GetComponent<VaultDoor>();
if (VD == null) return;
//Remove Door Frame
NextTick(() => {
if (VD.Frame != null) {
VD.Frame.Kill();
}
}
);
if (VD.PlayersCUIed == null) return;
//Remove CUI
foreach (BasePlayer player in VD.PlayersCUIed) {
if (player != null) {
CuiHelper.DestroyUi(player, "VaultHealth");
}
}
UnityEngine.Object.DestroyImmediate(VD);
}
}
//Code and KeyLock position Fix
void OnEntitySpawned(BaseEntity cl) {
if (Rust.Application.isLoading) return;
if (cl == null) {
return;
}
//Checks if codelock/keylock
if (cl is CodeLock || cl is KeyLock) {
//Checks if its a vault door
BaseEntity Door = cl.GetParentEntity();
if (Door != null && Door.ToString().Contains("door.vault.static")) {
//Moves codelock and update
cl.transform.localPosition += codeoffset;
cl.SendNetworkUpdateImmediate(true);
}
}
//Add component in spawn here so Copypaste can Work with vaultdoors.
if (cl is Door && cl.ToString().Contains("door.vault.static")) {
if (cl.GetComponent<VaultDoor>() == null) {
if (REPlaced.Contains(cl.transform.position)) {
if (showDebug) Puts("Skipping Rust Edit Placed Vault Door");
return;
}
if (showDebug) Puts("Adding VaultDoor Component");
//Delay since copypaste might not of spawn door frame yet.
timer.Once(2f, () => {
try {
cl.gameObject.AddComponent<VaultDoor>();
}
catch {
}
;
}
);
}
}
}
//Hook vault placement to switch in.
private void OnEntityBuilt(Planner plan, GameObject go) {
CheckDeploy(go.ToBaseEntity());
}
//Hooks if should pickup
private void OnHammerHit(BasePlayer player, HitInfo info) {
CheckHit(player, info?.HitEntity);
}
#endregion
#region Core
List<Door> FindVaultDoors(Vector3 pos, float radius) {
//Casts a sphere at given position and find all doors there
var hits = Physics.SphereCastAll(pos, radius, Vector3.one);
var x = new List<Door>();
foreach (var hit in hits) {
var entity = hit.GetEntity()?.GetComponent<Door>();
if (entity && !x.Contains(entity)) x.Add(entity);
}
return x;
}
void DestroyGroundComp(BaseEntity ent) {
UnityEngine.Object.DestroyImmediate(ent.GetComponent<DestroyOnGroundMissing>());
UnityEngine.Object.DestroyImmediate(ent.GetComponent<GroundWatch>());
//Stops Decay
UnityEngine.Object.DestroyImmediate(ent.GetComponent<DeployableDecay>());
}
void DestroyMeshCollider(BaseEntity ent) {
foreach (var mesh in ent.GetComponentsInChildren<MeshCollider>()) {
UnityEngine.Object.DestroyImmediate(mesh);
}
}
//Resets the component after server restart
private void CheckVaultDoor() {
//Build list of VaultDoors In Map File
for (int i = World.Serialization.world.prefabs.Count - 1; i >= 0; i--) {
PrefabData prefabdata = World.Serialization.world.prefabs[i];
if (prefabdata.id == 3595032872) {
REPlaced.Add(prefabdata.position);
//Check its still there and fix if not
if (FindVaultDoors(prefabdata.position, 4f).Count == 0) {
Door replacement = GameManager.server.CreateEntity(StringPool.Get(prefabdata.id), prefabdata.position, prefabdata.rotation) as Door;
if (replacement == null) return;
DestroyGroundComp(replacement);
DestroyMeshCollider(replacement);
replacement.Spawn();
replacement.transform.position = prefabdata.position;
replacement.transform.rotation = prefabdata.rotation;
replacement.pickup.enabled = false;
replacement.SendNetworkUpdateImmediate(true);
}
}
}
if (showDebug) Puts("Founded " + REPlaced.Count.ToString() + " Map Placed Vault Doors");
int VaultsUpdated = 0;
foreach (var vaultdoor in GameObject.FindObjectsOfType<BaseEntity>()) {
//Skip Servers Vault Doors
if (REPlaced.Contains(vaultdoor.transform.position)) {
if (showDebug) Puts("Skipping Map Placed Vault Door @ " + vaultdoor.transform.position.ToString());
continue;
}
if (vaultdoor.ShortPrefabName == "door.vault.static" && vaultdoor.GetComponent<VaultDoor>() == null) {
if (showDebug) Puts("Found vaultdoor " + vaultdoor.ToString() + " " + vaultdoor.OwnerID.ToString() + " Adding Component");
vaultdoor.gameObject.AddComponent<VaultDoor>();
VaultsUpdated++;
}
}
Puts("Updated " + VaultsUpdated.ToString() + " VaultDoors");
}
//Gives player vault door
private void GiveVaultDoor(BasePlayer player, bool pickup = false) {
var item = CreateItem();
if (item != null && player != null) {
player.GiveItem(item);
message(player, pickup ? "Pickup" : "Receive");
}
}
//Checks if has the correct permission
private bool CanCraft(BasePlayer player) {
if (!permission.UserHasPermission(player.UserIDString, permUse)) {
message(player, "Permission");
return false;
}
return CanFix(player, null, true);
}
//Creates vault door
private Item CreateItem() {
var item = ItemManager.CreateByName("wall.frame.garagedoor", 1, skinID);
if (item != null) {
item.text = "Vault Door";
item.name = item.text;
}
return item;
}
//Checks if its a vault door when hit with hammer
private void CheckHit(BasePlayer player, BaseEntity entity) {
if (entity == null) {
return;
}
if (!IsVaultDoor(entity.skinID)) {
return;
}
//Check if door is open and has no lock to remove Otherwise heal door
Door VD = entity as Door;
if (VD.GetSlot(0) == null && VD.IsOpen()) {
entity.GetComponent<VaultDoor>()?.TryPickup(player);
}
else {
if (VD._health < VD._maxHealth && CanFix(player, VD)) {
Effect.server.Run("assets/bundled/prefabs/fx/build/repair_full_metal.prefab", VD.transform.position);
VD.health += RepairAmmount;
}
}
}
//Checks if can fix
private bool CanFix(BasePlayer player, Door VD, bool craft = false) {
Dictionary<string, int> Needed = new Dictionary<string, int>();
Dictionary<string, int> Parts = new Dictionary<string, int>();
if (!craft) {
Parts = RepairCost;
//Check repair delay
if (VD.SecondsSinceAttacked < RepairDelay) {
message(player, "Wait", (RepairDelay - VD.SecondsSinceAttacked).ToString("#.#"));
return false;
}
}
else {
if (!craftcosts) return true;
Parts = CraftCost;
}
//Check has needed meterials
foreach (var component in Parts) {
string name = component.Key;
if (player.inventory.GetAmount(ItemManager.FindItemDefinition(component.Key).itemid) < component.Value) {
if (!Needed.ContainsKey(name)) {
Needed.Add(name, 0);
}
Needed[name] += component.Value;
}
}
//Has everything needed so remove from player and send can fix.
if (Needed.Count == 0) {
foreach (var item in Parts) {
player.inventory.Take(null, ItemManager.FindItemDefinition(item.Key).itemid, item.Value);
}
return true;
}
//Doesnt have everything needed to build list and message use. Send cant fix
else {
string text = "";
foreach (var item in Needed) {
text += $" * {item.Key} x{item.Value}\n";
}
message(player, "Repair", text);
return false;
}
}
private bool IsVaultDoor(ulong skin) {
return skin != 0 && skin == skinID;
}
//Checks if vault door should be swapped in
private void CheckDeploy(BaseEntity entity) {
if (entity == null) {
return;
}
//Checks if is using vault door skin
if (!IsVaultDoor(entity.skinID)) {
return;
}
//Creates Doorway
var doorway = GameManager.server.CreateEntity("assets/prefabs/building core/wall.doorway/wall.doorway.prefab", entity.transform.position, entity.transform.rotation);
if (doorway == null) {
//Something Failed
return;
}
doorway.Spawn();
doorway.OwnerID = entity.OwnerID;
//sets up door frame to fill in gaps around vault door
var buildingBlock = doorway as BuildingBlock;
if (buildingBlock != null) {
//Upgrade HQM
buildingBlock.SetGrade((BuildingGrade.Enum)4);
//Grounded so doesnt fall apart
buildingBlock.grounded = false;
//Sets health as max
buildingBlock.health = buildingBlock.MaxHealth();
//Rotate from Door Way
Vector3 rot = buildingBlock.transform.rotation.eulerAngles;
rot = new Vector3(rot.x, rot.y + 180, rot.z);
//Create Vault Door
Door vaultdoor = GameManager.server.CreateEntity(prefab, buildingBlock.transform.position, buildingBlock.transform.rotation) as Door;
if (vaultdoor == null) {
return;
}
//Stupid rotation based move stuff
Vector3 movepos = buildingBlock.transform.position;
movepos += buildingBlock.transform.forward * 1.0f;
movepos += buildingBlock.transform.right * -0.54f;
movepos += buildingBlock.transform.up * 0.2f;
//Sets door way as creator so can destory vault on door way being destroyed
vaultdoor.creatorEntity = doorway;
vaultdoor.transform.rotation = Quaternion.Euler(rot);
vaultdoor.transform.position = movepos;
//Set skin and owner
vaultdoor.skinID = skinID;
vaultdoor.OwnerID = entity.OwnerID;
//Delay setting Max health and health other wise it defaults to 800
timer.Once(1f, () => {
vaultdoor.SetMaxHealth(VaultMaxHealth);
vaultdoor.SetHealth(VaultMaxHealth);
}
);
//Sets up functions
vaultdoor.Spawn();
vaultdoor.SendNetworkUpdateImmediate();
}
//Cleans out placeholder
NextTick(() => {
entity?.Kill();
}
);
}
//Removes script on unload incase some ones restarting plugin but not restarted server
int DestroyVaultDoorScript() {
int killed = 0;
foreach (var vaultdoor in GameObject.FindObjectsOfType<Door>()) {
foreach (var vd in vaultdoor.GetComponentsInChildren<VaultDoor>()) {
UnityEngine.Object.DestroyImmediate(vd);
killed++;
}
}
return killed;
}
#endregion
#region Commands
//Chat command
[ChatCommand("vaultdoor.craft")]
private void Craft(BasePlayer player) {
if (CanCraft(player)) {
GiveVaultDoor(player);
}
}
//Console command
[ConsoleCommand("vaultdoor.give")]
private void Cmd(ConsoleSystem.Arg arg) {
if (arg.IsAdmin && arg.Args?.Length > 0) {
var player = BasePlayer.Find(arg.Args[0]) ?? BasePlayer.FindSleeping(arg.Args[0]);
if (player == null) {
PrintWarning($"Can't find player with that name/ID! {arg.Args[0]}");
return;
}
GiveVaultDoor(player);
}
}
#endregion
#region Scripts
public class VaultDoor : MonoBehaviour {
//Hold doors info
public Door vdoor = null;
//Holds Position that can be used after Vdoors destroyed.
public Vector3 Position;
//Hold door frames info
public BaseEntity Frame = null;
//List of players that have CUI active
public List<BasePlayer> PlayersCUIed = new List<BasePlayer>();
private void Awake() {
//Setup
vdoor = this.GetComponent<Door>();
if (vdoor == null) return;
Position = vdoor.transform.position;
//Set Custom Health
vdoor.SetMaxHealth(VaultMaxHealth);
vdoor.SetHealth(VaultMaxHealth);
Frame = vdoor.creatorEntity;
//If no creatorEntity most likey a server restart so find it.
if (Frame == null) {
//Offsets scan position since where vault shows isnt where its position is.
Vector3 scanpos = Position;
scanpos += vdoor.transform.forward * 1.0f;
scanpos += vdoor.transform.right * -0.54f;
scanpos += vdoor.transform.up * 0.0f;
if (plugin.showDebug) foreach (BasePlayer BP in BasePlayer.activePlayerList) {
if (BP.IsAdmin) BP.SendConsoleCommand("ddraw.sphere", 8f, Color.red, scanpos, 0.5f);
}
List<BaseEntity> BuildingBlock = new List<BaseEntity>();
//Scans area for players
Vis.Entities<BaseEntity>(scanpos, 0.5f, BuildingBlock);
foreach (BaseEntity doorframe in BuildingBlock) {
if (doorframe.ShortPrefabName == "wall.doorway") {
if (plugin.showDebug) plugin.Puts("Found Creator Doorway " + doorframe.ToString());
Frame = doorframe;
break;
}
}
}
//Setup checking if door frame has been destroyed
InvokeRepeating("CheckFrame", 5, 8);
InvokeRepeating("VaultHealthBar", 2, 2);
}
void VaultHealthBar() {
List<BasePlayer> PlayersInRange = new List<BasePlayer>();
//Scans area for players
Vis.Entities<BasePlayer>(vdoor.transform.position, 5f, PlayersInRange);
//Logic to remove CUI from players that have left area
foreach (BasePlayer bp in PlayersCUIed.ToArray()) {
if (!PlayersInRange.Contains(bp)) {
CuiHelper.DestroyUi(bp, "VaultHealth");
PlayersCUIed.Remove(bp);
}
}
//Shows CUI to each player in range
if (PlayersInRange.Count != 0) {
foreach (BasePlayer player in PlayersInRange.ToArray()) {
if (!player.IsSleeping()) {
CuiHelper.DestroyUi(player, "VaultHealth");
var elements = new CuiElementContainer();
elements.Add(new CuiLabel {
Text = {
Text = "Vault Health " + vdoor._health.ToString("#.##") + "/" + vdoor._maxHealth.ToString(), FontSize = 16, Align = TextAnchor.MiddleCenter
}
, RectTransform = {
AnchorMin = "0.806 0.955", AnchorMax = "0.99 0.989"
}
}
, "Overlay", "VaultHealth");
CuiHelper.AddUi(player, elements);
if (!PlayersCUIed.Contains(player)) {
PlayersCUIed.Add(player);
}
}
}
}
}
void CheckFrame() {
//Frame has been destoryed so destroy vault
try {
if (Frame == null && vdoor != null) {
foreach (var effect in effects) {
Effect.server.Run(effect, Position);
}
vdoor.Kill();
}
}
catch {
}
}
public void TryPickup(BasePlayer player) {
//Owner has hit with hammer, Destroy frame and vault door and refund them one.
if (vdoor.OwnerID == player.userID) {
vdoor.Kill();
if (Frame != null) {
Frame.Kill();
}
plugin.GiveVaultDoor(player, true);
}
}
}
#endregion
}
}