C#:
using Network;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using ProtoBuf;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using UnityEngine;
using static Facepunch.Rust.Analytics.Server;
namespace Oxide.Plugins {
[Info ("CustomLootPrefables", "suck my dick", "1.0.0" )]
[Description ("Loot custom things" )]
public class CustomLootPrefables : RustPlugin {
public const bool DebugMode = false;
public static CustomLootPrefables Instance {
get;
private set;
}
public System.Random Randomizer {
get;
set;
}
= new System.Random ();
public System.Random GetSeededRandomizer (int seed ) {
return new System.Random (seed );
}
#region Permissions
public const string AdminPerm = "CustomLootPrefables.admin";
public const string EditorPerm = "CustomLootPrefables.editor";
public void RegisterPermissions () {
permission.RegisterPermission (AdminPerm, this );
permission.RegisterPermission (EditorPerm, this );
}
#endregion
#region Plugins
[PluginReference]
Plugin ImageLibrary;
[PluginReference]
Plugin QuickSort;
[PluginReference]
Plugin ZoneManager;
public void RefreshPlugins () {
if (ImageLibrary == null || !ImageLibrary.IsLoaded ) {
ImageLibrary = plugins.Find ("ImageLibrary" );
ImageLibrary?.Load ();
}
if (QuickSort == null || !QuickSort.IsLoaded ) {
QuickSort = plugins.Find ("QuickSort" );
QuickSort?.Load ();
}
if (ZoneManager == null || !ZoneManager.IsLoaded ) {
ZoneManager = plugins.Find ("ZoneManager" );
ZoneManager?.Load ();
}
}
#endregion
#region Raycast
private bool TryGetClosestRayPoint (BasePlayer player, out object closestEnt, out Vector3 closestHitpoint ) {
var hits = Physics.RaycastAll (player.eyes.HeadRay (), Config.Distance );
var closestdist = 999999f;
closestHitpoint = player.eyes.position;
closestEnt = false;
foreach (var hit in hits ) {
var colliderName = hit.collider.name.ToLower ().Trim ();
if (hit.distance < closestdist && !colliderName.Contains ("preventbuilding" ) && !colliderName.Contains ("prevent_building" ) && !colliderName.Contains ("prevent_movement" ) && !colliderName.Contains ("terrain" ) && !colliderName.Contains ("player.prefab" ) ) {
closestdist = hit.distance;
closestEnt = hit.collider;
closestHitpoint = hit.point;
}
}
hits = null;
if (closestEnt is bool ) return false;
return true;
}
#endregion
#region CUI
public const string CUIInteractionName = "stlootable";
public const string CUIEditorInteractionName = "stlootableeditorinteraction";
public const string CUIEditorName = "stlootableeditor";
public const string CUICodeLockInputName = "stlootableclin";
public const string CUIPinAppendCommand = "CustomLootPrefables.pinappend";
public const string CUIPinApplyCommand = "CustomLootPrefables.pinapply";
public const string CUIPinUndoCommand = "CustomLootPrefables.pinundo";
public const string DamageColor = "1 0.3 0.3 0.8";
public const string HackingColor = "0.5 0.8 0.3 0.8";
public Dictionary<BasePlayer, PlayerInteraction?> CUIPlayers {
get;
set;
}
= new Dictionary<BasePlayer, PlayerInteraction?> (800 );
public Dictionary<BasePlayer, TimeSince> TimedPlayers {
get;
set;
}
= new Dictionary<BasePlayer, TimeSince> (800 );
public Dictionary<BasePlayer, Vector3> PositionCache {
get;
set;
}
= new Dictionary<BasePlayer, Vector3> (800 );
public Dictionary<BasePlayer, string> PinCache {
get;
set;
}
= new Dictionary<BasePlayer, string> (800 );
public const int ProcessorCount = 2;
public struct PlayerInteraction {
public RootConfig.Interaction Interaction {
get;
set;
}
public RootLock Lock {
get;
set;
}
public RootHack Hack {
get;
set;
}
public RootData.Lootable Lootable {
get;
set;
}
public bool IsLoadingTimer {
get;
set;
}
public DateTime Timer {
get;
set;
}
public float TimerTime => (float )(DateTime.Now - Timer ).TotalSeconds;
}
public void DrawInteraction (BasePlayer player, RootConfig.Interaction interaction, RootConfig.LootableDefinition definition, RootData.Lootable lootable, bool transition = true, bool enableDot = true, bool reset = true ) {
UndrawInteraction (player, reset );
var container = new CuiElementContainer ();
var background = container.Add (new CuiPanel {
Image = {
Color = $"0 0 0 0"
}
, RectTransform = {
AnchorMin = "0.36 0.36", AnchorMax = "0.64 0.738"
}
, CursorEnabled = false
}
, "Hud", CUIInteractionName );
var offset = "0 -10";
var fade = transition ? 0.3f : 0f;
var @lock = lootable != null && lootable.Lock != null ? lootable.Lock : null;
var hack = lootable != null && lootable.Hack != null ? lootable.Hack : null;
var i = default (PlayerInteraction? );
if (!CUIPlayers.ContainsKey (player ) ) CUIPlayers.Add (player, i = new PlayerInteraction {
Interaction = interaction, Lock = @lock, Lootable = lootable
}
);
else i = CUIPlayers [player ];
if (enableDot ) container.Add (new CuiElement {
Parent = background, FadeOut = fade, Components = {
Death.GetRawImage (Config.Urls.DotUrl, fade : fade ), new CuiRectTransformComponent {
AnchorMin = "0 0", AnchorMax = "1 1", OffsetMin = offset, OffsetMax = offset
}
}
}
);
if (Config.ShadowOpacity != 0f ) container.Add (new CuiElement {
Parent = background, FadeOut = fade, Components = {
Death.GetRawImage (Config.Urls.ShadowUrl, color : $"1 1 1 {Config.ShadowOpacity}", fade : fade ), new CuiRectTransformComponent {
AnchorMin = "0 0", AnchorMax = "1 1", OffsetMin = offset, OffsetMax = offset
}
}
}
);
container.Add (new CuiElement {
Parent = background, FadeOut = fade, Components = {
Death.GetRawImage (lootable != null && lootable.IsBusy (player ) ? Config.Urls.BusyUrl : (@lock == null ? (hack == null ? interaction.Icon : hack.IsHacking ? Config.Urls.HackingUrl : Config.Urls.HackUrl ) : Config.Urls.LockUrl ), fade : fade ), new CuiRectTransformComponent {
AnchorMin = "0.46 0.53", AnchorMax = "0.54 0.63", OffsetMin = offset, OffsetMax = offset
}
}
}
);
container.Add (new CuiLabel {
Text = {
Text = $"<b>{( lootable != null && lootable.IsBusy ( player ) ? $" {
Config.BusyName
}
" : ( @lock == null ? hack == null ? interaction.Text : hack.IsHacking ? Config.HackingName : Config.HackName : Config.LockName ) )}</b>{( DebugMode ? $" {
lootable?.LastRefillTick
}
" : "" )}".ToUpper (), FadeIn = fade, FontSize = 13, Font = "robotocondensed-regular.ttf", Align = TextAnchor.LowerCenter
}
, RectTransform = {
AnchorMin = $"0 0.435", AnchorMax = $"1 1"
}
}
, background );
if (lootable != null ) {
if (lootable.IsLocked () && definition != null && definition.Lock != null ) {
var value = lootable.Lock.Health;
var total = definition.Lock.Health * Config.LootableHealthMultiplier;
var count = lootable.Contents.Count;
DrawInteractionBar (background, container, value, total, fade, count, definition, lootable );
}
else if (lootable.Hack != null && definition != null && definition.Hack != null ) {
var time = lootable.GetHackTime ();
var totalTime = lootable.GetTotalHackingTime ();
if (lootable.IsHacking () ) {
DrawInteractionBar (background, container, totalTime - time, totalTime, fade, -1, definition, textOne : $"{totalTime - time:0}s", textTwo : $"Please wait...", hackMode : true );
}
}
}
if (i != null && i.Value.IsLoadingTimer ) {
var span = DateTime.Now - i.Value.Timer;
var value = definition.Timer - (float )span.TotalSeconds;
var total = definition.Timer;
DrawInteractionBar (background, container, value, total, fade, 0, definition, textOne : $"{value:0}s", textTwo : "", hackMode : true );
}
CuiHelper.AddUi (player, container );
}
public void UndrawInteraction (BasePlayer player, bool reset = true ) {
if (reset && !CUIPlayers.ContainsKey (player ) ) return;
for (int i = 0; i < ProcessorCount; i++ ) {
CuiHelper.DestroyUi (player, CUICodeLockInputName );
}
for (int i = 0; i < ProcessorCount; i++ ) {
CuiHelper.DestroyUi (player, CUIInteractionName );
}
for (int i = 0; i < ProcessorCount; i++ ) {
CuiHelper.DestroyUi (player, CUIEditorInteractionName );
}
for (int i = 0; i < ProcessorCount; i++ ) {
CuiHelper.DestroyUi (player, CUIEditorName );
}
if (reset ) CUIPlayers.Remove (player );
}
public void DrawInteractionBar (string background, CuiElementContainer container, float value, float total, float fade, int count = -1, RootConfig.LootableDefinition definition = null, RootData.Lootable lootable = null, string textOne = null, string textTwo = null, bool hackMode = false ) {
container.Add (new CuiLabel {
Text = {
Text = textOne == null ? $"<b>{value:n0} / {total:n0}</b>".ToUpper () : textOne, FadeIn = fade, FontSize = 10, Font = "robotocondensed-regular.ttf", Align = TextAnchor.UpperRight
}
, RectTransform = {
AnchorMin = "0.3 0.9", AnchorMax = "0.7 1"
}
}
, background );
var bar = container.Add (new CuiPanel {
Image = {
Color = hackMode ? HackingColor : DamageColor, FadeIn = fade
}
, RectTransform = {
AnchorMin = "0.3 0.925", AnchorMax = "0.7 0.95"
}
, CursorEnabled = false
}
, background );
container.Add (new CuiPanel {
Image = {
Color = $"1 1 1 1", FadeIn = fade
}
, RectTransform = {
AnchorMin = "0 0", AnchorMax = $"{Scale ( value, 0f, total, 0f, 1f )} 1"
}
, CursorEnabled = false
}
, bar );
if ((definition != null && Instance.Config.ShowLockedLootableApproximateCount ) || textTwo != null ) {
var randomizer = GetSeededRandomizer (lootable == null ? definition.InteractionIndex : (int )(lootable.Position.x + lootable.Position.y + lootable.Position.z + definition.InteractionIndex ) );
container.Add (new CuiLabel {
Text = {
Text = textTwo == null ? $"~{randomizer.Next ( count - 2, count + 2 ):n0} items appx.".ToUpper () : textTwo, FadeIn = fade, FontSize = 10, Font = "robotocondensed-regular.ttf", Align = TextAnchor.UpperLeft
}
, RectTransform = {
AnchorMin = "0.3 0.9", AnchorMax = "0.7 1"
}
}
, background );
randomizer = null;
}
}
private void DrawCodeLockInput (BasePlayer player ) {
if (!PinCache.ContainsKey (player ) ) PinCache.Add (player, string.Empty );
for (int i = 0; i < 5; i++ ) {
CuiHelper.DestroyUi (player, CUICodeLockInputName );
}
var container = new CuiElementContainer ();
var background = container.Add (new CuiPanel {
Image = {
Color = $"0.3 0.3 0.3 0.9", Material = "assets/content/ui/uibackgroundblur.mat"
}
, RectTransform = {
AnchorMin = "0 0", AnchorMax = "1 1"
}
, CursorEnabled = true
}
, "Hud", CUICodeLockInputName );
container.Add (new CuiButton {
Button = {
Command = $"{CUIPinApplyCommand}", Color = "0 0 0 0"
}
, Text = {
Text = string.Empty
}
, RectTransform = {
AnchorMin = "0 0", AnchorMax = "1 1"
}
}
, background );
var panel = container.Add (new CuiPanel {
Image = {
Color = $"0 0 0 0"
}
, RectTransform = {
AnchorMin = "0.425 0.35", AnchorMax = "0.575 0.7"
}
, CursorEnabled = false
}
, background );
container.Add (new CuiLabel {
Text = {
Text = $"<b>{Config.CodeInputTitle}</b>".ToUpper (), FontSize = 18, Font = "robotocondensed-regular.ttf", Align = TextAnchor.UpperCenter
}
, RectTransform = {
AnchorMin = $"0 0.75", AnchorMax = $"1 0.985"
}
}
, panel );
var pinText = "";
foreach (var number in PinCache [player ] ) pinText += $"{number} ";
var pin = container.Add (new CuiPanel {
Image = {
Color = $"0 0 0 0.5"
}
, RectTransform = {
AnchorMin = "0.25 0.78", AnchorMax = "0.75 0.875"
}
, CursorEnabled = false
}
, panel );
container.Add (new CuiLabel {
Text = {
Text = $"<b>{pinText.Trim ()}</b>".ToUpper (), Color = "1 1 1 0.7", FontSize = 18, Font = "robotocondensed-regular.ttf", Align = TextAnchor.MiddleCenter
}
, RectTransform = {
AnchorMin = $"0 0", AnchorMax = $"1 1"
}
}
, pin );
#region Buttons
var offset = 0f;
var horizontalOffset = 12f;
var spacing = 37.5f;
var count = 9;
for (int i = 0; i < 3; i++ ) {
container.Add (new CuiButton {
Button = {
Command = $"{CUIPinAppendCommand} {count - 2}", Color = "0.8 0.8 0.8 0.35"
}
, Text = {
Text = $"<b>{count - 2}</b>", Align = TextAnchor.MiddleCenter, Color = "0.15 0.15 0.15 0.7", Font = "robotocondensed-regular.ttf", FontSize = 19
}
, RectTransform = {
AnchorMin = "0.2 0.62", AnchorMax = "0.35 0.75", OffsetMin = $"{horizontalOffset} {offset}", OffsetMax = $"{horizontalOffset} {offset}"
}
}
, panel );
container.Add (new CuiButton {
Button = {
Command = $"{CUIPinAppendCommand} {count - 1}", Color = "0.8 0.8 0.8 0.35"
}
, Text = {
Text = $"<b>{count - 1}</b>", Align = TextAnchor.MiddleCenter, Color = "0.15 0.15 0.15 0.7", Font = "robotocondensed-regular.ttf", FontSize = 19
}
, RectTransform = {
AnchorMin = "0.2 0.62", AnchorMax = "0.35 0.75", OffsetMin = $"{horizontalOffset + 32} {offset}", OffsetMax = $"{horizontalOffset + 32} {offset}"
}
}
, panel );
container.Add (new CuiButton {
Button = {
Command = $"{CUIPinAppendCommand} {count}", Color = "0.8 0.8 0.8 0.35"
}
, Text = {
Text = $"<b>{count}</b>", Align = TextAnchor.MiddleCenter, Color = "0.15 0.15 0.15 0.7", Font = "robotocondensed-regular.ttf", FontSize = 19
}
, RectTransform = {
AnchorMin = "0.2 0.62", AnchorMax = "0.35 0.75", OffsetMin = $"{horizontalOffset + 64} {offset}", OffsetMax = $"{horizontalOffset + 64} {offset}"
}
}
, panel );
offset -= spacing;
count -= 3;
}
container.Add (new CuiButton {
Button = {
Command = $"{CUIPinAppendCommand} 0", Color = "0.8 0.8 0.8 0.35"
}
, Text = {
Text = $"<b>0</b>", Align = TextAnchor.MiddleCenter, Color = "0.15 0.15 0.15 0.7", Font = "robotocondensed-regular.ttf", FontSize = 19
}
, RectTransform = {
AnchorMin = "0.2 0.62", AnchorMax = "0.515 0.75", OffsetMin = $"{horizontalOffset} {offset}", OffsetMax = $"{horizontalOffset} {offset}"
}
}
, panel );
var acceptButton = container.Add (new CuiButton {
Button = {
Command = $"{CUIPinApplyCommand}", Color = "0.2 0.85 0.2 0.35"
}
, Text = {
Text = string.Empty, Align = TextAnchor.MiddleCenter, Color = "0.15 0.15 0.15 0.7", Font = "robotocondensed-regular.ttf", FontSize = 19
}
, RectTransform = {
AnchorMin = "0.535 0.62", AnchorMax = "0.68 0.75", OffsetMin = $"{horizontalOffset} {offset}", OffsetMax = $"{horizontalOffset} {offset}"
}
}
, panel );
container.Add (new CuiElement {
Parent = acceptButton, Components = {
Death.GetRawImage (Config.Urls.CheckUrl, color : "0.15 0.15 0.15 0.7" ), new CuiRectTransformComponent {
AnchorMin = "0.2 0.22", AnchorMax = "0.8 0.78"
}
}
}
);
offset -= spacing;
container.Add (new CuiButton {
Button = {
Command = $"{CUIPinUndoCommand}", Color = "0.5 0.5 0.5 0.35"
}
, Text = {
Text = $"<b>C</b>", Align = TextAnchor.MiddleCenter, Color = "1 1 1 0.4", Font = "robotocondensed-regular.ttf", FontSize = 19
}
, RectTransform = {
AnchorMin = "0.2 0.62", AnchorMax = "0.68 0.75", OffsetMin = $"{horizontalOffset} {offset}", OffsetMax = $"{horizontalOffset} {offset}"
}
}
, panel );
#endregion
CuiHelper.AddUi (player, container );
if (!CUIPlayers.ContainsKey (player ) ) CUIPlayers.Add (player, new PlayerInteraction () );
}
public bool IsLootingLootable (BasePlayer player, RootData.Lootable lootable ) {
if (!CUIPlayers.ContainsKey (player ) ) return false;
return CUIPlayers [player ]?.Lootable == lootable;
}
[ConsoleCommand (CUIPinAppendCommand )]
private void PinAppendCommand (ConsoleSystem.Arg arg ) {
var player = arg.Player ();
if (player == null ) return;
if (PinCache [player ].Length >= 4 ) PinCache [player ] = string.Empty;
PinCache [player ] += arg.Args [0 ];
DrawCodeLockInput (player );
}
[ConsoleCommand (CUIPinApplyCommand )]
private void PinApplyCommand (ConsoleSystem.Arg arg ) {
var player = arg.Player ();
if (player == null ) return;
var interaction = CUIPlayers [player ];
if (string.IsNullOrEmpty (PinCache [player ] ) || PinCache [player ].Length < 4 ) {
UndrawInteraction (player );
PinCache [player ] = string.Empty;
return;
}
if (PinCache [player ] == interaction?.Lootable.Hack.Code ) {
var definition = interaction?.Lootable.GetDefinition ();
var interactionDefinition = Config.Interactions [definition.InteractionIndex ];
PlayerLootContainer (player, interaction?.Lootable.GetContainer (definition.ContainerSize, definition.Liquid, definition.AllowStack ), "genericsmall" );
if (!string.IsNullOrEmpty (interactionDefinition.OpenEffect ) ) SendEffectTo (interactionDefinition.OpenEffect, player );
}
else {
player.ChatMessage ($"Wrong code for that static lootable container." );
}
PinCache [player ] = string.Empty;
UndrawInteraction (player );
}
[ConsoleCommand (CUIPinUndoCommand )]
private void PinUndoCommand (ConsoleSystem.Arg arg ) {
var player = arg.Player ();
if (player == null ) return;
if (!string.IsNullOrEmpty (PinCache [player ] ) ) PinCache [player ] = PinCache [player ].Substring (0, PinCache [player ].Length - 1 );
DrawCodeLockInput (player );
}
#endregion
#region Override
public class Death {
public static string GetImage (string url, bool isPng = true, ulong skin = 0 ) {
try {
var name = GetStringChecksum (url );
if (string.IsNullOrEmpty (url ) ) return string.Empty;
if ((bool )Instance.ImageLibrary.Call ("HasImage", name, skin ) ) {
var success = Instance.ImageLibrary.Call ("GetImage", name, skin );
return !isPng ? null : (string )success;
}
else {
Instance.ImageLibrary.Call ("AddImage", url, name, skin );
return !isPng ? url : null;
}
}
catch {
Instance.RefreshPlugins ();
}
return string.Empty;
}
public static CuiRawImageComponent GetRawImage (string url, ulong skin = 0, string color = "", float fade = 0.3f ) {
var _url = GetImage (url, isPng : false, skin : skin );
var _png = GetImage (url, skin : skin );
return new CuiRawImageComponent {
Url = _url, Png = _png, Color = color, FadeIn = fade
}
;
}
}
public static string GetStringChecksum (string value ) {
if (value.Length <= 3 ) return null;
using (var md5 = MD5.Create () ) {
var hash = md5.ComputeHash (System.Text.Encoding.UTF8.GetBytes (value ) );
return BitConverter.ToString (hash ).Replace ("-", "" ).ToLowerInvariant ();
}
}
private void OnServerInitialized () {
if (Instance != null ) Instance = this;
RegisterPermissions ();
timer.Every (20, () => {
ServerMgr.Instance.StartCoroutine (DoRefillingCalculations () );
}
);
LoadContainer ();
Log ($"Initialized lootables." );
}
private void Loaded () {
RefreshPlugins ();
if (ConfigFile == null ) ConfigFile = new Core.Configuration.DynamicConfigFile ($"{Manager.ConfigPath}/{Name}.json" );
if (DataFile == null ) DataFile = Interface.Oxide.DataFileSystem.GetFile ($"{Name}_data" );
if (!ConfigFile.Exists () ) {
ConfigFile.WriteObject (Config ?? (Config = new RootConfig () ) );
}
else {
Config = ConfigFile.ReadObject<RootConfig> ();
}
if (DataFile.Exists () ) Data = DataFile.ReadObject<RootData> ();
else Data = new RootData ();
if (Instance == null ) Instance = this;
}
private void Unload () {
foreach (var player in CUIPlayers.ToArray () ) {
UndrawInteraction (player.Key );
}
foreach (var player in Editors ) {
UndrawEditor (player.Key, false );
UndrawEditorInteraction (player.Key );
}
foreach (var lootable in Data.Lootables ) {
lootable.ClearContainer ();
}
Data.Lootables.Clear ();
Data.Container.ItemContainer?.Kill ();
Instance = null;
}
private void OnServerSave () {
SaveContainer ();
ConfigFile.WriteObject (Config ?? (Config = new RootConfig () ) );
DataFile.WriteObject (Data ?? (Data = new RootData () ) );
}
private void OnPlayerInput (BasePlayer player, InputState input ) {
if (Config == null || Instance == null ) return;
try {
if (Config.AsyncMode ) {
if (!CoroutineBuffer.ContainsKey (player.userID ) ) CoroutineBuffer.Add (player.userID, true );
else if (CoroutineBuffer [player.userID ] && !input.WasJustPressed (BUTTON.USE ) && !input.WasJustPressed (BUTTON.RELOAD ) ) return;
CoroutineBuffer [player.userID ] = true;
player.StartCoroutine (DoPlayerInput (player, input ) );
}
else {
object closestEnt;
Vector3 closestHitpoint;
if (!TryGetClosestRayPoint (player, out closestEnt, out closestHitpoint ) ) {
if (CUIPlayers.ContainsKey (player ) ) {
var i = CUIPlayers [player ].GetValueOrDefault ();
i.Timer = DateTime.Now;
i.IsLoadingTimer = false;
i.Lootable?.CancelHack ();
CUIPlayers [player ] = i;
}
UndrawEditorInteraction (player );
UndrawInteraction (player );
return;
}
var obj = (closestEnt as Collider )?.gameObject;
if (closestEnt == null || obj == null ) return;
var name = obj.transform.GetRecursiveName ().ToLower ();
if (IsInEditMode (player ) ) {
if (input.WasJustPressed (BUTTON.RELOAD ) ) {
var editor = GetOrCreateEditor (player );
if (!editor.IsEditing ) DrawEditor (player, EditModes.Settings );
}
if (obj.transform.parent != null ) {
if (!EditorInteractionPlayers.ContainsKey (player ) || (EditorInteractionPlayers.ContainsKey (player ) && EditorInteractionPlayers [player ] != obj.transform ) ) {
if (!EditorInteractionPlayers.ContainsKey (player ) ) EditorInteractionPlayers.Add (player, obj.transform );
else EditorInteractionPlayers [player ] = obj.transform;
DrawEditorInteraction (player, obj.transform );
}
}
if (input.WasJustPressed (BUTTON.USE ) ) {
var editor = GetOrCreateEditor (player );
editor.StartEdit (Config.Definitions.FirstOrDefault (x => name.Contains (x.PrefabFilter ) ) ?? new RootConfig.LootableDefinition (obj.transform.name.Split (' ' ) [0 ].ToLower (), 2, new List<RootLootableItemDefinition> () ) );
editor.Transform = obj.transform;
DrawEditor (player );
}
}
else {
if (input.WasJustPressed (BUTTON.FIRE_THIRD ) && permission.UserHasPermission (player.UserIDString, AdminPerm ) && !player.IsHoldingEntity<BaseEntity> () ) {
var ids = ZoneManager?.Call<string []> ("GetPlayerZoneIDs", player ) ?? new string [0 ];
player.ChatMessage ($"<size=10>Looking at:</size>\n<color=orange>{name}</color>\n" + $"<size=10>Zone(s) [{ids.Length:n0}]:</size>\n<color=orange>{( ids.Length == 0 ? "-" : string.Join ( ", ", ids ) )}</color>" );
return;
}
var farAway = Vector3.Distance (closestHitpoint, player.transform.position ) > Config.Distance;
var definition = GetDefinition (obj );
var interaction = definition == null ? null : Config.Interactions [definition.InteractionIndex ];
var lootable = GetLootable (player, obj, definition, false );
var playerInteraction = !CUIPlayers.ContainsKey (player ) ? null : CUIPlayers [player ];
if (definition != null && definition.HasTimer () && lootable == null ) lootable = GetLootable (player, obj, definition, true );
if (lootable != null && !lootable.IsLocked () && definition.HasTimer () ) {
if (playerInteraction == null && !player.inventory.loot.IsLooting () ) {
DrawInteraction (player, interaction, definition, lootable, true, reset : false );
}
var val = playerInteraction.GetValueOrDefault ();
if (input.IsDown (BUTTON.USE ) ) {
if (!PositionCache.ContainsKey (player ) ) PositionCache.Add (player, closestHitpoint );
else PositionCache [player ] = closestHitpoint;
if (input.WasJustPressed (BUTTON.USE ) ) {
val.Timer = DateTime.Now;
val.IsLoadingTimer = true;
CUIPlayers [player ] = val;
DrawInteraction (player, interaction, definition, lootable, true, reset : false );
}
else if (val.IsLoadingTimer && val.TimerTime >= definition.Timer ) {
val.Timer = DateTime.Now;
val.IsLoadingTimer = false;
PlayerLootContainer (player, lootable.GetContainer (definition.ContainerSize, definition.Liquid, definition.AllowStack ), "genericsmall" );
if (!string.IsNullOrEmpty (interaction.OpenEffect ) ) SendEffectTo (interaction.OpenEffect, player );
CUIPlayers [player ] = val;
UndrawInteraction (player, true );
return;
}
}
else {
val.IsLoadingTimer = false;
CUIPlayers [player ] = val;
if (input.WasDown (BUTTON.USE ) && !player.inventory.loot.IsLooting () ) {
DrawInteraction (player, interaction, definition, lootable, false, reset : false );
}
}
CUIPlayers [player ] = val;
if (!TimedPlayers.ContainsKey (player ) || (TimedPlayers.ContainsKey (player ) && TimedPlayers [player ] >= Config.DamageCUIRefreshRate / 2 ) ) {
if (input.IsDown (BUTTON.USE ) && !player.inventory.loot.IsLooting () ) DrawInteraction (player, interaction, definition, lootable, false, reset : false );
if (TimedPlayers.ContainsKey (player ) ) TimedPlayers [player ] = 0f;
else TimedPlayers.Add (player, 0f );
}
return;
}
else {
var val = playerInteraction.GetValueOrDefault ();
val.Timer = DateTime.Now;
val.IsLoadingTimer = false;
CUIPlayers [player ] = val;
}
if (definition != null && !definition.Rule.IsValid (name, player ) ) return;
if (interaction == null && playerInteraction?.Interaction == interaction || playerInteraction?.Lock != lootable?.Lock || playerInteraction?.Interaction != interaction ) {
if (lootable != null && lootable.HackingPlayer == player ) {
lootable.CancelHack ();
}
UndrawInteraction (player );
}
if (!farAway && definition != null && !player.inventory.loot.IsLooting () && !Config.IsFilteredOut (name ) && Config.ZoneCheck (player ) ) {
if (definition.Lock != null || definition.Hack != null ) lootable = GetLootable (player, obj, definition, true );
if (!CUIPlayers.ContainsKey (player ) && !player.inventory.loot.IsLooting () ) {
DrawInteraction (player, interaction, definition, lootable, true );
}
}
else {
if (lootable != null && lootable.HackingPlayer == player ) {
lootable.CancelHack ();
}
if (CUIPlayers.ContainsKey (player ) ) UndrawInteraction (player );
}
if (definition != null && !farAway ) {
if (input.WasJustPressed (BUTTON.USE ) ) {
if (lootable == null ) lootable = GetLootable (player, obj, definition, true );
if (lootable == null ) return;
if (!PositionCache.ContainsKey (player ) ) PositionCache.Add (player, closestHitpoint );
else PositionCache [player ] = closestHitpoint;
if (lootable.IsHackable () && !lootable.IsLocked () && !lootable.IsBusy (player ) ) {
lootable.StartHack (player );
DrawInteraction (player, interaction, definition, lootable, true, false );
lootable.Hack.HackingTimer = timer.Every (Config.DamageCUIRefreshRate, () => {
if (!CUIPlayers.ContainsKey (player ) || Vector3.Distance (PositionCache [player ], player.transform.position ) > Config.Distance ) {
if (lootable != null && lootable.HackingPlayer == player ) {
lootable.CancelHack ();
}
UndrawInteraction (player );
return;
}
if (lootable.HackHacked () ) {
var hackNote = ItemManager.CreateByName ("note" );
hackNote.text = $"Successfully hacked! The code is: {lootable.Hack.Code}\n\nPress [RELOAD] to open the code input panel.";
player.GiveItem (hackNote );
lootable.Hack.HackedTimes++;
if (lootable != null && lootable.HackingPlayer == player ) {
lootable.CancelHack ();
}
}
var players = CUIPlayers?.ToArray ();
for (int i = 0; i < players.Length; i++ ) {
if (players [i ].Value?.Lootable == lootable ) {
DrawInteraction (players [i ].Key, interaction, definition, lootable, false, false );
}
}
players = null;
}
);
return;
}
else if (lootable.IsHacking () ) return;
if (!lootable.IsLocked () && CUIPlayers [player ].Value.TimerTime >= definition.Timer ) {
PlayerLootContainer (player, lootable.GetContainer (definition.ContainerSize, definition.Liquid, definition.AllowStack ), "genericsmall" );
if (!string.IsNullOrEmpty (interaction.OpenEffect ) ) SendEffectTo (interaction.OpenEffect, player );
}
}
else if (input.WasJustPressed (BUTTON.RELOAD ) && !lootable.IsLocked () && lootable.IsHackable () ) {
DrawCodeLockInput (player );
}
}
}
}
}
catch {
}
}
private object CanLootPlayer (BasePlayer looted, BasePlayer looter ) {
if (Config == null || Instance == null ) return null;
if (Data.IsLootingLootable (looter ) ) {
return true;
}
return null;
}
private void OnPlayerAttack (BasePlayer player, HitInfo info ) {
if (Config == null || Instance == null ) return;
object closestEnt;
Vector3 closestHitpoint;
if (!TryGetClosestRayPoint (player, out closestEnt, out closestHitpoint ) ) return;
var obj = (closestEnt as Collider )?.gameObject;
if (closestEnt == null || obj == null ) return;
var lootable = GetLootable (player, obj );
if (lootable == null ) return;
var definition = lootable.GetDefinition ();
if (!lootable.IsLocked () ) return;
var multiplier = info.damageProperties.fallback.GetMultiplier (HitArea.Head );
var damageAmount = GetRandomNumber (Config.DamageMultiplierMinimum, Config.DamageMultiplierMaximum ) * multiplier;
lootable.Lock.Health -= damageAmount;
if (lootable.Lock.Health <= 0 ) {
lootable.Lock = null;
}
if (!TimedPlayers.ContainsKey (player ) || (TimedPlayers.ContainsKey (player ) && TimedPlayers [player ] >= Config.DamageCUIRefreshRate ) || !lootable.IsLocked () ) {
ServerMgr.Instance.Invoke (() => {
var players = CUIPlayers.ToArray ();
foreach (var cuiPlayer in players ) {
if (cuiPlayer.Value?.Lootable == lootable ) {
DrawInteraction (cuiPlayer.Key, Config.Interactions [definition.InteractionIndex ], definition, lootable, false );
}
}
players = null;
}
, 0.2f );
TimedPlayers [player ] = 0;
}
}
private void OnPlayerLootEnd (PlayerLoot inventory ) {
var player = inventory.baseEntity;
if (player == null ) return;
if (CUIPlayers.ContainsKey (player ) ) CUIPlayers [player ] = null;
}
private void OnPluginLoaded (Plugin name ) {
RefreshPlugins ();
}
private void OnPluginUnloaded (Plugin name ) {
RefreshPlugins ();
}
private void OnNewSave (string filename ) {
DataFile.WriteObject (Data = new RootData () );
}
private void OnEntityKill (TimedExplosive entity ) {
var colliders = Facepunch.Pool.GetList<Collider> ();
Vis.Colliders (entity.transform.position, entity.explosionRadius, colliders );
foreach (var collider in colliders ) {
var lootable = GetLootable (null, collider.gameObject );
if (lootable != null && lootable.IsLocked () ) {
lootable.Lock.Health -= entity.damageTypes.Sum (x => x.amount );
lootable.Lock = null;
}
}
Facepunch.Pool.FreeList (ref colliders );
}
public static void PlayerLootContainer (BasePlayer player, ItemContainer container, string lootPanel ) {
player.inventory.loot.Clear ();
player.inventory.loot.PositionChecks = false;
player.inventory.loot.entitySource = player;
player.inventory.loot.itemSource = null;
player.inventory.loot.AddContainer (container );
player.inventory.loot.MarkDirty ();
player.inventory.loot.SendImmediate ();
player.ClientRPCPlayer (null, player, "RPC_OpenLootPanel", lootPanel );
Instance.QuickSort?.CallHook ("UserInterface", player );
}
public static ItemContainer CreateContainer (int capacity = 1, bool liquid = false ) {
var container = new ItemContainer {
isServer = true, allowedContents = liquid ? ItemContainer.ContentsType.Liquid : ItemContainer.ContentsType.Generic, capacity = capacity
}
;
container.GiveUID ();
return container;
}
public Dictionary<ulong, bool> CoroutineBuffer {
get;
private set;
}
= new Dictionary<ulong, bool> ();
public IEnumerator DoPlayerInput (BasePlayer player, InputState input ) {
object closestEnt;
Vector3 closestHitpoint;
if (!TryGetClosestRayPoint (player, out closestEnt, out closestHitpoint ) ) {
if (CUIPlayers.ContainsKey (player ) ) {
var i = CUIPlayers [player ].GetValueOrDefault ();
i.Timer = DateTime.Now;
i.IsLoadingTimer = false;
i.Lootable?.CancelHack ();
CUIPlayers [player ] = i;
}
UndrawEditorInteraction (player );
UndrawInteraction (player );
CoroutineBuffer [player.userID ] = false;
yield break;
}
var obj = (closestEnt as Collider )?.gameObject;
if (closestEnt == null || obj == null ) {
CoroutineBuffer [player.userID ] = false;
yield break;
}
var name = obj.transform.GetRecursiveName ().ToLower ();
try {
if (IsInEditMode (player ) ) {
if (input.WasJustPressed (BUTTON.RELOAD ) ) {
var editor = GetOrCreateEditor (player );
if (!editor.IsEditing ) DrawEditor (player, EditModes.Settings );
}
if (obj != null ) {
if (!EditorInteractionPlayers.ContainsKey (player ) || (EditorInteractionPlayers.ContainsKey (player ) && EditorInteractionPlayers [player ] != obj.transform ) ) {
if (!EditorInteractionPlayers.ContainsKey (player ) ) EditorInteractionPlayers.Add (player, obj.transform );
else EditorInteractionPlayers [player ] = obj.transform;
DrawEditorInteraction (player, obj.transform );
}
}
if (input.WasJustPressed (BUTTON.USE ) ) {
var editor = GetOrCreateEditor (player );
editor.StartEdit (Config.Definitions.FirstOrDefault (x => obj.transform.name.ToLower ().Contains (x.PrefabFilter ) ) ?? new RootConfig.LootableDefinition (obj.transform.name.Split (' ' ) [0 ].ToLower (), 2, new List<RootLootableItemDefinition> () ) );
editor.Transform = obj.transform;
DrawEditor (player );
}
}
else {
if (input.WasJustPressed (BUTTON.FIRE_THIRD ) && permission.UserHasPermission (player.UserIDString, AdminPerm ) && !player.IsHoldingEntity<BaseEntity> () ) {
var ids = ZoneManager?.Call<string []> ("GetPlayerZoneIDs", player ) ?? new string [0 ];
player.ChatMessage ($"<size=10>Looking at:</size>\n<color=orange>{name}</color>\n" + $"<size=10>Zone(s) [{ids.Length:n0}]:</size>\n<color=orange>{( ids.Length == 0 ? "-" : string.Join ( ", ", ids ) )}</color>" );
yield break;
}
var farAwa
// ... [Code preview truncated due to length. Full source in attached file] ...