C#:
using System;
using System.Reflection;
using System.Linq;
using System.Collections.Generic;
using Oxide.Game.Rust.Cui;
using UnityEngine;
using Oxide.Core;
using Oxide.Core.Plugins;
using Newtonsoft.Json;
namespace Oxide.Plugins {
[Info("HomeRecycler", "mabe", "0.0.2")]
[Description("Домашний переработчик с красивым сопровождением GUI.")]
public class HomeRecycler : RustPlugin {
#region Class [КЛАСС/КОНФИГ]
[PluginReference]
Plugin ImageLibrary;
Dictionary<uint, ulong> startedRecyclers = new Dictionary<uint, ulong>();
public Dictionary<int, KeyValuePair<string, int>> itemsNeededToCraft = new Dictionary<int, KeyValuePair<string, int>>();
public static HomeRecycler Instance;
private ItemBlueprint bp;
private class RecyclerEntity : MonoBehaviour {
private DestroyOnGroundMissing desGround;
private GroundWatch groundWatch;
public ulong OwnerID;
void Awake() {
OwnerID = GetComponent<BaseEntity>().OwnerID;
desGround = GetComponent<DestroyOnGroundMissing>();
if (!desGround) gameObject.AddComponent<DestroyOnGroundMissing>();
groundWatch = GetComponent<GroundWatch>();
if (!groundWatch) gameObject.AddComponent<GroundWatch>();
}
}
public class Craftss {
[JsonProperty("Shortname предмета для крафта")]
public string ShortName;
[JsonProperty("ShortId предмета")]
public int Shortid;
[JsonProperty("Кол-во для крафта")]
public int Amount;
}
private enum REC {
Rec
}
ConfigData config;
class ConfigData {
[JsonProperty("Включить/Выключить подбор переработчика")]
public bool Available = true;
[JsonProperty("Запрещать устанавливать переработчик в зоне действия чужого шкафа")]
public bool Privelege = true;
[JsonProperty("Можно ли устанавливать переработчик на структурах?")]
public bool Structure = true;
[JsonProperty("Можно ли устанавливать переработчик на землю?")]
public bool Ground = false;
[JsonProperty("Скорость переработчика")]
public float Speed = 5f;
[JsonProperty("Выпадение скрапа")]
public float RatioScrap = 1f;
[JsonProperty("Стак")]
public float percentOfMaxStackToTake = 0.4f;
[JsonProperty("Скорость работы переработчика")]
public float Ratio = 0.5f;
[JsonProperty("Привилегия на выдачу доступа к крафту")]
public string RecyclerPermission = "homerecycler.use";
[JsonProperty("Цвет кнопки ЗАКРЫТЬ")]
public string Close = "0.76 0.24 0.24 0.9";
[JsonProperty("Цвет кнопки СКРАФТИТЬ")]
public string Craft = "0.45 0.72 0.42 0.9";
[JsonProperty("Цвет кнопки ИНФОРМАЦИЯ")]
public string Infobutton = "0.6 0.4 1";
[JsonProperty("Заголовок в блоке информации")]
public string Infodop = "Информация о крафте";
[JsonProperty("Текст в блоке информации")]
public string RecInfo = "Чтобы скрафтить переработчик, нужно найти все необходимые компоненты и положить в инвентарь.\nЗайти в меню крафта и нажать на кнопку скрафтить.\nПосле этого он появится у вас в инвентаре.\nВажно знать, что его нельзя ставить на землю, только в доме.\n\n<color=#8653ed>DARKPLUGINS.RU</color>";
[JsonProperty(PropertyName = "Список предметов для замены скинов и имени")]
public Dictionary<REC, Dictionary<string, Craftss>> items;
public static ConfigData GetNewCong() {
return new ConfigData {
items = new Dictionary<REC, Dictionary<string, Craftss>> {
[REC.Rec]
= new Dictionary<string, Craftss> {
["1"]
= new Craftss {
ShortName = "hq.metal.ore", Amount = 100, Shortid = -1982036270
}
, ["2"] = new Craftss {
ShortName = "metal.fragments", Amount = 5000, Shortid = 69511070
}
, ["3"] = new Craftss {
ShortName = "metal.refined", Amount = 300, Shortid = 317398316
}
, ["4"] = new Craftss {
ShortName = "gears", Amount = 20, Shortid = 479143914
}
, ["5"] = new Craftss {
ShortName = "metalpipe", Amount = 20, Shortid = 95950017
}
, ["6"] = new Craftss {
ShortName = "techparts", Amount = 20, Shortid = 73681876
}
,
}
,
}
,
}
;
}
}
protected override void LoadConfig() {
base.LoadConfig();
try {
config = Config.ReadObject<ConfigData>();
if (config?.items == null) LoadDefaultConfig();
}
catch {
LoadDefaultConfig();
}
NextTick(SaveConfig);
}
protected override void LoadDefaultConfig() => config = ConfigData.GetNewCong();
protected override void SaveConfig() => Config.WriteObject(config);
#endregion
#region Permission [ПРИВИЛЕГИЯ]
private void Loaded() {
permission.RegisterPermission(config.RecyclerPermission, this);
}
#endregion
#region Var [СЛОИ]
[JsonProperty("Системный слой")]
private string Layer = "UI_RECYCLER";
private string LayerInfo = "UI_INFO";
#endregion
#region Oxide [ДОПОЛНЕНИЯ]
private void Init() {
Instance = this;
}
private void OnServerInitialized() {
ImageLibrary.Call("AddImage", "https://imgur.com/QEUXtZJ.png", "RecyclerImage");
var allobjects = UnityEngine.Object.FindObjectsOfType<Recycler>();
foreach (var r in allobjects) {
if (r.OwnerID != 0 && r.gameObject.GetComponent<RecyclerEntity>() == null) r.gameObject.AddComponent<RecyclerEntity>();
}
var ingredients = new List<ItemAmount>();
}
void Unload() {
var allobjects = UnityEngine.Object.FindObjectsOfType<RecyclerEntity>();
foreach (var r in allobjects) {
GameObject.Destroy(r);
}
foreach (BasePlayer player in BasePlayer.activePlayerList) {
CuiHelper.DestroyUi(player, Layer);
}
}
object CanStackItem(Item item, Item anotherItem) {
if (item.info.itemid == 833533164 && item.skin == 1321253094) return false;
return null;
}
#endregion
#region Command [КОМАНДЫ]
[ConsoleCommand("giverecycler")]
void cmdGiveRecycler(ConsoleSystem.Arg arg) {
var player = arg?.Player() ?? null;
if (player?.net.connection.authLevel < 2) return;
if (arg.Args == null || arg.Args.Length < 1) {
SendReply(arg, "giverecycler SteamID");
return;
}
BasePlayer targetPlayer = BasePlayer.Find(arg.Args[0]);
if (targetPlayer == null) {
SendReply(arg, "Игрок не найден");
return;
}
SendReply(arg, "Переработчик был выдан");
if (GiveRecycler(targetPlayer)) {
SendReply(targetPlayer, "Ты получил переработчик");
}
else {
SendReply(targetPlayer, "Нет места в инвентаре");
}
}
[ChatCommand("rec")]
void cmdCraft43(BasePlayer player, string command, string[] args) {
if (!permission.UserHasPermission(player.UserIDString, config.RecyclerPermission)) {
SendReply(player, "У тебя нету прав использовать эту команду!");
return;
}
RecyclerUI(player);
}
[ConsoleCommand("recyclerinfo")]
private void cmdRecyclerInfo(ConsoleSystem.Arg arg) {
var player = arg.Player();
RecyclerInfoUI(player);
}
[ConsoleCommand("recyclercraft")]
private void cmdCraftRecycler(ConsoleSystem.Arg arg) {
var player = arg.Player();
bool enough = true;
foreach (var ct in config.items.Select((i, t) => new {
A = i, B = t
}
)) {
foreach (var bt in ct.A.Value.Select((i, t) => new {
A = i, B = t
}
)) {
var haveCount = player.inventory.GetAmount(bt.A.Value.Shortid);
if (haveCount >= bt.A.Value.Amount) continue;
enough = false;
}
}
if (!enough) {
SendReply(player, "У вас не хватает ресурсов для крафта переработчика");
return;
}
foreach (var ct in config.items.Select((i, t) => new {
A = i, B = t
}
)) {
foreach (var bt in ct.A.Value.Select((i, t) => new {
A = i, B = t
}
)) {
player.inventory.Take(null, bt.A.Value.Shortid, bt.A.Value.Amount);
}
}
if (GiveRecycler(player)) {
SendReply(player, "Ты скрафтил переработчик");
}
else {
SendReply(player, "Нет места в инвентаре");
}
}
#endregion
#region GUI [ПАНЕЛЬ]
private void RecyclerUI(BasePlayer player) {
CuiElementContainer container = new CuiElementContainer();
CuiHelper.DestroyUi(player, Layer);
float gap = -0.008f;
float width = 0.30f;
float height = 0.51f;
float startxBox = 0.05f;
float startyBox = 0.999f - height;
float xmin = startxBox;
float ymin = startyBox;
int current = 6;
container.Add(new CuiPanel {
CursorEnabled = true, RectTransform = {
AnchorMin = "0.25 0.29", AnchorMax = "0.735 0.82"
}
, Image = {
Color = "1 1 1 0.17", Material = "assets/content/ui/uibackgroundblur.mat"
}
,
}
, "Hud", Layer);
container.Add(new CuiButton {
RectTransform = {
AnchorMin = "0 0.85", AnchorMax = "0.998 0.998"
}
, Button = {
Color = "0 0 0 0"
}
, Text = {
Text = "ДОМАШНИЙ ПЕРЕРАБОТЧИК", Align = TextAnchor.MiddleCenter, FontSize = 28, Font = "robotocondensed-bold.ttf", Color = "0.91 0.91 0.91 1"
}
}
, Layer);
container.Add(new CuiButton {
RectTransform = {
AnchorMin = "0.81 0.02", AnchorMax = "0.98 0.125"
}
, Button = {
Color = config.Close, Close = Layer
}
, Text = {
Text = "ЗАКРЫТЬ", Align = TextAnchor.MiddleCenter, FontSize = 18, Font = "robotocondensed-bold.ttf", Color = "0.91 0.91 0.91 1"
}
}
, Layer);
container.Add(new CuiButton {
RectTransform = {
AnchorMin = "0.61 0.02", AnchorMax = "0.795 0.125"
}
, Button = {
Color = config.Craft, Command = "recyclercraft", Close = Layer
}
, Text = {
Text = "СКРАФТИТЬ", Align = TextAnchor.MiddleCenter, FontSize = 16, Font = "robotocondensed-bold.ttf", Color = "0.91 0.91 0.91 1"
}
}
, Layer);
container.Add(new CuiButton {
RectTransform = {
AnchorMin = "0.40 0.02", AnchorMax = "0.595 0.125"
}
, Button = {
Color = config.Infobutton, Command = "recyclerinfo", Material = "assets/content/ui/uibackgroundblur.mat"
}
, Text = {
Text = "ИНФОРМАЦИЯ", Align = TextAnchor.MiddleCenter, FontSize = 16, Font = "robotocondensed-bold.ttf", Color = "0.91 0.91 0.91 1"
}
}
, Layer);
container.Add(new CuiButton {
RectTransform = {
AnchorMin = "0.672 0.225", AnchorMax = "0.737 0.799"
}
, Button = {
Color = "1 1 1 0.08"
}
, Text = {
Text = "=", Align = TextAnchor.MiddleCenter, FontSize = 50, Font = "robotocondensed-bold.ttf", Color = "0.91 0.91 0.91 1"
}
}
, Layer);
//Картинка переработчика
container.Add(new CuiButton {
RectTransform = {
AnchorMin = "0.77 0.375", AnchorMax = "0.982 0.642"
}
, Button = {
Color = "1 1 1 0.08"
}
, Text = {
Text = "", Align = TextAnchor.MiddleCenter, FontSize = 18, Font = "robotocondensed-bold.ttf"
}
}
, Layer, ".Images");
container.Add(new CuiElement {
Parent = ".Images", Components = {
new CuiRawImageComponent {
Png = (string) ImageLibrary.Call("GetImage", "RecyclerImage")
}
, new CuiRectTransformComponent {
AnchorMin = "0.05 0.05", AnchorMax = "0.95 0.95", OffsetMax = "0 0"
}
}
}
);
#endregion
#region Items Icons [ИКОНКИ НА ПРЕДМЕТЫ]
container.Add(new CuiButton {
RectTransform = {
AnchorMin = "0.01 0.235", AnchorMax = "0.68 0.822"
}
, Button = {
Color = "0 0 0 0"
}
, Text = {
Text = "", Align = TextAnchor.MiddleCenter, FontSize = 0, Font = "robotocondensed-bold.ttf"
}
}
, Layer, ".UI_RECYCLER");
foreach (var ct in config.items.Select((i, t) => new {
A = i, B = t
}
)) {
foreach (var bt in ct.A.Value.Select((i, t) => new {
A = i, B = t
}
)) {
container.Add(new CuiButton() {
Button = {
Command = "", Color = "1 1 1 0.08"
}
, RectTransform = {
AnchorMin = xmin + " " + ymin, AnchorMax = (xmin + width) + " " + (ymin + height *1), OffsetMax = "-7 -9", OffsetMin = "6 0",
}
, Text = {
Text = $"{bt.A.Value.Amount} ", Align = TextAnchor.LowerRight, FontSize = 14, Color = "0.91 0.91 0.91 1"
}
}
, ".UI_RECYCLER", $"ui.recycler.{bt.A.Value.ShortName}");
xmin += width + gap;
if (xmin + width >= 1) {
xmin = startxBox;
ymin -= height + gap;
}
container.Add(new CuiElement {
Parent = $"ui.recycler.{bt.A.Value.ShortName}", Components = {
new CuiRawImageComponent {
FadeIn = 0.5f, Png = (string)ImageLibrary?.CallHook("GetImage", bt.A.Value.ShortName)
}
, new CuiRectTransformComponent {
AnchorMin = "0.11 0.15", AnchorMax = "0.849 0.849"
}
}
}
);
current++;
if (current == 6) {
PrintWarning("Количество элементов превысило максимальную вместительность UI, отображено 8 позиций");
break;
}
}
}
CuiHelper.AddUi(player, container);
}
#endregion
#region Block of Information [ИНФОРМАЦИЯ]
private void RecyclerInfoUI(BasePlayer player) {
CuiElementContainer container = new CuiElementContainer();
CuiHelper.DestroyUi(player, LayerInfo);
container.Add(new CuiPanel {
CursorEnabled = true, RectTransform = {
AnchorMin = "0.25 0.29", AnchorMax = "0.735 0.82"
}
, Image = {
Color = "0 0 0 0.9", Material = "assets/content/ui/uibackgroundblur.mat"
}
,
}
, "Hud", LayerInfo);
container.Add(new CuiButton {
RectTransform = {
AnchorMin = "0 0.83", AnchorMax = "0.998 0.998"
}
, Button = {
Color = "0 0 0 0"
}
, Text = {
Text = config.Infodop, Align = TextAnchor.MiddleCenter, FontSize = 25, Font = "robotocondensed-bold.ttf", Color = "0.91 0.91 0.91 1"
}
}
, LayerInfo);
container.Add(new CuiButton {
RectTransform = {
AnchorMin = "0 0", AnchorMax = "0.998 0.825"
}
, Button = {
Color = "0 0 0 0"
}
, Text = {
Text = config.RecInfo, Align = TextAnchor.MiddleCenter, FontSize = 14, Font = "robotocondensed-regular.ttf", Color = "0.91 0.91 0.91 1"
}
}
, LayerInfo);
container.Add(new CuiButton {
RectTransform = {
AnchorMin = "-10 -10", AnchorMax = "10 10"
}
, Button = {
Color = "0 0 0 0", Close = LayerInfo
}
, Text = {
Text = ""
}
}
, LayerInfo);
CuiHelper.AddUi(player, container);
}
#endregion
#region Core [ДОПОЛНЕНИЕ]
bool GiveRecycler(ItemContainer container) {
var item = ItemManager.CreateByItemID(833533164, 1, 1321253094);
item.name = "Recycler";
return item.MoveToContainer(container, -1, false);
}
bool GiveRecycler(BasePlayer player) {
var item = ItemManager.CreateByItemID(833533164, 1, 1321253094);
item.name = "Recycler";
if (!player.inventory.GiveItem(item)) {
item.Drop(player.inventory.containerMain.dropPosition, player.inventory.containerMain.dropVelocity, new Quaternion());
return false;
}
return true;
}
bool Check(BaseEntity entity) {
GroundWatch component = entity.gameObject.GetComponent<GroundWatch>();
List<Collider> list = Facepunch.Pool.GetList<Collider>();
Vis.Colliders<Collider>(entity.transform.TransformPoint(component.groundPosition), component.radius, list, component.layers, QueryTriggerInteraction.Collide);
foreach (Collider collider in list) {
if (!(collider.transform.root == entity.gameObject.transform.root)) {
BaseEntity baseEntity = collider.gameObject.ToBaseEntity();
if ((!(bool)(baseEntity) || !baseEntity.IsDestroyed && !baseEntity.isClient) && baseEntity is BuildingBlock) {
Facepunch.Pool.FreeList<Collider>(ref list);
return true;
}
}
}
Facepunch.Pool.FreeList<Collider>(ref list);
return false;
}
void OnEntityBuilt(Planner plan, GameObject obj) {
var player = plan.GetOwnerPlayer();
var entity = obj.ToBaseEntity();
if (entity == null) return;
var ePos = entity.transform.position;
RaycastHit rHit;
if (entity != null && entity.ShortPrefabName == "box.wooden.large" && entity.skinID == 1321253094L) {
if (Physics.Raycast(new Vector3(ePos.x, ePos.y + 1, ePos.z), Vector3.down, out rHit, 2f, LayerMask.GetMask("Construction")) && rHit.GetEntity() != null) {
if (!config.Structure) {
SendReply(player, "Переработчики нельзя ставить на строения (фундамент, потолки и тд)");
GiveRecycler(player);
entity.Kill();
return;
}
}
else {
if (!config.Ground) {
GiveRecycler(player);
SendReply(player, "Нельзя ставить на землю");
entity.Kill();
return;
}
}
Recycler recycler = GameManager.server.CreateEntity("assets/bundled/prefabs/static/recycler_static.prefab", entity.transform.position, entity.transform.rotation) as Recycler;
recycler.Spawn();
entity.Kill();
recycler.gameObject.AddComponent<RecyclerEntity>();
}
}
private void OnHammerHit(BasePlayer player, HitInfo info) {
var entity = info.HitEntity;
if (entity == null) return;
if (!entity.ShortPrefabName.Contains("recycler")) return;
if (!config.Available) {
SendReply(player, "Подбор переработчика запрещен!");
return;
}
if (config.Privelege && !player.IsBuildingAuthed()) {
SendReply (player, "Вам нужно право на строительство чтобы подобрать переработчик");
return;
}
if (GiveRecycler(player)) {
SendReply(player, "Вы успешно подобрали переработчик!");
}
else {
SendReply(player, "У вас недостаточно места в инвентаре!");
}
info.HitEntity.Kill();
}
void OnRecyclerToggle(Recycler recycler, BasePlayer player) {
startedRecyclers[recycler.net.ID] = player.userID;
NextTick(() => {
if (config.Speed != 5f) {
recycler.CancelInvoke(new Action(recycler.RecycleThink));
recycler.InvokeRepeating(new Action(recycler.RecycleThink), config.Speed, config.Speed);
}
}
);
}
object OnRecycleItem(Recycler recycler, Item item) {
if (recycler.OwnerID == 0) return null;
if (item.info.Blueprint == null) {
return false;
}
bool flag = false;
float num = config.Ratio;
float percentToTake = config.percentOfMaxStackToTake;
if (item.hasCondition) {
num = Mathf.Clamp01(num * Mathf.Clamp(item.conditionNormalized * item.maxConditionNormalized, 0.1f, 1f));
}
int num2 = 1;
if (item.amount > 1) {
num2 = Mathf.CeilToInt(Mathf.Min((float)item.amount, (float)item.info.stackable * percentToTake));
}
if (item.info.Blueprint.scrapFromRecycle > 0) {
float ratioScrap = config.RatioScrap;
Item newItem = ItemManager.CreateByName("scrap", (int)(item.info.Blueprint.scrapFromRecycle * num2 * ratioScrap), 0uL);
recycler.MoveItemToOutput(newItem);
}
item.UseItem(num2);
foreach (ItemAmount ingredient in item.info.Blueprint.ingredients) {
if (!(ingredient.itemDef.shortname == "scrap")) {
float num3 = ingredient.amount / (float)item.info.Blueprint.amountToCreate;
int num4 = 0;
if (num3 <= 1f) {
for (int j = 0; j < num2; j++) {
if (UnityEngine.Random.Range(0f, 1f) <= num) {
num4++;
}
}
}
else {
num4 = Mathf.CeilToInt(Mathf.Clamp(num3 * num * UnityEngine.Random.Range(1f, 1f), 0f, ingredient.amount) * (float)num2);
}
if (num4 > 0) {
int num5 = Mathf.CeilToInt((float)num4 / (float)ingredient.itemDef.stackable);
for (int k = 0; k < num5; k++) {
int num6 = (num4 <= ingredient.itemDef.stackable) ? num4 : ingredient.itemDef.stackable;
Item newItem2 = ItemManager.Create(ingredient.itemDef, num6, 0uL);
if (!recycler.MoveItemToOutput(newItem2)) {
flag = true;
}
num4 -= num6;
if (num4 <= 0) {
break;
}
}
}
}
}
if (flag) recycler.StopRecycling();
return false;
}
#endregion
}
}