C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System;
using System.Collections.Generic;
using UnityEngine;
using Oxide.Core;
using System.Text;
using System.Linq;
namespace Oxide.Plugins {
[Info ("Recycle", "Calytic", "2.1.10")]
[Description ("Recycle crafted items to base resources")]
class Recycle : RustPlugin {
#region Configuration
float cooldownMinutes;
float refundRatio;
float scrapMultiplier;
string box;
bool npconly;
List<object> npcids;
float radiationMax;
List<object> recyclableTypes;
List<object> blackList;
bool allowSafeZone;
#endregion
#region State
Dictionary<string, DateTime> recycleCooldowns = new Dictionary<string, DateTime> ();
class OnlinePlayer {
public BasePlayer Player;
public BasePlayer Target;
public StorageContainer View;
public List<BasePlayer> Matches;
public OnlinePlayer (BasePlayer player) {
}
}
public Dictionary<ItemContainer, ulong> containers = new Dictionary<ItemContainer, ulong> ();
[OnlinePlayers]
Hash<BasePlayer, OnlinePlayer> onlinePlayers = new Hash<BasePlayer, OnlinePlayer> ();
#endregion
#region Initialization
protected override void LoadDefaultConfig () {
Config ["Settings", "box"] = "assets/prefabs/deployable/woodenbox/woodbox_deployed.prefab";
Config ["Settings", "cooldownMinutes"] = 5;
Config ["Settings", "refundRatio"] = 0.5f;
Config ["Settings", "scrapMultiplier"] = 1f;
Config ["Settings", "radiationMax"] = 1;
Config ["Settings", "NPCOnly"] = false;
Config ["Settings", "NPCIDs"] = new List<object> ();
Config ["Settings", "recyclableTypes"] = GetDefaultRecyclableTypes ();
Config ["Settings", "blacklist"] = new List<object>();
Config ["Settings", "allowSafeZone"] = true;
Config ["VERSION"] = Version.ToString ();
}
void Unloaded () {
foreach (var player in BasePlayer.activePlayerList) {
OnlinePlayer onlinePlayer;
if (onlinePlayers.TryGetValue (player, out onlinePlayer) && onlinePlayer.View != null) {
CloseBoxView (player, onlinePlayer.View);
}
}
}
void Init () {
Unsubscribe (nameof (CanNetworkTo));
Unsubscribe (nameof (OnEntityTakeDamage));
}
void Loaded () {
permission.RegisterPermission ("recycle.use", this);
permission.RegisterPermission ("recycle.nocooldown", this);
LoadMessages ();
CheckConfig ();
cooldownMinutes = GetConfig ("Settings", "cooldownMinutes", 5f);
box = GetConfig ("Settings", "box", "assets/prefabs/deployable/woodenbox/box_wooden.item.prefab");
refundRatio = GetConfig ("Settings", "refundRatio", 0.5f);
scrapMultiplier = GetConfig ("Settings", "scrapMultiplier", 1f);
radiationMax = GetConfig ("Settings", "radiationMax", 1f);
recyclableTypes = GetConfig ("Settings", "recyclableTypes", GetDefaultRecyclableTypes ());
blackList = GetConfig("Settings", "blacklist", new List<object>());
npconly = GetConfig ("Settings", "NPCOnly", false);
npcids = GetConfig ("Settings", "NPCIDs", new List<object> ());
allowSafeZone = GetConfig ("Settings", "allowSafeZone", true);
}
void CheckConfig () {
if (Config ["VERSION"] == null) {
// FOR COMPATIBILITY WITH INITIAL VERSIONS WITHOUT VERSIONED CONFIG
ReloadConfig ();
}
else if (GetConfig ("VERSION", "") != Version.ToString ()) {
// ADDS NEW, IF ANY, CONFIGURATION OPTIONS
ReloadConfig ();
}
}
protected void ReloadConfig () {
Config ["VERSION"] = Version.ToString ();
// NEW CONFIGURATION OPTIONS HERE
// END NEW CONFIGURATION OPTIONS
PrintToConsole ("Upgrading configuration file");
SaveConfig ();
}
void LoadMessages () {
lang.RegisterMessages (new Dictionary<string, string> {
{
"Recycle: Complete", "Recycling <color=lime>{0}</color> to {1}% base materials:"
}
, {
"Recycle: Item", " <color=lime>{0}</color> X <color=yellow>{1}</color>"
}
, {
"Recycle: Invalid", "Cannot recycle that!"
}
, {
"Denied: Permission", "You lack permission to do that"
}
, {
"Denied: Privilege", "You lack build privileges and cannot do that"
}
, {
"Denied: Swimming", "You cannot do that while swimming"
}
, {
"Denied: Falling", "You cannot do that while falling"
}
, {
"Denied: Mounted", "You cannot do that while mounted"
}
, {
"Denied: Wounded", "You cannot do that while wounded"
}
, {
"Denied: Irradiated", "You cannot do that while irradiated"
}
, {
"Denied: Generic", "You cannot do that right now"
}
, {
"Denied: Ship", "You cannot do that while on a ship"
}
, {
"Denied: Lift", "You cannot do that while on a lift"
}
, {
"Denied: Balloon", "You cannot do that while on a balloon"
}
, {
"Denied: Safe Zone", "You cannot do that while in a safe zone"
}
, {
"Cooldown: Seconds", "You are doing that too often, try again in a {0} seconds(s)."
}
, {
"Cooldown: Minutes", "You are doing that too often, try again in a {0} minute(s)."
}
,
}
, this);
}
List<object> GetDefaultRecyclableTypes () {
return new List<object> () {
ItemCategory.Ammunition.ToString(), ItemCategory.Attire.ToString(), ItemCategory.Common.ToString(), ItemCategory.Component.ToString(), ItemCategory.Construction.ToString(), ItemCategory.Items.ToString(), ItemCategory.Medical.ToString(), ItemCategory.Misc.ToString(), ItemCategory.Tool.ToString(), ItemCategory.Traps.ToString(), ItemCategory.Weapon.ToString(),
}
;
}
bool IsRecycleBox (BaseNetworkable entity) {
foreach (KeyValuePair<BasePlayer, OnlinePlayer> kvp in onlinePlayers) {
if (kvp.Value?.View?.net != null && entity?.net != null && kvp.Value.View.net.ID == entity.net.ID) {
return true;
}
}
return false;
}
#endregion
#region Oxide Hooks
object CanNetworkTo (BaseNetworkable entity, BasePlayer target) {
if (entity == null || target == null || entity == target) return null;
if (target.IsAdmin) return null;
OnlinePlayer onlinePlayer;
bool IsMyBox = false;
if (onlinePlayers.TryGetValue (target, out onlinePlayer)) {
if (onlinePlayer.View != null && onlinePlayer.View.net.ID == entity.net.ID) {
IsMyBox = true;
}
}
if (IsRecycleBox (entity) && !IsMyBox) return false;
return null;
}
object OnEntityTakeDamage (BaseCombatEntity entity, HitInfo hitInfo) {
if (hitInfo == null) return null;
if (entity == null) return null;
if (IsRecycleBox (entity)) return false;
return null;
}
void OnPlayerInit (BasePlayer player) {
onlinePlayers [player].View = null;
onlinePlayers [player].Target = null;
onlinePlayers [player].Matches = null;
}
void OnPlayerDisconnected (BasePlayer player) {
if (onlinePlayers [player].View != null) {
CloseBoxView (player, onlinePlayers [player].View);
}
}
void OnPlayerLootEnd (PlayerLoot inventory) {
BasePlayer player;
if ((player = inventory.GetComponent<BasePlayer> ()) == null) return;
OnlinePlayer onlinePlayer;
if (onlinePlayers.TryGetValue (player, out onlinePlayer) && onlinePlayer.View != null) {
if (onlinePlayer.View == inventory.entitySource) {
CloseBoxView (player, (StorageContainer)inventory.entitySource);
}
}
}
void OnItemAddedToContainer (ItemContainer container, Item item) {
if (container.playerOwner is BasePlayer) {
if (onlinePlayers.ContainsKey (container.playerOwner)) {
BasePlayer owner = container.playerOwner;
if (containers.ContainsKey (container)) {
if (SalvageItem (owner, item)) {
item.Remove (0f);
item.RemoveFromContainer ();
}
else {
ShowNotification (owner, GetMsg ("Recycle: Invalid", owner));
if (!owner.inventory.containerMain.IsFull ()) {
item.MoveToContainer (owner.inventory.containerMain);
}
else if (!owner.inventory.containerBelt.IsFull ()) {
item.MoveToContainer (owner.inventory.containerBelt);
}
}
}
}
}
}
void OnUseNPC (BasePlayer npc, BasePlayer player) {
if (!npcids.Contains (npc.UserIDString)) return;
ShowBox (player, player);
}
void AddNpc (string id) {
npcids.Add (id);
}
void RemoveNpc (string id) {
if (npcids.Contains (id)) {
npcids.Remove (id);
}
}
#endregion
#region Commands
[ConsoleCommand ("rec")]
void ccRec (ConsoleSystem.Arg arg) {
cmdRec (arg.Connection.player as BasePlayer, arg.cmd.Name, arg.Args);
}
//[ConsoleCommand ("receverything")]
//void ccRecEverything (ConsoleSystem.Arg arg)
//{
// if (arg.connection == null) return;
// if (arg.connection.authLevel < 1) return;
// List<ItemDefinition> items = ItemManager.GetItemDefinitions ();
// foreach (ItemDefinition def in items) {
// SalvageItem (arg.Connection.player as BasePlayer, ItemManager.Create (def, 1));
// }
//}
[ChatCommand ("rec")]
void cmdRec (BasePlayer player, string command, string [] args) {
if (npconly) return;
ShowBox (player, player);
}
#endregion
#region Core Methods
void ShowBox (BasePlayer player, BaseEntity target) {
string playerID = player.userID.ToString ();
if (!CanPlayerRecycle (player)) return;
if (cooldownMinutes > 0 && !player.IsAdmin && !permission.UserHasPermission (player.UserIDString, "recycle.nocooldown")) {
DateTime startTime;
if (recycleCooldowns.TryGetValue (playerID, out startTime)) {
DateTime endTime = DateTime.Now;
TimeSpan span = endTime.Subtract (startTime);
if (span.TotalMinutes > 0 && span.TotalMinutes < Convert.ToDouble (cooldownMinutes)) {
double timeleft = System.Math.Round (Convert.ToDouble (cooldownMinutes) - span.TotalMinutes, 2);
if (span.TotalSeconds < 0) {
recycleCooldowns.Remove (playerID);
}
if (timeleft < 1) {
double timelefts = System.Math.Round ((Convert.ToDouble (cooldownMinutes) * 60) - span.TotalSeconds);
SendReply (player, string.Format (GetMsg ("Cooldown: Seconds", player), timelefts.ToString ()));
return;
}
SendReply (player, string.Format (GetMsg ("Cooldown: Minutes", player), System.Math.Round (timeleft).ToString ()));
return;
}
recycleCooldowns.Remove (playerID);
}
}
if (!recycleCooldowns.ContainsKey (player.userID.ToString ())) {
recycleCooldowns.Add (player.userID.ToString (), DateTime.Now);
}
var ply = onlinePlayers [player];
if (ply.View == null) {
if (!OpenBoxView (player, target)) {
recycleCooldowns.Remove (playerID);
}
return;
}
CloseBoxView (player, ply.View);
NextFrame (delegate () {
if (!OpenBoxView (player, target)) {
recycleCooldowns.Remove (playerID);
}
}
);
}
void HideBox (BasePlayer player) {
player.EndLooting ();
var ply = onlinePlayers [player];
if (ply.View == null) {
return;
}
CloseBoxView (player, ply.View);
}
bool OpenBoxView (BasePlayer player, BaseEntity targArg) {
Subscribe (nameof (CanNetworkTo));
Subscribe (nameof (OnEntityTakeDamage));
var pos = new Vector3 (player.transform.position.x, player.transform.position.y - 0.6f, player.transform.position.z);
int slots = 1;
var view = GameManager.server.CreateEntity (box, pos) as StorageContainer;
if (!view) return false;
view.GetComponent<DestroyOnGroundMissing> ().enabled = false;
view.GetComponent<GroundWatch> ().enabled = false;
view.transform.position = pos;
player.EndLooting ();
if (targArg is BasePlayer) {
BasePlayer target = targArg as BasePlayer;
ItemContainer container = new ItemContainer ();
container.playerOwner = player;
container.ServerInitialize ((Item)null, slots);
if ((int)container.uid == 0) container.GiveUID ();
if (!containers.ContainsKey (container)) {
containers.Add (container, player.userID);
}
view.enableSaving = false;
view.Spawn ();
view.inventory = container;
view.SendNetworkUpdate (BasePlayer.NetworkQueue.Update);
onlinePlayers [player].View = view;
onlinePlayers [player].Target = target;
timer.Once (0.2f, delegate () {
if (onlinePlayers [player].View != null) {
onlinePlayers [player].View.PlayerOpenLoot (player);
}
}
);
return true;
}
return false;
}
void CloseBoxView (BasePlayer player, StorageContainer view) {
OnlinePlayer onlinePlayer;
if (!onlinePlayers.TryGetValue (player, out onlinePlayer)) return;
if (onlinePlayer.View == null) return;
if (containers.ContainsKey (view.inventory)) {
containers.Remove (view.inventory);
}
player.inventory.loot.containers = new List<ItemContainer> ();
view.inventory = new ItemContainer ();
if (player.inventory.loot.IsLooting ()) {
player.SendConsoleCommand ("inventory.endloot", null);
}
onlinePlayer.View = null;
onlinePlayer.Target = null;
NextFrame (delegate () {
view.KillMessage ();
if (onlinePlayers.Values.Count (p => p.View != null) <= 0) {
Unsubscribe (nameof (CanNetworkTo));
Unsubscribe (nameof (OnEntityTakeDamage));
}
}
);
}
// bool SalvageItem(BasePlayer player, Item item)
// {
// var sb = new StringBuilder();
//
// var ratio = item.hasCondition ? (item.condition / item.maxCondition) : 1;
//
// sb.Append(string.Format(GetMsg("Recycle: Complete", player), item.info.displayName.english, (refundRatio * 100)));
//
// if (item.info.Blueprint == null)
// {
// return false;
// }
//
// foreach (var ingredient in item.info.Blueprint.ingredients)
// {
// if (!ingredient.itemDef.shortname == "scrap")
// {
// var refundAmount = (double)ingredient.amount / item.info.Blueprint.amountToCreate;
// refundAmount *= item.amount;
// refundAmount *= ratio;
// refundAmount *= refundRatio;
// refundAmount = System.Math.Ceiling(refundAmount);
// if (refundAmount < 1)
// refundAmount = 1;
//
// var newItem = ItemManager.Create(ingredient.itemDef, (int)refundAmount);
//
// ItemBlueprint ingredientBp = ingredient.itemDef.Blueprint;
// if (item.hasCondition)
// newItem.condition = (float)System.Math.Ceiling(newItem.maxCondition * ratio);
//
// player.GiveItem(newItem);
// sb.AppendLine();
// sb.Append(string.Format(GetMsg("Recycle: Item", player), newItem.info.displayName.english, newItem.amount));
// }
// }
//
// ShowNotification(player, sb.ToString());
//
// return true;
// }
//
List<string> exclude = new List<string> () {
"scrap", "antiradpills", "battery.small", "blood", "blueprintbase"
}
;
bool SalvageItem (BasePlayer player, Item item) {
if (item == null) {
return false;
}
if (!recyclableTypes.Contains (Enum.GetName (typeof (ItemCategory), item.info.category))) {
return false;
}
if(blackList.Contains (item.info.shortname)) {
return false;
}
if (item.info.category == ItemCategory.Food) {
return false;
}
if (exclude.Contains (item.info.shortname)) {
return false;
}
var refundAmount = refundRatio;
var sb = new StringBuilder ();
if (item.hasCondition) {
refundAmount = Mathf.Clamp01 (refundAmount * Mathf.Clamp (item.conditionNormalized * item.maxConditionNormalized, 0.1f, 1f));
}
var amountToConsume = 1;
if (item.amount > 1) {
amountToConsume = Mathf.CeilToInt (Mathf.Min (item.amount, item.info.stackable * 0.1f));
}
if (item.info.Blueprint != null && item.info.Blueprint.scrapFromRecycle > 0) {
float scrapAmount = (item.info.Blueprint.scrapFromRecycle * scrapMultiplier) * amountToConsume;
var newItem = ItemManager.CreateByName ("scrap", Convert.ToInt32 (scrapAmount));
if (newItem != null) {
player.GiveItem (newItem);
sb.AppendLine ();
sb.Append (string.Format (GetMsg ("Recycle: Item", player), newItem.info.displayName.english, newItem.amount));
}
}
if (item.info.Blueprint != null && item.info.Blueprint.ingredients.Count > 0) {
item.UseItem (amountToConsume);
foreach (ItemAmount current in item.info.Blueprint.ingredients.OrderBy (x => Core.Random.Range (0, 1000))) {
if (!(current.itemDef.shortname == "scrap") && item.info.Blueprint != null) {
var refundMultiplier = current.amount / item.info.Blueprint.amountToCreate;
var refundMaximum = 0;
if (refundMultiplier <= 1) {
for (var index = 0; index < amountToConsume; ++index) {
if (Core.Random.Range (0, 1) <= refundAmount) {
++refundMaximum;
}
}
}
else {
refundMaximum = Mathf.CeilToInt (Mathf.Clamp (refundMultiplier * refundAmount, 0f, current.amount) * amountToConsume);
}
if (refundMaximum > 0) {
int refundIterations = Mathf.Clamp (Mathf.CeilToInt (refundMaximum / current.itemDef.stackable), 1, refundMaximum);
for (var index = 0; index < refundIterations; ++index) {
var itemAmount = refundMaximum <= current.itemDef.stackable ? refundMaximum : current.itemDef.stackable;
var newItem = ItemManager.Create (current.itemDef, itemAmount);
if (newItem != null) {
player.GiveItem (newItem);
sb.AppendLine ();
sb.Append (string.Format (GetMsg ("Recycle: Item", player), newItem.info.displayName.english, newItem.amount));
refundMaximum -= itemAmount;
if (refundMaximum <= 0) break;
}
}
}
}
}
}
var msg = sb.ToString ();
if (msg != string.Empty) {
ShowNotification (player, msg);
if (Interface.Oxide.CallHook ("OnRecycleItemSalvaged", player, item) != null) {
return false;
}
return true;
}
return false;
}
bool CanPlayerRecycle (BasePlayer player) {
if (!permission.UserHasPermission (player.UserIDString, "recycle.use")) {
SendReply (player, GetMsg ("Denied: Permission", player));
return false;
}
if (!player.CanBuild ()) {
SendReply (player, GetMsg ("Denied: Privilege", player));
return false;
}
if (radiationMax > 0 && player.radiationLevel > radiationMax) {
SendReply (player, GetMsg ("Denied: Irradiated", player));
return false;
}
if (player.IsSwimming ()) {
SendReply (player, GetMsg ("Denied: Swimming", player));
return false;
}
if (!player.IsOnGround () || player.IsFlying || player.isInAir) {
SendReply (player, GetMsg ("Denied: Falling", player));
return false;
}
if (player.isMounted) {
SendReply (player, GetMsg ("Denied: Mounted", player));
return false;
}
if (player.IsWounded ()) {
SendReply (player, GetMsg ("Denied: Wounded", player));
return false;
}
if (player.GetComponentInParent<CargoShip> ()) {
SendReply (player, GetMsg ("Denied: Ship", player));
return false;
}
if (player.GetComponentInParent<HotAirBalloon> ()) {
SendReply (player, GetMsg ("Denied: Balloon", player));
return false;
}
if (player.GetComponentInParent<Lift> ()) {
SendReply (player, GetMsg ("Denied: Lift", player));
return false;
}
if (!allowSafeZone && player.InSafeZone ()) {
SendReply (player, GetMsg ("Denied: Safe Zone", player));
return false;
}
var canRecycle = Interface.Call ("CanRecycleCommand", player);
if (canRecycle != null) {
if (canRecycle is string) {
SendReply (player, Convert.ToString (canRecycle));
}
else {
SendReply (player, GetMsg ("Denied: Generic", player));
}
return false;
}
return true;
}
#endregion
#region GUI
public string jsonNotify = @"[{""name"":""NotifyMsg"",""parent"":""Overlay"",""components"":[{""type"":""UnityEngine.UI.Image"",""color"":""0 0 0 0.89""},{""type"":""RectTransform"",""anchormax"":""0.99 0.94"",""anchormin"":""0.69 0.77""}]},{""name"":""MassText"",""parent"":""NotifyMsg"",""components"":[{""type"":""UnityEngine.UI.Text"",""text"":""{msg}"",""fontSize"":16,""align"":""UpperLeft""},{""type"":""RectTransform"",""anchormax"":""0.98 0.99"",""anchormin"":""0.01 0.02""}]},{""name"":""CloseButton{1}"",""parent"":""NotifyMsg"",""components"":[{""type"":""UnityEngine.UI.Button"",""color"":""0.95 0 0 0.68"",""close"":""NotifyMsg"",""imagetype"":""Tiled""},{""type"":""RectTransform"",""anchormax"":""0.99 1"",""anchormin"":""0.91 0.86""}]},{""name"":""CloseButtonLabel"",""parent"":""CloseButton{1}"",""components"":[{""type"":""UnityEngine.UI.Text"",""text"":""X"",""fontSize"":10,""align"":""MiddleCenter""},{""type"":""RectTransform"",""anchormax"":""1 1"",""anchormin"":""0 0""}]}]";
public void ShowNotification (BasePlayer player, string msg) {
HideNotification (player);
string send = jsonNotify.Replace ("{msg}", msg);
CommunityEntity.ServerInstance.ClientRPCEx (new Network.SendInfo {
connection = player.net.connection
}
, null, "AddUI", send);
timer.Once (3f, delegate () {
HideNotification (player);
}
);
}
public void HideNotification (BasePlayer player) {
CommunityEntity.ServerInstance.ClientRPCEx (new Network.SendInfo {
connection = player.net.connection
}
, null, "DestroyUI", "NotifyMsg");
}
#endregion
#region HelpText
void SendHelpText (BasePlayer player) {
var sb = new StringBuilder ().Append ("Recycle by <color=#ce422b>http://rustservers.io</color>\n").Append (" ").Append ("<color=\"#ffd479\">/rec</color> - Open recycle box").Append ("\n");
player.ChatMessage (sb.ToString ());
}
#endregion
#region Helper methods
string GetMsg (string key, BasePlayer player = null) {
return lang.GetMessage (key, this, player == null ? null : player.UserIDString);
}
T GetConfig<T> (string name, T defaultValue) {
if (Config [name] == null) {
Config [name] = defaultValue;
Config.Save ();
return defaultValue;
}
return (T)Convert.ChangeType (Config [name], typeof (T));
}
T GetConfig<T> (string name, string name2, T defaultValue) {
if (Config [name, name2] == null) {
Config [name, name2] = defaultValue;
Config.Save ();
return defaultValue;
}
return (T)Convert.ChangeType (Config [name, name2], typeof (T));
}
#endregion
}
}