C#:
//#define TESTING
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using Facepunch;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Oxide.Core;
using Oxide.Core.Libraries;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using Oxide.Plugins.CraftsExtensionMethods;
using Rust;
using UnityEngine;
using Random = UnityEngine.Random;
namespace Oxide.Plugins
{
[Info("Crafts", "Mevent", "2.10.2")]
public class Crafts : RustPlugin
{
#region Fields
[PluginReference] private Plugin
ImageLibrary = null,
SpawnModularCar = null,
Notify = null,
UINotify = null,
LangAPI = null;
private static Crafts _instance;
private const string Layer = "UI.Crafts";
private const string EditLayer = "UI.Crafts.Edit";
private const string PermEdit = "crafts.edit";
private const string PermSetWb = "crafts.setworkbench";
private const string PermBypass = "crafts.bypass";
private List<CraftConf> _crafts = new List<CraftConf>();
private readonly List<RecyclerComponent> _recyclers = new List<RecyclerComponent>();
private readonly List<CarController> _cars = new List<CarController>();
private readonly List<BasePlayer> _openedUi = new List<BasePlayer>();
private readonly Dictionary<string, List<KeyValuePair<int, string>>> _itemsCategories =
new Dictionary<string, List<KeyValuePair<int, string>>>();
private readonly List<SafeZoneComponent> _safeZones = new List<SafeZoneComponent>();
private enum WorkbenchLevel
{
None = 0,
One = 1,
Two = 2,
Three = 3
}
private enum CraftType
{
Command,
Vehicle,
Item,
Recycler,
ModularCar
}
private readonly Dictionary<int, ItemForCraft> _itemsById = new Dictionary<int, ItemForCraft>();
private readonly Dictionary<int, CraftConf> _craftsById = new Dictionary<int, CraftConf>();
private readonly Dictionary<BasePlayer, Dictionary<string, object>> _craftEditing =
new Dictionary<BasePlayer, Dictionary<string, object>>();
private readonly Dictionary<BasePlayer, Dictionary<string, object>> _itemEditing =
new Dictionary<BasePlayer, Dictionary<string, object>>();
private readonly Dictionary<BasePlayer, CustomWorkbenchConf> _openedCustomWb =
new Dictionary<BasePlayer, CustomWorkbenchConf>();
#endregion
#region Config
private static Configuration _config;
private class Configuration
{
[JsonProperty(PropertyName = "Commands", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public readonly string[] Commands = {"craft", "crafts"};
[JsonProperty(PropertyName = "Close UI when reusing a command?")]
public readonly bool CloseReusing = false;
[JsonProperty(PropertyName = "Work with Notify?")]
public readonly bool UseNotify = true;
[JsonProperty(PropertyName = "Work with LangAPI?")]
public readonly bool UseLangAPI = true;
[JsonProperty(PropertyName = "Permission (ex: crafts.use)")]
public readonly string Permission = string.Empty;
[JsonProperty(PropertyName = "Economy")]
public readonly EconomyConf Economy = new EconomyConf
{
Show = false,
Type = EconomyConf.EconomyType.Plugin,
AddHook = "Deposit",
BalanceHook = "Balance",
RemoveHook = "Withdraw",
Plug = "Economics",
ShortName = "scrap",
DisplayName = string.Empty,
Skin = 0
};
[JsonProperty(PropertyName = "Categories", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public readonly List<Category> Categories = new List<Category>
{
new Category
{
Enabled = true,
Permission = string.Empty,
Title = "Vehicles",
Color = new IColor("#161617", 100),
Crafts = new List<CraftConf>
{
new CraftConf
{
Enabled = true,
Image = "https://i.imgur.com/YXjADeE.png",
Title = "Minicopter",
Description = "Fast air transport",
CmdToGive = "givecopter",
Permission = "crafts.all",
DisplayName = "Minicopter",
ShortName = "electric.flasherlight",
Amount = 1,
SkinID = 2080145158,
Type = CraftType.Vehicle,
Prefab = "assets/content/vehicles/minicopter/minicopter.entity.prefab",
Level = WorkbenchLevel.One,
UseDistance = true,
Distance = 1.5f,
GiveCommand = string.Empty,
Ground = true,
Structure = true,
Items = new List<ItemForCraft>
{
new ItemForCraft(string.Empty, "gears", 5, 0),
new ItemForCraft(string.Empty, "roadsigns", 5, 0),
new ItemForCraft(string.Empty, "metal.fragments", 2000, 0)
},
Modular = new ModularCarConf
{
CodeLock = true,
KeyLock = false,
EnginePartsTier = 2,
FreshWaterAmount = 0,
FuelAmount = 140,
Modules = new[]
{
"vehicle.1mod.engine",
"vehicle.1mod.cockpit.armored",
"vehicle.1mod.cockpit.armored"
}
},
Cooldown = 0,
MultipleCraft = false,
MaxAmount = 0,
Craft = true,
Sale = false,
Cost = 100
},
new CraftConf
{
Enabled = true,
Image = "https://i.imgur.com/dmWQOm6.png",
Description = "Slow water transport",
Title = "Row Boat",
CmdToGive = "giverowboat",
Permission = "crafts.all",
DisplayName = "Row Boat",
ShortName = "coffin.storage",
Amount = 1,
SkinID = 2080150023,
Type = CraftType.Vehicle,
Prefab = "assets/content/vehicles/boats/rowboat/rowboat.prefab",
Level = WorkbenchLevel.Two,
UseDistance = true,
Distance = 1.5f,
GiveCommand = string.Empty,
Ground = true,
Structure = true,
Items = new List<ItemForCraft>
{
new ItemForCraft(string.Empty, "gears", 5, 0),
new ItemForCraft(string.Empty, "roadsigns", 5, 0),
new ItemForCraft(string.Empty, "metal.fragments", 2000, 0)
},
Modular = new ModularCarConf
{
CodeLock = true,
KeyLock = false,
EnginePartsTier = 2,
FreshWaterAmount = 0,
FuelAmount = 140,
Modules = new[]
{
"vehicle.1mod.engine",
"vehicle.1mod.cockpit.armored",
"vehicle.1mod.cockpit.armored"
}
},
Cooldown = 0,
MultipleCraft = false,
MaxAmount = 0,
Craft = true,
Sale = false,
Cost = 100
},
new CraftConf
{
Enabled = true,
Image = "https://i.imgur.com/CgpVw2j.png",
Description = "Slow water transport",
Title = "RHIB",
CmdToGive = "giverhibboat",
Permission = "crafts.all",
DisplayName = "RHIB",
ShortName = "electric.sirenlight",
Amount = 1,
SkinID = 2080150770,
Type = CraftType.Vehicle,
GiveCommand = string.Empty,
Prefab = "assets/content/vehicles/boats/rhib/rhib.prefab",
Level = WorkbenchLevel.Three,
UseDistance = true,
Distance = 1.5f,
Ground = true,
Structure = true,
Items = new List<ItemForCraft>
{
new ItemForCraft(string.Empty, "gears", 5, 0),
new ItemForCraft(string.Empty, "roadsigns", 5, 0),
new ItemForCraft(string.Empty, "metal.fragments", 2000, 0)
},
Modular = new ModularCarConf
{
CodeLock = true,
KeyLock = false,
EnginePartsTier = 2,
FreshWaterAmount = 0,
FuelAmount = 140,
Modules = new[]
{
"vehicle.1mod.engine",
"vehicle.1mod.cockpit.armored",
"vehicle.1mod.cockpit.armored"
}
},
Cooldown = 0,
MultipleCraft = false,
MaxAmount = 0,
Craft = true,
Sale = false,
Cost = 100
},
new CraftConf
{
Enabled = true,
Image = "https://i.imgur.com/cp2Xx2A.png",
Title = "Hot Air Balloon",
Description = "Slow air transport",
CmdToGive = "givehotair",
Permission = "crafts.all",
DisplayName = "Hot Air Balloon",
ShortName = "box.repair.bench",
Amount = 1,
SkinID = 2080152635,
Type = CraftType.Vehicle,
GiveCommand = string.Empty,
Prefab = "assets/prefabs/deployable/hot air balloon/hotairballoon.prefab",
Level = WorkbenchLevel.Three,
UseDistance = true,
Distance = 1.5f,
Ground = true,
Structure = true,
Items = new List<ItemForCraft>
{
new ItemForCraft(string.Empty, "gears", 5, 0),
new ItemForCraft(string.Empty, "roadsigns", 5, 0),
new ItemForCraft(string.Empty, "metal.fragments", 2000, 0)
},
Modular = new ModularCarConf
{
CodeLock = true,
KeyLock = false,
EnginePartsTier = 2,
FreshWaterAmount = 0,
FuelAmount = 140,
Modules = new[]
{
"vehicle.1mod.engine",
"vehicle.1mod.cockpit.armored",
"vehicle.1mod.cockpit.armored"
}
},
Cooldown = 0,
MultipleCraft = false,
MaxAmount = 0,
Craft = true,
Sale = false,
Cost = 100
},
new CraftConf
{
Enabled = true,
Image = "https://i.imgur.com/7JZE0Lr.png",
Title = "Transport Helicopter",
Description = "Fast air transport",
CmdToGive = "givescrapheli",
Permission = "crafts.all",
DisplayName = "Transport Helicopter",
ShortName = "electric.flasherlight",
Amount = 1,
SkinID = 2080154394,
Type = CraftType.Vehicle,
GiveCommand = string.Empty,
Prefab = "assets/content/vehicles/scrap heli carrier/scraptransporthelicopter.prefab",
Level = WorkbenchLevel.Three,
UseDistance = true,
Distance = 1.5f,
Ground = true,
Structure = true,
Items = new List<ItemForCraft>
{
new ItemForCraft(string.Empty, "gears", 5, 0),
new ItemForCraft(string.Empty, "roadsigns", 5, 0),
new ItemForCraft(string.Empty, "metal.fragments", 2000, 0)
},
Modular = new ModularCarConf
{
CodeLock = true,
KeyLock = false,
EnginePartsTier = 2,
FreshWaterAmount = 0,
FuelAmount = 140,
Modules = new[]
{
"vehicle.1mod.engine",
"vehicle.1mod.cockpit.armored",
"vehicle.1mod.cockpit.armored"
}
},
Cooldown = 0,
MultipleCraft = false,
MaxAmount = 0,
Craft = true,
Sale = false,
Cost = 100
},
new CraftConf
{
Enabled = true,
Image = "https://i.imgur.com/xj0N3lI.png",
Title = "Snowmobile",
Description = "Conquers snow biomes",
CmdToGive = "givesnowmobile",
Permission = "crafts.all",
DisplayName = "Snowmobile",
ShortName = "electric.flasherlight",
Amount = 1,
SkinID = 2747934628,
Type = CraftType.Vehicle,
GiveCommand = string.Empty,
Prefab = "assets/content/vehicles/snowmobiles/snowmobile.prefab",
Level = WorkbenchLevel.Two,
UseDistance = true,
Distance = 1.5f,
Ground = true,
Structure = false,
Items = new List<ItemForCraft>
{
new ItemForCraft(string.Empty, "gears", 5, 0),
new ItemForCraft(string.Empty, "roadsigns", 5, 0),
new ItemForCraft(string.Empty, "metal.fragments", 2000, 0)
},
Modular = new ModularCarConf
{
CodeLock = true,
KeyLock = false,
EnginePartsTier = 2,
FreshWaterAmount = 0,
FuelAmount = 140,
Modules = new[]
{
"vehicle.1mod.engine",
"vehicle.1mod.cockpit.armored",
"vehicle.1mod.cockpit.armored"
}
},
Cooldown = 0,
MultipleCraft = false,
MaxAmount = 0,
Craft = true,
Sale = false,
Cost = 100
}
}
},
new Category
{
Enabled = true,
Permission = string.Empty,
Title = "Cars",
Color = new IColor("#161617", 100),
Crafts = new List<CraftConf>
{
new CraftConf
{
Enabled = true,
Image = "https://i.imgur.com/eioxlvK.png",
Title = "Sedan",
Description = "5KM/H",
CmdToGive = "givesedan",
Permission = "crafts.all",
DisplayName = "Car",
ShortName = "woodcross",
Amount = 1,
SkinID = 2080151780,
Type = CraftType.Vehicle,
GiveCommand = string.Empty,
Prefab = "assets/content/vehicles/sedan_a/sedantest.entity.prefab",
Level = WorkbenchLevel.Two,
UseDistance = true,
Distance = 1.5f,
Ground = true,
Structure = true,
Items = new List<ItemForCraft>
{
new ItemForCraft(string.Empty, "gears", 5, 0),
new ItemForCraft(string.Empty, "roadsigns", 5, 0),
new ItemForCraft(string.Empty, "metal.fragments", 2000, 0)
},
Modular = new ModularCarConf
{
CodeLock = true,
KeyLock = false,
EnginePartsTier = 2,
FreshWaterAmount = 0,
FuelAmount = 140,
Modules = new[]
{
"vehicle.1mod.engine",
"vehicle.1mod.cockpit.armored",
"vehicle.1mod.cockpit.armored"
}
},
Cooldown = 0,
MultipleCraft = false,
MaxAmount = 0,
Craft = true,
Sale = false,
Cost = 100
},
new CraftConf
{
Enabled = true,
Image = "https://i.imgur.com/z7X5D5V.png",
Title = "Ferrari",
Description = "25KM/H",
CmdToGive = "givemod1",
Permission = "crafts.all",
DisplayName = "Car",
ShortName = "electric.flasherlight",
Amount = 1,
SkinID = 2244308598,
Type = CraftType.ModularCar,
Prefab = string.Empty,
GiveCommand = string.Empty,
Level = WorkbenchLevel.Two,
UseDistance = true,
Distance = 1.5f,
Ground = true,
Structure = true,
Items = new List<ItemForCraft>
{
new ItemForCraft(string.Empty, "gears", 5, 0),
new ItemForCraft(string.Empty, "roadsigns", 5, 0),
new ItemForCraft(string.Empty, "metal.fragments", 2000, 0)
},
Modular = new ModularCarConf
{
CodeLock = true,
KeyLock = false,
EnginePartsTier = 2,
FreshWaterAmount = 0,
FuelAmount = 140,
Modules = new[]
{
"vehicle.1mod.engine",
"vehicle.1mod.cockpit.armored",
"vehicle.1mod.cockpit.armored"
}
},
Cooldown = 0,
MultipleCraft = false,
MaxAmount = 0,
Craft = true,
Sale = false,
Cost = 100
}
}
},
new Category
{
Enabled = true,
Permission = string.Empty,
Title = "Misc",
Color = new IColor("#161617", 100),
Crafts = new List<CraftConf>
{
new CraftConf
{
Enabled = true,
Image = "https://i.imgur.com/LLB2AVi.png",
Title = "Home Recycler",
Description = string.Empty,
CmdToGive = "giverecycler",
Permission = "crafts.all",
DisplayName = "Home Recycler",
ShortName = "research.table",
Amount = 1,
SkinID = 2186833264,
Type = CraftType.Recycler,
Prefab = "assets/bundled/prefabs/static/recycler_static.prefab",
GiveCommand = string.Empty,
Level = WorkbenchLevel.Two,
UseDistance = true,
Distance = 1.5f,
Ground = true,
Structure = true,
Items = new List<ItemForCraft>
{
new ItemForCraft(string.Empty, "gears", 5, 0),
new ItemForCraft(string.Empty, "roadsigns", 5, 0),
new ItemForCraft(string.Empty, "metal.fragments", 2000, 0)
},
Modular = new ModularCarConf
{
CodeLock = true,
KeyLock = false,
EnginePartsTier = 2,
FreshWaterAmount = 0,
FuelAmount = 140,
Modules = new[]
{
"vehicle.1mod.engine",
"vehicle.1mod.cockpit.armored",
"vehicle.1mod.cockpit.armored"
}
},
Cooldown = 0,
MultipleCraft = false,
MaxAmount = 0,
Craft = true,
Sale = false,
Cost = 100
},
new CraftConf
{
Enabled = true,
Image = "https://i.imgur.com/mw1T17x.png",
Title = string.Empty,
Description = string.Empty,
CmdToGive = "givelr300",
Permission = "crafts.all",
DisplayName = string.Empty,
ShortName = "rifle.lr300",
Amount = 1,
SkinID = 0,
Type = CraftType.Item,
Prefab = string.Empty,
GiveCommand = string.Empty,
Level = WorkbenchLevel.None,
UseDistance = true,
Distance = 1.5f,
Ground = true,
Structure = true,
Items = new List<ItemForCraft>
{
new ItemForCraft(string.Empty, "gears", 5, 0),
new ItemForCraft(string.Empty, "roadsigns", 5, 0),
new ItemForCraft(string.Empty, "metal.fragments", 2000, 0)
},
Modular = new ModularCarConf
{
CodeLock = true,
KeyLock = false,
EnginePartsTier = 2,
FreshWaterAmount = 0,
FuelAmount = 140,
Modules = new[]
{
"vehicle.1mod.engine",
"vehicle.1mod.cockpit.armored",
"vehicle.1mod.cockpit.armored"
}
},
Cooldown = 0,
MultipleCraft = false,
MaxAmount = 0,
Craft = true,
Sale = false,
Cost = 100
}
}
}
};
[JsonProperty(PropertyName = "Workbenches Setting",
ObjectCreationHandling = ObjectCreationHandling.Replace)]
public readonly Dictionary<WorkbenchLevel, IColor> Workbenches =
new Dictionary<WorkbenchLevel, IColor>
{
[WorkbenchLevel.None] = new IColor("#FFFFFF", 00),
[WorkbenchLevel.One] = new IColor("#74884A", 100),
[WorkbenchLevel.Two] = new IColor("#B19F56", 100),
[WorkbenchLevel.Three] = new IColor("#B43D3D", 100)
};
[JsonProperty(PropertyName = "Recycler Settings")]
public readonly RecyclerConfig Recycler = new RecyclerConfig
{
Speed = 5f,
Radius = 7.5f,
Text = "<size=19>RECYCLER</size>\n<size=15>{0}/{1}</size>",
Color = "#C5D0E6",
Delay = 0.75f,
Available = true,
Owner = true,
Amounts = new[]
{0.9f, 0, 0, 0, 0, 0.5f, 0, 0, 0, 0.9f, 0.5f, 0.5f, 0, 1, 1, 0.5f, 0, 0, 0, 0, 0, 1, 1},
Scale = 0.5f,
DDraw = true,
Building = true,
Destroy = new RecyclerDestroy
{
CheckGround = true,
Item = true,
Effects = new List<string>
{
"assets/bundled/prefabs/fx/item_break.prefab",
"assets/bundled/prefabs/fx/impacts/stab/rock/stab_rock_01.prefab"
}
}
};
[JsonProperty(PropertyName = "Car Settings")]
public readonly CarConfig Car = new CarConfig
{
ActiveItems = new ActiveItemOptions
{
Disable = true,
BlackList = new[]
{
"explosive.timed", "rocket.launcher", "surveycharge", "explosive.satchel"
}
},
Radius = 7.5f,
Text = "<size=15>{0}/{1}</size>",
Color = "#C5D0E6",
Delay = 0.75f
};
[JsonProperty(PropertyName = "Custom Workbench Stations (Entity ID - settings)",
ObjectCreationHandling = ObjectCreationHandling.Replace)]
public readonly Dictionary<uint, CustomWorkbenchConf> CustomWorkbench =
new Dictionary<uint, CustomWorkbenchConf>
{
[123343941] = new CustomWorkbenchConf
{
Categories = new List<string>
{
"Cars", "Misc"
},
SafeZone = true,
SafeZoneRadius = 5,
WorkBench = new Dictionary<string, int>
{
["crafts.default"] = 0,
["crafts.premium"] = 3
}
}
};
[JsonProperty(PropertyName = "UI Settings")]
public readonly UserInterface UI = new UserInterface
{
CatWidth = 90,
CatMargin = 5,
CatHeight = 25,
CraftWidth = 125,
CraftHeight = 125,
CraftMargin = 10,
CraftYIndent = -115,
CraftStrings = 2,
CraftAmountOnString = 5,
CategoriesAmountOnPage = 7,
PageSize = 25,
PageSelectedSize = 40,
PagesMargin = 5,
ItemMargin = 40,
ItemWidth = 130,
Color1 = new IColor("#0E0E10", 100),
Color2 = new IColor("#161617", 100),
Color3 = new IColor("#FFFFFF", 100),
Color4 = new IColor("#4B68FF", 100),
Color5 = new IColor("#74884A", 100),
Color6 = new IColor("#CD4632", 100),
Color7 = new IColor("#595651", 100),
Color8 = new IColor("#4B68FF", 70),
Color9 = new IColor("#0E0E10", 98),
Color10 = new IColor("#4B68FF", 50),
Color11 = new IColor("#FF4B4B", 100),
BackgroundImage = string.Empty,
CloseAfterCraft = true
};
public VersionNumber Version;
}
private class EconomyConf
{
public enum EconomyType
{
Plugin,
Item
}
[JsonProperty(PropertyName = "Show Balance")]
public bool Show;
[JsonProperty(PropertyName = "Type (Plugin/Item)")] [JsonConverter(typeof(StringEnumConverter))]
public EconomyType Type;
[JsonProperty(PropertyName = "Plugin name")]
public string Plug;
[JsonProperty(PropertyName = "Balance add hook")]
public string AddHook;
[JsonProperty(PropertyName = "Balance remove hook")]
public string RemoveHook;
[JsonProperty(PropertyName = "Balance show hook")]
public string BalanceHook;
[JsonProperty(PropertyName = "ShortName")]
public string ShortName;
[JsonProperty(PropertyName = "Display Name (empty - default)")]
public string DisplayName;
[JsonProperty(PropertyName = "Skin")] public ulong Skin;
public double ShowBalance(BasePlayer player)
{
switch (Type)
{
case EconomyType.Plugin:
{
var plugin = _instance?.plugins?.Find(Plug);
if (plugin == null) return 0;
return Math.Round(Convert.ToDouble(plugin.Call(BalanceHook, player.userID)), 2);
}
case EconomyType.Item:
{
return ItemCount(player.inventory.AllItems(), ShortName, Skin);
}
default:
return 0;
}
}
public void AddBalance(BasePlayer player, double amount)
{
switch (Type)
{
case EconomyType.Plugin:
{
var plugin = _instance?.plugins?.Find(Plug);
if (plugin == null) return;
switch (Plug)
{
case "BankSystem":
case "ServerRewards":
plugin.Call(AddHook, player.userID, (int) amount);
break;
default:
plugin.Call(AddHook, player.userID, amount);
break;
}
break;
}
case EconomyType.Item:
{
var am = (int) amount;
var item = ToItem(am);
if (item == null) return;
player.GiveItem(item);
break;
}
}
}
public bool RemoveBalance(BasePlayer player, double amount)
{
switch (Type)
{
case EconomyType.Plugin:
{
if (ShowBalance(player) < amount) return false;
var plugin = _instance?.plugins.Find(Plug);
if (plugin == null) return false;
switch (Plug)
{
case "BankSystem":
case "ServerRewards":
plugin.Call(RemoveHook, player.userID, (int) amount);
break;
default:
plugin.Call(RemoveHook, player.userID, amount);
break;
}
return true;
}
case EconomyType.Item:
{
var playerItems = player.inventory.AllItems();
var am = (int) amount;
if (ItemCount(playerItems, ShortName, Skin) < am) return false;
Take(playerItems, ShortName, Skin, am);
return true;
}
default:
return false;
}
}
public bool Transfer(BasePlayer player, BasePlayer targetPlayer, double amount)
{
if (!RemoveBalance(player, amount))
return false;
AddBalance(targetPlayer, amount);
return true;
}
private Item ToItem(int amount)
{
var item = ItemManager.CreateByName(ShortName, amount, Skin);
if (item == null)
{
Debug.LogError($"Error creating item with ShortName: '{ShortName}'");
return null;
}
if (!string.IsNullOrEmpty(DisplayName)) item.name = DisplayName;
return item;
}
}
private class CustomWorkbenchConf
{
[JsonProperty(PropertyName = "Categories (Titles) [* - all]",
ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<string> Categories;
[JsonProperty(PropertyName = "Use safe zone")]
public bool SafeZone;
[JsonProperty(PropertyName = "Safe Zone Radius")]
public float SafeZoneRadius;
[JsonProperty(PropertyName = "WorkBench Level", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, int> WorkBench = new Dictionary<string, int>
{
["crafts.default"] = 0,
["crafts.premium"] = 0
};
public WorkbenchLevel GetWorkBenchLevel(BasePlayer player)
{
var result = 0;
foreach (var check in WorkBench)
if (!string.IsNullOrEmpty(check.Key) &&
_instance.permission.UserHasPermission(
player.UserIDString, check.Key)
&& check.Value > result)
result = check.Value;
return (WorkbenchLevel) result;
}
}
private class UserInterface
{
[JsonProperty(PropertyName = "Category Width")]
public float CatWidth;
[JsonProperty(PropertyName = "Category Height")]
public float CatHeight;
[JsonProperty(PropertyName = "Category Margin")]
public float CatMargin;
[JsonProperty(PropertyName = "Craft Width")]
public float CraftWidth;
[JsonProperty(PropertyName = "Craft Height")]
public float CraftHeight;
[JsonProperty(PropertyName = "Craft Margin")]
public float CraftMargin;
[JsonProperty(PropertyName = "Craft Y Indent")]
public float CraftYIndent;
[JsonProperty(PropertyName = "Craft Amount On String")]
public int CraftAmountOnString;
[JsonProperty(PropertyName = "Categories Amount On Page")]
public int CategoriesAmountOnPage;
[JsonProperty(PropertyName = "Craft Strings")]
public int CraftStrings;
[JsonProperty(PropertyName = "Page Size")]
public float PageSize;
[JsonProperty(PropertyName = "Page Selected Size")]
public float PageSelectedSize;
[JsonProperty(PropertyName = "Pages Margin")]
public float PagesMargin;
[JsonProperty(PropertyName = "Item Width")]
public float ItemWidth;
[JsonProperty(PropertyName = "Item Margin")]
public float ItemMargin;
[JsonProperty(PropertyName = "Color 1")]
public IColor Color1;
[JsonProperty(PropertyName = "Color 2")]
public IColor Color2;
[JsonProperty(PropertyName = "Color 3")]
public IColor Color3;
[JsonProperty(PropertyName = "Color 4")]
public IColor Color4;
[JsonProperty(PropertyName = "Color 5")]
public IColor Color5;
[JsonProperty(PropertyName = "Color 6")]
public IColor Color6;
[JsonProperty(PropertyName = "Color 7")]
public IColor Color7;
[JsonProperty(PropertyName = "Color 8")]
public IColor Color8;
[JsonProperty(PropertyName = "Color 9")]
public IColor Color9;
[JsonProperty(PropertyName = "Color 10")]
public IColor Color10;
[JsonProperty(PropertyName = "Color 11")]
public IColor Color11;
[JsonProperty(PropertyName = "Background Image")]
public string BackgroundImage;
[JsonProperty(PropertyName = "Close after craft?")]
public bool CloseAfterCraft;
}
private class Category
{
[JsonProperty(PropertyName = "Enabled")]
public bool Enabled;
[JsonProperty(PropertyName = "Permission (ex: crafts.vip)")]
public string Permission;
[JsonProperty(PropertyName = "Title")] public string Title;
[JsonProperty(PropertyName = "Background color")]
public IColor Color;
[JsonProperty(PropertyName = "Items", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<CraftConf> Crafts;
}
private class CraftConf
{
[JsonProperty(PropertyName = "ID")] public int ID;
[JsonProperty(PropertyName = "Enabled")]
public bool Enabled;
[JsonProperty(PropertyName = "Image")] public string Image;
[JsonProperty(PropertyName = "Title")] public string Title;
[JsonProperty(PropertyName = "Description")]
public string Description;
[JsonProperty(PropertyName = "Command (to give an item)")]
public string CmdToGive;
[JsonProperty(PropertyName = "Permission (ex: crafts.vip)")]
public string Permission;
[JsonProperty(PropertyName = "Display Name")]
public string DisplayName;
[JsonProperty(PropertyName = "ShortName")]
public string ShortName;
[JsonProperty(PropertyName = "Amount")]
public int Amount;
[JsonProperty(PropertyName = "Skin")] public ulong SkinID;
[JsonProperty(PropertyName = "Type (Item/Command/Vehicle/Recycler)")]
[JsonConverter(typeof(StringEnumConverter))]
public CraftType Type;
[JsonProperty(PropertyName = "Prefab")]
public string Prefab;
[JsonProperty(PropertyName = "Command on give")]
public string GiveCommand;
[JsonProperty(PropertyName = "Workbench Level")]
public WorkbenchLevel Level;
[JsonProperty(PropertyName = "Distance Check")]
public bool UseDistance;
[JsonProperty(PropertyName = "Distance")]
public float Distance;
[JsonProperty(PropertyName = "Place the ground")]
public bool Ground;
[JsonProperty(PropertyName = "Place the structure")]
public bool Structure;
[JsonProperty(PropertyName = "Items For Craft",
ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<ItemForCraft> Items;
[JsonProperty(PropertyName = "For Modular Car")]
public ModularCarConf Modular;
[JsonProperty(PropertyName = "Cooldown")]
public float Cooldown;
[JsonProperty(PropertyName = "Multiple Craft")]
public bool MultipleCraft;
[JsonProperty(PropertyName = "Maximum number of crafts")]
public int MaxAmount;
[JsonProperty(PropertyName = "Enable Craft?")]
public bool Craft;
[JsonProperty(PropertyName = "Enable Sales?")]
public bool Sale;
[JsonProperty(PropertyName = "Cost")] public float Cost;
[JsonIgnore] private int _itemId = -1;
[JsonIgnore]
public int itemId
{
get
{
if (_itemId == -1)
_itemId = ItemManager.FindItemDefinition(ShortName)?.itemid ?? -1;
return _itemId;
}
}
[JsonIgnore]
public int PUBLIC_ID
{
get
{
while (ID == 0)
{
var val = Random.Range(int.MinValue, int.MaxValue);
if (_instance._craftsById.ContainsKey(val)) continue;
ID = val;
}
return ID;
}
}
[JsonIgnore] private string _publicTitle;
[JsonIgnore]
public string PublicTitle
{
get
{
if (string.IsNullOrEmpty(_publicTitle))
_publicTitle = GetName();
return _publicTitle;
}
}
private string GetName()
{
if (!string.IsNullOrEmpty(Title))
return Title;
if (!string.IsNullOrEmpty(DisplayName))
return DisplayName;
var def = ItemManager.FindItemDefinition(ShortName);
if (!string.IsNullOrEmpty(ShortName) && def != null)
return def.displayName.translated;
return string.Empty;
}
public Item ToItem()
{
var newItem = ItemManager.CreateByName(ShortName, Amount, SkinID);
if (newItem == null)
{
Debug.LogError($"Error creating item with ShortName: '{ShortName}'");
return null;
}
if (!string.IsNullOrEmpty(DisplayName)) newItem.name = DisplayName;
return newItem;
}
public void Give(BasePlayer player)
{
if (player == null) return;
var item = ToItem();
if (item == null) return;
player.GiveItem(item, BaseEntity.GiveItemReason.PickedUp);
}
public void Spawn(BasePlayer player, Vector3 pos, Quaternion rot)
{
switch (Type)
{
case CraftType.ModularCar:
{
_instance?.SpawnModularCar?.Call("API_SpawnPresetCar", player, Modular.Get());
break;
}
case CraftType.Vehicle:
{
var entity = GameManager.server.CreateEntity(Prefab, pos,
Quaternion.Euler(0, player.GetNetworkRotation().eulerAngles.y - 90, 0));
if (entity == null) return;
entity.skinID = SkinID;
entity.OwnerID = player.userID;
entity.Spawn();
break;
}
default:
{
var entity = GameManager.server.CreateEntity(Prefab, pos, rot);
if (entity == null) return;
entity.skinID = SkinID;
entity.OwnerID = player.userID;
entity.Spawn();
break;
}
}
}
public Dictionary<string, object> ToDictionary()
{
return new Dictionary<string, object>
{
["Generated"] = false,
["Enabled"] = Enabled,
["Image"] = Image,
["Title"] = Title,
["Description"] = Description,
["CmdToGive"] = CmdToGive,
["Permission"] = Permission,
["DisplayName"] = DisplayName,
["ShortName"] = ShortName,
["Amount"] = Amount,
["SkinID"] = SkinID,
["Type"] = Type,
["Prefab"] = Prefab,
["GiveCommand"] = GiveCommand,
["Level"] = Level,
["UseDistance"] = UseDistance,
["Distance"] = Distance,
["Ground"] = Ground,
["Structure"] = Structure,
["Items"] = Items,
["Craft"] = Craft,
["Sales"] = Sale,
["Cost"] = Cost
};
}
public void UpdateCooldown(BasePlayer player)
{
PlayerCooldown.GetOrAdd(player.userID)?.Add(this);
}
public bool HasCooldown(BasePlayer player, out int timeLeft)
{
timeLeft = 0;
if (Cooldown <= 0)
return false;
var data = PlayerCooldown.GetOrAdd(player.userID);
if (data == null) return false;
timeLeft = data.GetCooldown(this);
return timeLeft > 0;
}
}
private class IColor
{
[JsonProperty(PropertyName = "HEX")] public string Hex;
[JsonProperty(PropertyName = "Opacity (0 - 100)")]
public readonly float Alpha;
public string Get()
{
if (string.IsNullOrEmpty(Hex)) Hex = "#FFFFFF";
var str = Hex.Trim('#');
if (str.Length != 6) throw new Exception(Hex);
var r = byte.Parse(str.Substring(0, 2), NumberStyles.HexNumber);
var g = byte.Parse(str.Substring(2, 2), NumberStyles.HexNumber);
var b = byte.Parse(str.Substring(4, 2), NumberStyles.HexNumber);
return $"{(double) r / 255} {(double) g / 255} {(double) b / 255} {Alpha / 100}";
}
public IColor(string hex, float alpha)
{
Hex = hex;
Alpha = alpha;
}
}
private class ItemForCraft
{
[JsonProperty(PropertyName = "Image")] public string Image;
[JsonProperty(PropertyName = "ShortName")]
public string ShortName;
[JsonProperty(PropertyName = "Amount")]
public int Amount;
[JsonProperty(PropertyName = "Skin")] public ulong SkinID;
[JsonProperty(PropertyName = "Title (empty - default)")]
public string Title = string.Empty;
[JsonIgnore] private int _itemId = -1;
[JsonIgnore]
public int itemId
{
get
{
if (_itemId == -1)
_itemId = ItemManager.FindItemDefinition(ShortName)?.itemid ?? -1;
return _itemId;
}
}
[JsonIgnore] private string _publicTitle;
[JsonIgnore]
public string PublicTitle
{
get
{
if (string.IsNullOrEmpty(_publicTitle))
{
if (string.IsNullOrEmpty(Title))
_publicTitle = ItemManager.FindItemDefinition(ShortName)?.displayName.translated ??
"UNKNOWN";
else
_publicTitle = Title;
}
return _publicTitle;
}
}
[JsonIgnore] private int _id = -1;
[JsonIgnore]
public int ID
{
get
{
while (_id == -1)
{
var val = Random.Range(int.MinValue, int.MaxValue);
if (_instance._itemsById.ContainsKey(val)) continue;
_id = val;
}
return _id;
}
}
public Dictionary<string, object> ToDictionary()
{
return new Dictionary<string, object>
{
["Generated"] = false,
["ID"] = ID,
["Image"] = Image,
["ShortName"] = ShortName,
["Amount"] = Amount,
["SkinID"] = SkinID,
["Title"] = Title
};
}
public string GetItemDisplayName(BasePlayer player)
{
return _config.UseLangAPI && _instance.LangAPI != null &&
_instance.LangAPI.Call<bool>("IsDefaultDisplayName", PublicTitle)
? _instance.LangAPI.Call<string>("GetItemDisplayName", ShortName, PublicTitle,
player.UserIDString) ?? PublicTitle
: PublicTitle;
}
#region Constructor
public ItemForCraft()
{
}
public ItemForCraft(string image, string shortname, int amount, ulong skin)
{
Image = image;
ShortName = shortname;
Amount = amount;
SkinID = skin;
}
#endregion
}
private class ModularCarConf
{
[JsonProperty(PropertyName = "CodeLock")]
public bool CodeLock;
[JsonProperty(PropertyName = "KeyLock")]
public bool KeyLock;
[JsonProperty(PropertyName = "Engine Parts Tier")]
public int EnginePartsTier;
[JsonProperty(PropertyName = "Fresh Water Amount")]
public int FreshWaterAmount;
[JsonProperty(PropertyName = "Fuel Amount")]
public int FuelAmount;
[JsonProperty(PropertyName = "Modules", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public string[] Modules;
public Dictionary<string, object> Get()
{
return new Dictionary<string, object>
{
["CodeLock"] = CodeLock,
["KeyLock"] = KeyLock,
["EnginePartsTier"] = EnginePartsTier,
["FreshWaterAmount"] = FreshWaterAmount,
["FuelAmount"] = FuelAmount,
["Modules"] = Modules
};
}
}
private class CarConfig
{
[JsonProperty(PropertyName = "Active Items (in hand)")]
public ActiveItemOptions ActiveItems;
[JsonProperty(PropertyName = "DDraw Radius")]
public float Radius;
[JsonProperty(PropertyName = "DDraw Text")]
public string Text;
[JsonProperty(PropertyName = "DDraw Color")]
public string Color;
[JsonProperty(PropertyName = "DDraw Delay (sec)")]
public float Delay;
}
public class ActiveItemOptions
{
[JsonProperty(PropertyName = "Forbid to hold all items")]
public bool Disable;
[JsonProperty(PropertyName = "List of blocked items (shortname)",
ObjectCreationHandling = ObjectCreationHandling.Replace)]
public string[] BlackList;
}
private class RecyclerConfig
{
[JsonProperty(PropertyName = "Recycling speed")]
public float Speed;
[JsonProperty(PropertyName = "Use DDraw? (showing damage on the recycler)")]
public bool DDraw;
[JsonProperty(PropertyName = "DDraw Radius")]
public float Radius;
[JsonProperty(PropertyName = "DDraw Text")]
public string Text;
[JsonProperty(PropertyName = "DDraw Color")]
public string Color;
[JsonProperty(PropertyName = "DDraw Delay (sec)")]
public float Delay;
[JsonProperty(PropertyName = "Enabled pickup?")]
public bool Available;
[JsonProperty(PropertyName = "Only owner can pickup")]
public bool Owner;
[JsonProperty(PropertyName = "Check ability to build for pickup")]
public bool Building;
[JsonProperty(PropertyName = "BaseProtection Settings",
ObjectCreationHandling = ObjectCreationHandling.Replace)]
public float[] Amounts;
[JsonProperty(PropertyName = "Damage Scale")]
public float Scale;
[JsonProperty(PropertyName = "Destroy Settings")]
public RecyclerDestroy Destroy;
[JsonIgnore] private CraftConf _craft;
[JsonIgnore]
public Item GetItem
{
get
{
if (_craft == null)
_craft = _instance._crafts.Find(x => x.Type == CraftType.Recycler);
return _craft?.ToItem();
}
}
}
private class RecyclerDestroy
{
[JsonProperty(PropertyName = "Check ground for recyclers? (destroy on missng)")]
public bool CheckGround;
[JsonProperty(PropertyName = "Give item on destroy?")]
public bool Item;
[JsonProperty(PropertyName = "Effects on destroy", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<string> Effects;
}
protected override void LoadConfig()
{
base.LoadConfig();
try
{
_config = Config.ReadObject<Configuration>();
if (_config == null) throw new Exception();
if (_config.Version < Version)
UpdateConfigValues();
SaveConfig();
}
catch
{
PrintError("Your configuration file contains an error.Using default configuration values.");
LoadDefaultConfig();
}
}
protected override void SaveConfig()
{
Config.WriteObject(_config);
}
protected override void LoadDefaultConfig()
{
_config = new Configuration();
}
private void UpdateConfigValues()
{
PrintWarning("Config update detected! Updating config values...");
if (_config.Version < new VersionNumber(2, 4, 0))
_config.Categories.ForEach(cat => { cat.Color = new IColor("#161617", 100); });
_config.Version = Version;
PrintWarning("Config update completed!");
}
#endregion
#region Data
private PlayerCooldown _cooldown;
private void LoadCooldown()
{
try
{
_cooldown = Interface.Oxide.DataFileSystem.ReadObject<PlayerCooldown>($"{Name}/Cooldowns");
}
catch (Exception e)
{
PrintError(e.ToString());
}
if (_cooldown == null) _cooldown = new PlayerCooldown();
}
private void SaveCooldown()
{
Interface.Oxide.DataFileSystem.WriteObject($"{Name}/Cooldowns", _cooldown);
}
private class PlayerCooldown
{
[JsonProperty(PropertyName = "Players", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public readonly Dictionary<ulong, PlayerCooldownData> Players = new Dictionary<ulong, PlayerCooldownData>();
public static PlayerCooldownData GetOrAdd(ulong member)
{
if (!_instance._cooldown.Players.ContainsKey(member))
_instance._cooldown.Players.Add(member, new PlayerCooldownData());
return _instance._cooldown.Players[member];
}
}
private class PlayerCooldownData
{
[JsonProperty(PropertyName = "LastTime", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<int, DateTime> LastTime = new Dictionary<int, DateTime>();
public void Add(CraftConf craft)
{
if (craft.Cooldown > 0) LastTime[craft.PUBLIC_ID] = DateTime.Now;
}
public int GetCooldown(CraftConf craft)
{
DateTime time;
if (LastTime.TryGetValue(craft.PUBLIC_ID, out time))
return (int) time.AddSeconds(craft.Cooldown).Subtract(DateTime.Now).TotalSeconds;
return 0;
}
}
#endregion
#region Hooks
private void Init()
{
_instance = this;
_crafts = _config.Categories.SelectMany(x => x.Crafts).ToList();
RegisterPermissions();
RegisterCommands();
LoadCooldown();
#if TESTING
StopwatchWrapper.OnComplete = DebugMessage;
#endif
}
private void OnServerInitialized(bool initial)
{
LoadItems();
LoadImages();
LoadCustomWorkbenches();
if (!initial)
{
#if TESTING
using (new StopwatchWrapper("Loading entities took {0}ms."))
#endif
{
foreach (var ent in BaseNetworkable.serverEntities.OfType<BaseCombatEntity>())
OnEntitySpawned(ent);
}
}
if (_config.Categories.Exists(cat => cat.Crafts.Exists(craft => craft.Cooldown > 0)))
timer.Every(1, UpdateCooldown);
}
private void Unload()
{
DestroyUi();
DestroyRecyclers();
DestroyCars();
DestroyCustomWorkbenches();
SaveCooldown();
_instance = null;
_config = null;
}
private void OnEntityBuilt(Planner held, GameObject go)
{
if (held == null || go == null) return;
var player = held.GetOwnerPlayer();
if (player == null) return;
var entity = go.ToBaseEntity();
if (entity == null || entity.skinID == 0) return;
var craft = _crafts.Find(x =>
(x.Type == CraftType.Vehicle || x.Type == CraftType.Recycler || x.Type == CraftType.ModularCar) &&
x.SkinID == entity.skinID);
if (craft == null) return;
var transform = entity.transform;
var itemName = craft.PublicTitle;
NextTick(() =>
{
if (entity != null) entity.Kill();
});
RaycastHit rHit;
if (Physics.Raycast(transform.position + new Vector3(0, 0.1f, 0), Vector3.down, out rHit, 4f,
LayerMask.GetMask("Construction")) && rHit.GetEntity() != null)
{
if (!craft.Structure)
{
Reply(player, OnStruct, itemName);
GiveCraft(player, craft);
return;
}
}
else
{
if (!craft.Ground)
{
Reply(player, OnGround, itemName);
GiveCraft(player, craft);
return;
}
}
if (craft.UseDistance && Vector3.Distance(player.ServerPosition, transform.position) < craft.Distance)
{
Reply(player, BuildDistance, craft.Distance);
GiveCraft(player, craft);
return;
}
craft.Spawn(player, transform.position, transform.rotation);
}
private object CanResearchItem(BasePlayer player, Item item)
{
if (player == null || item == null ||
!_crafts.Exists(craft => craft.Enabled && craft.Type == CraftType.Vehicle && craft.ShortName == item.info.shortname &&
(item.skin == 0 || craft.SkinID == item.skin))) return null;
return false;
}
private void OnEntitySpawned(BaseCombatEntity entity)
{
if (entity == null) return;
if (entity is Recycler)
{
entity.gameObject.AddComponent<RecyclerComponent>();
return;
}
if (entity is BasicCar) entity.gameObject.AddComponent<CarController>();
}
private void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info)
{
if (entity == null || entity.OwnerID == 0) return;
var recycler = entity.GetComponent<RecyclerComponent>();
if (recycler != null)
{
info.damageTypes.ScaleAll(_config.Recycler.Scale);
recycler.DDraw();
}
var car = entity.GetComponent<CarController>();
if (car != null)
{
car.ManageDamage(info);
car.DDraw();
}
}
private object OnRecyclerToggle(Recycler recycler, BasePlayer player)
{
if (recycler == null || player == null) return null;
var component = recycler.GetComponent<RecyclerComponent>();
if (component == null) return null;
if (!recycler.IsOn())
{
foreach (var obj in recycler.inventory.itemList)
obj.CollectedForCrafting(player);
component.StartRecycling();
}
else
{
component.StopRecycling();
}
return false;
}
private void OnHammerHit(BasePlayer player, HitInfo info)
{
if (player == null || info == null) return;
var entity = info.HitEntity;
if (entity == null || entity.OwnerID == 0) return;
var component = entity.GetComponent<RecyclerComponent>();
if (component == null) return;
if (!_config.Recycler.Available)
{
Reply(player, NotTake);
return;
}
component.TryPickup(player);
}
private void OnPlayerDisconnected(BasePlayer player)
{
if (player == null) return;
_updateCooldown.Remove(player);
_openedCustomWb.Remove(player);
}
private void OnEntityGroundMissing(Recycler recycler)
{
if (recycler == null) return;
var component = recycler.GetComponent<RecyclerComponent>();
if (component == null) return;
component.DestroyActions();
}
private object CanLootEntity(BasePlayer player, Workbench workbench)
{
if (player == null || workbench == null)
return null;
CustomWorkbenchConf customWb;
if (_config.CustomWorkbench.TryGetValue(workbench.net.ID, out customWb))
{
_openedCustomWb[player] = customWb;
MainUi(player, first: true);
return false;
}
return null;
}
#endregion
#region Commands
private void CmdOpenCrafts(IPlayer cov, string command, string[] args)
{
var player = cov?.Object as BasePlayer;
if (player == null) return;
if (!string.IsNullOrEmpty(_config.Permission) &&
!permission.UserHasPermission(player.UserIDString, _config.Permission))
{
SendNotify(player, NoPermission, 1);
return;
}
if (_config.CloseReusing)
{
if (_openedUi.Contains(player))
{
CuiHelper.DestroyUi(player, Layer);
_update
// ... [Code preview truncated due to length. Full source in attached file] ...