C#:
using Rust;
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Reflection;
using UnityEngine;
using Newtonsoft.Json;
using Oxide.Core.Configuration;
using Random = System.Random;
using Oxide.Core;
using Oxide.Core.Plugins;
using Facepunch.Extend;
namespace Oxide.Plugins {
[Info("AlphaLoot", "Fujikura", "2.0.5", ResourceId = 13)]
public class AlphaLoot : RustPlugin {
[PluginReference]
Plugin CustomLootSpawns;
[PluginReference]
Plugin FancyDrop;
[PluginReference]
Plugin SkinBox;
bool Changed = false;
bool firstSetup = false;
Random rng = new Random();
Random rngHeli = new Random();
List<int> rngHeliList = new List<int>();
Random rngBradley = new Random();
List<int> rngBradleyList = new List<int>();
double fancyDropBpProbability;
static AlphaLoot al = null;
double baseItemRarity = 3;
bool initialized = false;
bool skinsLoaded = false;
bool manualReload = false;
int oldProtocol = 0;
StoredExportNames storedExportNames = new StoredExportNames();
DynamicConfigFile itemRaritys;
DynamicConfigFile itemLootFractions;
DynamicConfigFile lootTable;
DynamicConfigFile heliLoot;
DynamicConfigFile bradleyLoot;
DynamicConfigFile fancyDropLoot;
DynamicConfigFile getFile(string file) => Interface.Oxide.DataFileSystem.GetDatafile($"{this.Title}/{file}");
bool chkFile(string file) => Interface.Oxide.DataFileSystem.ExistsDatafile($"{this.Title}/{file}");
Dictionary<string, object> lootData = new Dictionary<string, object>();
Dictionary<string, object> lootContainers = new Dictionary<string, object>();
Dictionary<string, object> lootCategoryLimits = new Dictionary<string, object>();
Dictionary<string, object> fancyDropData = new Dictionary<string, object>();
Dictionary<string, object> fancyDropLootSpawn = new Dictionary<string, object>();
List<object> heliData = new List<object>();
List<object> bradleyData = new List<object>();
Dictionary<string, object> rarityOverridesItems = new Dictionary<string, object>();
Dictionary<string, object> rarityOverridesBlueprints = new Dictionary<string, object>();
Dictionary<string, object> fractionOverrides = new Dictionary<string, object>();
Dictionary<string, object> weaponAmmoPreload = new Dictionary<string, object>();
Dictionary<string, List<ulong>> skinsCache = new Dictionary<string, List<ulong>>();
List<string> newGameItems = new List<string>();
Dictionary<string, string> AllContainerTypes = new Dictionary<string, string>();
Dictionary<string, LootSpawn> AllLootSpawns = new Dictionary<string, LootSpawn>();
FieldInfo _guidToPath = typeof(GameManifest).GetField("guidToPath", (BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic));
//MethodInfo _OnDestroy = typeof(SpawnPointInstance).GetMethod("OnDestroy", BindingFlags.NonPublic | BindingFlags.Instance);
Dictionary<string, string> guidToPathCopy = new Dictionary<string, string>();
Dictionary<string, List<string>[]> Items = new Dictionary<string, List<string>[]>();
Dictionary<string, List<string>[]> Blueprints = new Dictionary<string, List<string>[]>();
Dictionary<string, int[]> itemWeights = new Dictionary<string, int[]>();
Dictionary<string, int[]> blueprintWeights = new Dictionary<string, int[]>();
Dictionary<string, int> totalItemWeight = new Dictionary<string, int>();
Dictionary<string, int> totalBlueprintWeight = new Dictionary<string, int>();
Dictionary<string, List<string>[]> itemsDrop = new Dictionary<string, List<string>[]>();
Dictionary<string, List<string>[]> blueprintsDrop = new Dictionary<string, List<string>[]>();
Dictionary<string, int[]> itemWeightsDrop = new Dictionary<string, int[]>();
Dictionary<string, int[]> blueprintWeightsDrop = new Dictionary<string, int[]>();
Dictionary<string, int> totalItemWeightDrop = new Dictionary<string, int>();
Dictionary<string, int> totalBlueprintWeightDrop = new Dictionary<string, int>();
ConsoleSystem.Command[] alVars;
static Dictionary<string, string> alVarDescriptions = new Dictionary<string, string> {
["admininputlootrefresh"]
= "Enables fast container lootrefresh on hammerhit", ["adminlootrefreshinterval"] = "The interval in seconds for the admin loot check", ["blockplayeriteminput"] = "Blocks input of player items back into lootcontainers", ["debuglootrepopulation"] = "This would log the container lootrefreshs to console", ["disablerefreshfunctions"] = "Disables loot content refresh for all non-barrel types", ["enablefancydroploot"] = "Provides seperate itemlists for all drop types (FancyDropLoot.json)", ["enableheliloadout"] = "Provides predefined loadouts for heli crates (HeliLoot.json)", ["enablebradleyloadout"] = "Provides predefined loadouts for bradley crates (BradleyLoot.json)", ["excludecustomlootspawns"] = "Excludes CustomLootSpawn boxes from handling", ["includeworkshopskins"] = "Randomize also WorkShopskins", ["itemamountminmax"] = "Enables all loottables and itemlists to use a min and max per item", ["lootstackfixenable"] = "Removal of stacked loot container at same position", ["lootstackfixrange"] = "Range to check for stacked loot containers", ["pluginenabled"] = "Enables/disables the plugin loot spawning", ["refreshminutes"] = "Time in minutes after a looted-not-empty container will be refreshed", ["setupauthlevel"] = "AuthLevel to have access to the plugin commands", ["showadminlootinfo"] = "Writes the lootcontainer name to chat after a hammerhit", ["useskinboxskins"] = "Can re-use the skins loaded by Skinbox", ["blueprintprobability"] = "Can be used as bp dropchance modifier (default ~11%)",
}
;
static Dictionary<string, string> alCmdDescriptions = new Dictionary<string, string> {
["reload"]
= "Reloads the whole plugin internally", ["refreshboxes"] = "Refreshes the complete server loot", ["rarityreload"] = "Reloads the item raritys into server after changing them", ["rarityset"] = "Sets the item rarity for a specific item", ["raritysetbp"] = "Sets the blueprint rarity for a specific item", ["lootreload"] = "Can with \"reset\" be used to prefill all item settings with new defaults", ["enable"] = "Enables the plugin from passive state", ["disable"] = "Disables the plugin into passive state", ["itemlimit"] = "Sets the maximum item limit for a given item", ["itemremove"] = "Removes an item complete from the loot tables", ["itemfind"] = "Shows the entries for a specific item", ["itemadd"] = "Adds an item with a given limit to the specific containers", ["categorylist"] = "Lists the current category defaults", ["categoryset"] = "Modifies a given category in the plugin config", ["containertypes"] = "Lists the added container types and their status", ["containeradd"] = "Adds a not included containtertype to your loot tables", ["containerremove"] = "Removes a specific containtertype from your loot tables", ["showcontainers"] = "Lists all current containers on map", ["showconfig"] = "Shows and explains the current config options", ["searchitems"] = "Search any game item(s) by partial name", ["lootmultiplier"] = "Simplified multiplier for increasing vanilla lootspawns"
}
;
static Dictionary<string, object> defaultCategoryLimits() {
var dp = new Dictionary<string, object>();
var dp0 = new Dictionary<string, object>();
dp0.Add("VanillaMultiplier", 1);
dp0.Add("DropSkinned", false);
dp.Add("Weapon", dp0);
dp0 = new Dictionary<string, object>();
dp0.Add("VanillaMultiplier", 1);
dp0.Add("DropSkinned", false);
dp.Add("Ammunition", dp0);
dp0 = new Dictionary<string, object>();
dp0.Add("VanillaMultiplier", 1);
dp0.Add("DropSkinned", false);
dp.Add("Items", dp0);
dp0 = new Dictionary<string, object>();
dp0.Add("VanillaMultiplier", 1);
dp0.Add("DropSkinned", false);
dp.Add("Tool", dp0);
dp0 = new Dictionary<string, object>();
dp0.Add("VanillaMultiplier", 1);
dp0.Add("DropSkinned", false);
dp.Add("Traps", dp0);
dp0 = new Dictionary<string, object>();
dp0.Add("VanillaMultiplier", 1);
dp0.Add("DropSkinned", false);
dp.Add("Construction", dp0);
dp0 = new Dictionary<string, object>();
dp0.Add("VanillaMultiplier", 1);
dp0.Add("DropSkinned", false);
dp.Add("Attire", dp0);
dp0 = new Dictionary<string, object>();
dp0.Add("VanillaMultiplier", 1);
dp0.Add("DropSkinned", false);
dp.Add("Resources", dp0);
dp0 = new Dictionary<string, object>();
dp0.Add("VanillaMultiplier", 1);
dp0.Add("DropSkinned", false);
dp.Add("Food", dp0);
dp0 = new Dictionary<string, object>();
dp0.Add("VanillaMultiplier", 1);
dp0.Add("DropSkinned", false);
dp.Add("Medical", dp0);
dp0 = new Dictionary<string, object>();
dp0.Add("VanillaMultiplier", 1);
dp0.Add("DropSkinned", false);
dp.Add("Component", dp0);
dp0 = new Dictionary<string, object>();
dp0.Add("VanillaMultiplier", 1);
dp0.Add("DropSkinned", false);
dp.Add("Misc", dp0);
return dp;
}
bool pluginEnabled;
bool debugLogEnabled;
int refreshMinutes;
bool debugLootRepopulation;
bool adminInputLootRefresh;
float adminLootRefreshInterval;
int setupAuthLevel;
bool showAdminLootInfo;
bool includeWorkShopSkins;
bool disableRefreshFunctions;
bool blockPlayerItemInput;
bool lootStackFixEnable;
float lootStackFixRange;
bool itemAmountMinMax;
bool enableHeliLoadOut;
bool enableBradleyLoadOut;
bool enableFancyDropLoot;
bool useSkinBoxSkins;
bool excludeCustomLootSpawns;
double blueprintProbability;
bool renewRaritysNewProtocol;
object GetConfig(string menu, string datavalue, object defaultValue) {
var data = Config[menu] as Dictionary<string, object>;
if (data == null) {
data = new Dictionary<string, object>();
Config[menu] = data;
Changed = true;
}
object value;
if (!data.TryGetValue(datavalue, out value)) {
value = defaultValue;
data[datavalue] = value;
Changed = true;
}
return value;
}
void LoadVariables() {
lootCategoryLimits = (Dictionary<string, object>)GetConfig("LootCategorys", "Limits", defaultCategoryLimits());
weaponAmmoPreload = (Dictionary<string, object>)GetConfig("Weapons", "Ammo", new Dictionary<string, object>());
refreshMinutes = Convert.ToInt32(GetConfig("Generic", "refreshMinutes", 30));
debugLootRepopulation = Convert.ToBoolean(GetConfig("Generic", "debugLootRepopulation", false));
pluginEnabled = Convert.ToBoolean(GetConfig("Generic", "pluginEnabled", false));
debugLogEnabled = Convert.ToBoolean(GetConfig("Debug", "debugLogEnabled", false));
adminInputLootRefresh = Convert.ToBoolean(GetConfig("Generic", "adminInputLootRefresh", true));
adminLootRefreshInterval = Convert.ToSingle(GetConfig("Generic", "adminLootRefreshInterval", 3f));
setupAuthLevel = Convert.ToInt32(GetConfig("Generic", "setupAuthLevel", 2));
showAdminLootInfo = Convert.ToBoolean(GetConfig("Generic", "showAdminLootInfo", true));
includeWorkShopSkins = Convert.ToBoolean(GetConfig("Generic", "includeWorkShopSkins", false));
disableRefreshFunctions = Convert.ToBoolean(GetConfig("Generic", "disableRefreshFunctions", false));
blockPlayerItemInput = Convert.ToBoolean(GetConfig("Generic", "blockPlayerItemInput", true));
lootStackFixEnable = Convert.ToBoolean(GetConfig("Generic", "lootStackFixEnable", true));
lootStackFixRange = Convert.ToSingle(GetConfig("Generic", "lootStackFixRange", 0.3f));
itemAmountMinMax = Convert.ToBoolean(GetConfig("Generic", "itemAmountMinMax", true));
enableHeliLoadOut = Convert.ToBoolean(GetConfig("Generic", "enableHeliLoadOut", true));
enableBradleyLoadOut = Convert.ToBoolean(GetConfig("Generic", "enableBradleyLoadOut", true));
enableFancyDropLoot = Convert.ToBoolean(GetConfig("Generic", "enableFancyDropLoot", false));
useSkinBoxSkins = Convert.ToBoolean(GetConfig("Generic", "useSkinBoxSkins", false));
excludeCustomLootSpawns = Convert.ToBoolean(GetConfig("Generic", "excludeCustomLootSpawns", true));
blueprintProbability = Convert.ToDouble(GetConfig("Generic", "blueprintProbability", 0.11));
renewRaritysNewProtocol = Convert.ToBoolean(GetConfig("Generic", "renewRaritysNewProtocol", false));
var configremoval = false;
if ((Config.Get("Generic") as Dictionary<string, object>).ContainsKey("itemSlotVariance")) {
(Config.Get("Generic") as Dictionary<string, object>).Remove("itemSlotVariance");
configremoval = true;
}
if ((Config.Get("Generic") as Dictionary<string, object>).ContainsKey("enableLootFraction")) {
(Config.Get("Generic") as Dictionary<string, object>).Remove("enableLootFraction");
configremoval = true;
}
if ((Config.Get("Generic") as Dictionary<string, object>).ContainsKey("enableScrapSpawn")) {
(Config.Get("Generic") as Dictionary<string, object>).Remove("enableScrapSpawn");
configremoval = true;
}
if ((Config.Get("Generic") as Dictionary<string, object>).ContainsKey("itemCanSpawnAsBlueprint")) {
(Config.Get("Generic") as Dictionary<string, object>).Remove("itemCanSpawnAsBlueprint");
configremoval = true;
}
if ((Config.Get("Generic") as Dictionary<string, object>).ContainsKey("enableDefaultRarityOverrides")) {
(Config.Get("Generic") as Dictionary<string, object>).Remove("enableDefaultRarityOverrides");
configremoval = true;
}
if ((Config.Get("ExcludeFromMultiply") != null)) {
Config.Remove("ExcludeFromMultiply");
configremoval = true;
}
if (!Changed && !configremoval) return;
SaveConfig();
Changed = false;
}
protected override void LoadDefaultConfig() {
Config.Clear();
LoadVariables();
}
void Init() {
LoadVariables();
itemRaritys = getFile("ItemRaritys");
lootTable = getFile("LootTables");
itemLootFractions = getFile("LootFractions");
if (enableHeliLoadOut) heliLoot = getFile("HeliLoot");
if (enableBradleyLoadOut) bradleyLoot = getFile("BradleyLoot");
if (enableFancyDropLoot) fancyDropLoot = getFile("FancyDropLoot");
guidToPathCopy = (Dictionary<string, string>)_guidToPath.GetValue(GameManifest.Current);
}
void Loaded() => al = this;
void OnTerrainInitialized() {
if (debugLogEnabled) LogToFile("PopulateContainer", $"{DateTime.Now.ToString()} - SERVERSTARTUP > fresh server startup detected", this);
}
void OnServerInitialized() {
if (initialized) return;
int varCount = (Config["Generic"] as Dictionary<string, object>).Count;
alVars = new ConsoleSystem.Command[varCount];
int i = 0;
foreach (var conf in (Config["Generic"] as Dictionary<string, object>)) {
alVars[i] = new ConsoleSystem.Command {
Name = conf.Key, Parent = "alphaloot", FullName = "alphaloot." + conf.Key.ToLower(), ServerAdmin = true, Description = alVarDescriptions.ContainsKey(conf.Key.ToLower()) && alVarDescriptions[conf.Key.ToLower()] != string.Empty ? $"| {alVarDescriptions[conf.Key.ToLower()]} |" : "| no description - contact the author |", Variable = true, GetOveride = (() => Config["Generic", conf.Key].ToString()), SetOveride = delegate (string str) {
TypeCode typeCode = Convert.GetTypeCode(conf.Value);
switch (typeCode) {
case TypeCode.Boolean : Config["Generic", conf.Key] = str.ToBool();
break;
case TypeCode.Single : Config["Generic", conf.Key] = str.ToFloat();
break;
case TypeCode.Int32 : Config["Generic", conf.Key] = str.ToInt();
break;
default : break;
}
Config.Save();
LoadConfig();
}
}
;
i++;
}
foreach (var alCmd in alCmdDescriptions) {
if (ConsoleSystem.Index.Server.Dict.ContainsKey("al." + alCmd.Key)) ConsoleSystem.Index.Server.Dict["al." + alCmd.Key].Description = alCmd.Value + " (alphaloot)";
}
foreach (var indexCmd in ConsoleSystem.Index.Server.Dict.Where(k => k.Key.StartsWith("al.") && (k.Value.Description == null || k.Value.Description == string.Empty))) indexCmd.Value.Description = "no description - contact the author - (alphaloot)";
foreach (var alVar in alVars) ConsoleSystem.Index.Server.Dict[alVar.FullName.ToLower()] = alVar;
ConsoleSystem.Index.All = ConsoleSystem.Index.Server.Dict.Values.ToArray<ConsoleSystem.Command>();
NextFrame(() => ServerMgr.Instance.StartCoroutine(UpdateInternals(true)));
}
void Unload() {
foreach (var cmd in alVars) ConsoleSystem.Index.Server.Dict.Remove(cmd.FullName.ToLower());
if (itemRaritys != null) itemRaritys.Clear();
if (itemLootFractions != null) itemLootFractions.Clear();
if (lootTable != null) lootTable.Clear();
if (heliLoot != null) heliLoot.Clear();
if (bradleyLoot != null) bradleyLoot.Clear();
if (fancyDropLoot != null) fancyDropLoot.Clear();
if (!disableRefreshFunctions) {
var objs = UnityEngine.Object.FindObjectsOfType<RefreshHandler>().ToList();
if (objs.Count > 0) foreach (var obj in objs) GameObject.DestroyImmediate(obj);
}
var objsa = UnityEngine.Object.FindObjectsOfType<AdminLootHandler>().ToList();
if (objsa.Count > 0) foreach (var obj in objsa) GameObject.Destroy(obj);
}
void OnPluginLoaded(Plugin name) {
if (initialized && enableFancyDropLoot && name.Name == "FancyDrop") {
if (FancyDrop?.Call("getFancyDropTypes") == null) return;
Dictionary<string, object> setupDropTypes = FancyDrop.Call("getFancyDropTypes") as Dictionary<string, object>;
if (setupDropTypes != null && setupDropTypes.Count != 0) GetFancyDropLoot(setupDropTypes);
}
}
object CanAcceptItem(ItemContainer container, Item item) {
if (!pluginEnabled || !blockPlayerItemInput || container == null || container.entityOwner == null || container.entityOwner.GetComponent<LootContainer>() == null) return null;
if (item.GetOwnerPlayer()) return ItemContainer.CanAcceptResult.CannotAccept;
return null;
}
void OnEntitySpawned(BaseNetworkable entity) {
if (!initialized || !pluginEnabled || entity == null || !(entity is LootContainer)) return;
NextTick(() => {
if (entity == null || (CustomLootSpawns && excludeCustomLootSpawns && (bool)CustomLootSpawns?.Call("IsLootBox", entity.GetComponent<BaseEntity>()))) return;
if (lootStackFixEnable && entity.ShortPrefabName != "heli_crate" && entity.ShortPrefabName != "bradley_crate") {
LootContainer[] stacked = null;
try {
stacked = Physics.OverlapSphere(entity.transform.position, lootStackFixRange).Where(entry => entry != null && entry.GetComponentInParent<LootContainer>() != null).Select(entry => entry.GetComponentInParent<LootContainer>()).Distinct().OrderByDescending(c => c.net.ID).ToArray();
}
catch {
}
if (stacked != null && stacked.Length > 1) for (int i = 0; i < stacked.Length - 1; i++) {
if (stacked[i].gameObject.GetComponent<SpawnPointInstance>()) {
GameObject.Destroy(stacked[i].gameObject.GetComponent<SpawnPointInstance>());
//_OnDestroy.Invoke(stacked[i].gameObject.GetComponent<SpawnPointInstance>(), null);
}
stacked[i].Kill();
}
}
if (entity && enableHeliLoadOut && entity.ShortPrefabName == "heli_crate") {
PopulateSpecial(entity as LootContainer);
return;
}
if (entity && enableBradleyLoadOut && entity.ShortPrefabName == "bradley_crate") {
PopulateSpecial(entity as LootContainer);
return;
}
if (entity && enableFancyDropLoot && entity is SupplyDrop && FancyDrop) return;
if (entity) PopulateContainer(entity as LootContainer);
}
);
}
void OnEntityKill(BaseNetworkable entity) {
if (!initialized || !pluginEnabled || entity == null) return;
if (enableHeliLoadOut && entity is BaseHelicopter) {
timer.Once(1.0f, () => {
rngHeli = new Random();
rngHeliList = new List<int>();
}
);
}
if (enableBradleyLoadOut && entity is BradleyAPC) {
timer.Once(1.0f, () => {
rngBradley = new Random();
rngBradleyList = new List<int>();
}
);
}
}
IEnumerator UpdateInternals(bool doLog = true, bool recreateHeli = false) {
ClearDictionarys();
SaveExportNames();
LoadAllContainers();
LoadItemRaritys(doLog);
LoadLootFractions(doLog);
LoadLootTables(doLog);
GetFancyDropLoot(new Dictionary<string, object>(), false);
GetHeliLoot(recreateHeli);
GetBradleyLoot(recreateHeli);
FixLoot();
GetItemSkins();
LoadWeaponsAmmo();
if (!pluginEnabled || Changed || firstSetup) {
if (Changed) Config["Generic", "pluginEnabled"] = false;
SaveConfig();
Changed = false;
if (doLog) PrintWarning("Plugin running in passive mode.Activate by command 'al.enable'");
yield break;
}
foreach (var data in lootData) {
Items.Add(data.Key, new List<string>[5]);
Blueprints.Add(data.Key, new List<string>[5]);
for (var i = 0; i < 5; ++i) {
Items[data.Key][i] = new List<string>();
Blueprints[data.Key][i] = new List<string>();
}
var limits = (Dictionary<string, object>)data.Value;
foreach (var limit in limits) {
string name = limit.Key;
bool isBP = name.EndsWith(".bp") || name.EndsWith(".blueprint") ? true : false;
if (isBP) name = name.Replace(".bp", "").Replace(".blueprint", "");
ItemDefinition def = ItemManager.FindItemDefinition(name);
if (def != null) {
if (def.GetComponent<ItemModEntity>() != null && def.GetComponent<ItemModEntity>().entityPrefab != null && !guidToPathCopy.ContainsKey(def.GetComponent<ItemModEntity>().entityPrefab.guid)) continue;
if (isBP && def.Blueprint != null && def.Blueprint.isResearchable) {
if (!Blueprints[data.Key][(int)def.rarity].Contains(name)) Blueprints[data.Key][(int)def.rarity].Add(name);
}
if (!isBP && !Items[data.Key][(int)def.rarity].Contains(name)) Items[data.Key][(int)def.rarity].Add(name);
}
}
totalItemWeight.Add(data.Key, 0);
totalBlueprintWeight.Add(data.Key, 0);
itemWeights.Add(data.Key, new int[5]);
blueprintWeights.Add(data.Key, new int[5]);
for (var i = 0; i < 5; ++i) {
totalItemWeight[data.Key] += (itemWeights[data.Key][i] = ItemWeight(baseItemRarity, i) * Items[data.Key][i].Count);
totalBlueprintWeight[data.Key] += (blueprintWeights[data.Key][i] = ItemWeight(baseItemRarity, i) * Blueprints[data.Key][i].Count);
}
}
int populatedContainers = 0;
if (debugLogEnabled) LogToFile("PopulateContainer", $"{DateTime.Now.ToString()} - START > Initial LootPopulation started", this);
foreach (var container in UnityEngine.Object.FindObjectsOfType<LootContainer>().ToList()) {
if (CustomLootSpawns && excludeCustomLootSpawns && (bool)CustomLootSpawns?.Call("IsLootBox", container.GetComponent<BaseEntity>())) continue;
if (PopulateContainer(container)) populatedContainers++;
}
if (debugLogEnabled) LogToFile("PopulateContainer", $"{DateTime.Now.ToString()} - STARTED > Initial LootPopulation done with '{populatedContainers}' containers", this);
if (doLog) Puts($"Populated '{populatedContainers}' LootContainer with custom Loot.");
if (!initialized) Puts("All plugin variables & commands can be listed with \'find alphaloot\'");
initialized = true;
yield return null;
}
void ClearDictionarys() {
lootData.Clear();
lootContainers.Clear();
heliData.Clear();
bradleyData.Clear();
fancyDropData.Clear();
itemsDrop.Clear();
blueprintsDrop.Clear();
itemWeightsDrop.Clear();
blueprintWeightsDrop.Clear();
totalItemWeightDrop.Clear();
totalBlueprintWeightDrop.Clear();
Items.Clear();
Blueprints.Clear();
itemWeights.Clear();
blueprintWeights.Clear();
totalItemWeight.Clear();
totalBlueprintWeight.Clear();
newGameItems.Clear();
}
void GetItemSkins() {
if (skinsLoaded) return;
foreach (var itemDef in ItemManager.GetItemDefinitions()) {
List<ulong> skins;
skins = new List<ulong> {
0
}
;
skins.AddRange(ItemSkinDirectory.ForItem(itemDef).Select(skin => Convert.ToUInt64(skin.id)));
skinsCache.Add(itemDef.shortname, skins);
}
bool skinBoxEnabled = (plugins.Exists("SkinBox") && useSkinBoxSkins);
skinsLoaded = true;
if (includeWorkShopSkins && !skinBoxEnabled) {
GetWorkshopSkins();
return;
}
if (skinBoxEnabled) {
GetSkinBoxSkins();
return;
}
if (includeWorkShopSkins) GetWorkshopSkins();
}
void GetWorkshopSkins() {
int updated = 0;
foreach (var shopskin in Rust.Workshop.Approved.All.Where(skin => skin.Skinnable.ItemName != null && skin.Skinnable.ItemName != "")) {
if (!skinsCache.ContainsKey(shopskin.Skinnable.ItemName)) skinsCache[shopskin.Skinnable.ItemName] = new List<ulong>();
if (!skinsCache[shopskin.Skinnable.ItemName].Contains(shopskin.WorkshopdId)) {
skinsCache[shopskin.Skinnable.ItemName].Add(shopskin.WorkshopdId);
updated++;
}
}
if (updated > 0) Puts($"SkinCache filled with '{updated}' skins");
}
void OnSkinCacheUpdate(Dictionary<string, List<ulong>> skins, bool loading) {
if (!initialized || !skinsLoaded || !useSkinBoxSkins) return;
skinsCache = new Dictionary<string, List<ulong>>(skins);
int count = 0;
int items = 0;
foreach (var skin in skinsCache) {
if (skin.Value.Count > 1) {
count += skin.Value.Count - 1;
items++;
}
}
if (loading) Puts($"Reveived '{items}' items from SkinBox with '{count}' skins at all");
else Puts($"Reveived SkinBox skins update");
}
void GetSkinBoxSkins() {
var skins = SkinBox?.Call("getSkincache") ?? null;
if (skins == null || skins is bool) {
GetWorkshopSkins();
return;
}
skinsCache = new Dictionary<string, List<ulong>>(skins as Dictionary<string, List<ulong>>);
int count = 0;
int items = 0;
foreach (var skin in skinsCache) {
if (skin.Value.Count > 1) {
count += skin.Value.Count - 1;
items++;
}
}
Puts($"Reveived '{items}' items from SkinBox with '{count}' skins at all");
}
object OnFancyDropCrate(Dictionary<string, object> cratesettings, bool internalCall = false) {
if (!internalCall) if (!enableFancyDropLoot || !cratesettings.ContainsKey("droptype")) return null;
string crateName = string.Empty;
if (internalCall) crateName = "regular";
else crateName = (string)cratesettings["droptype"];
if (fancyDropData.ContainsKey(crateName)) {
if (((fancyDropData[crateName] as Dictionary<string, object>)["ItemsList"] as Dictionary<string, object>).Count > 0) {
var crateType = fancyDropData[crateName] as Dictionary<string, object>;
var maxItemCount = (crateType["ItemsList"] as Dictionary<string, object>).Count;
var itemCount = 6;
if (crateType.ContainsKey("ItemMin") && crateType.ContainsKey("ItemMax")) {
if ((int)crateType["ItemMin"] <= (int)crateType["ItemMax"]) itemCount = UnityEngine.Random.Range((int)crateType["ItemMin"], (int)crateType["ItemMax"]);
else itemCount = UnityEngine.Random.Range((int)crateType["ItemMax"], (int)crateType["ItemMin"]);
}
if (itemCount > maxItemCount) itemCount = maxItemCount;
var items = new List<Item>();
var itemNames = new List<string>();
var itemBlueprints = new List<int>();
var maxRetry = 10 * itemCount;
int divider = 1;
if (crateType.ContainsKey("ItemDivider")) divider = (int)crateType["ItemDivider"];
Dictionary<string, object> con = null;
object containerobj;
if (lootContainers.TryGetValue("supply_drop", out containerobj)) con = containerobj as Dictionary<string, object>;
for (int i = 0; i < itemCount; ++i) {
if (maxRetry == 0) break;
Item item = null;
if (con != null) item = MightyRNGDrop(crateName, divider, itemCount, (bool)(itemBlueprints.Count >= (int)con["MaxBlueprintSpawns"]));
else item = MightyRNGDrop(crateName, divider, itemCount);
if (item == null) {
--maxRetry;
--i;
continue;
}
if (itemNames.Contains(item.info.shortname) || (item.IsBlueprint() && itemBlueprints.Contains(item.blueprintTarget))) {
item.Remove(0f);
--maxRetry;
--i;
continue;
}
else if (item.IsBlueprint()) itemBlueprints.Add(item.blueprintTarget);
else itemNames.Add(item.info.shortname);
items.Add(item);
}
if (con != null) {
if ((bool)con["LootFraction"]) {
foreach (Item current in items.ToList()) if (current.hasCondition) current.condition = UnityEngine.Random.Range(current.info.condition.foundCondition.fractionMin, current.info.condition.foundCondition.fractionMax) * current.info.condition.max;
}
if ((int)con["ScrapAmount"] > 0) {
int scrapCount = 0;
if (con.ContainsKey("ScrapVariance") && (int)con["ScrapVariance"] != 0) scrapCount = Mathf.RoundToInt(UnityEngine.Random.Range(Convert.ToSingle(Mathf.Min((int)con["ScrapAmount"], (int)con["ScrapAmount"] + (int)con["ScrapVariance"])) * 100f, Convert.ToSingle(Mathf.Max((int)con["ScrapAmount"], (int)con["ScrapAmount"] + (int)con["ScrapVariance"])) * 100f) / 100f);
else scrapCount = (int)con["ScrapAmount"];
Item item = ItemManager.Create(ItemManager.FindItemDefinition("scrap"), scrapCount, 0uL);
items.Add(item);
}
}
return items;
}
}
return null;
}
void FixLoot() {
if (!lootStackFixEnable) return;
var spawns = UnityEngine.Object.FindObjectsOfType<LootContainer>().OrderBy(c => c.transform.position.x).ThenBy(c => c.transform.position.z).ThenBy(c => c.transform.position.z).ToList();
var count = spawns.Count();
var racelimit = count * count;
var antirace = 0;
var deleted = 0;
for (var i = 0; i < count; i++) {
var box = spawns[i];
var next = i + 1;
var pos = new Vector2(box.transform.position.x, box.transform.position.z);
if (++antirace > racelimit) return;
while (next < count) {
var box2 = spawns[next];
var pos2 = new Vector2(box2.transform.position.x, box2.transform.position.z);
var distance = Vector2.Distance(pos, pos2);
if (++antirace > racelimit) return;
if (distance < lootStackFixRange) {
spawns.RemoveAt(next);
count--;
if (box2.gameObject.GetComponent<SpawnPointInstance>()) {
GameObject.Destroy(box2.gameObject.GetComponent<SpawnPointInstance>());
//_OnDestroy.Invoke(box2.gameObject.GetComponent<SpawnPointInstance>(), null);
}
(box2 as BaseEntity).Kill();
deleted++;
}
else break;
}
}
if (deleted > 0) Puts($"Removed {deleted} stacked LootContainer.");
}
Item MightyRNG(string type, int divider, int itemCount, bool blockBPs = false) {
bool asBP = (rng.NextDouble() < blueprintProbability && !blockBPs);
List<string> selectFrom;
int limit = 0;
string itemName;
Item item;
if (divider < 1) divider = 1;
int maxRetry = 10 * itemCount;
do {
selectFrom = null;
item = null;
if (asBP) {
var r = rng.Next(totalBlueprintWeight[type]);
for (var i = 0; i < 5; ++i) {
limit += blueprintWeights[type][i];
if (r < limit) {
selectFrom = Blueprints[type][i];
break;
}
}
}
else {
var r = rng.Next(totalItemWeight[type]);
for (var i = 0; i < 5; ++i) {
limit += itemWeights[type][i];
if (r < limit) {
selectFrom = Items[type][i];
break;
}
}
}
if (selectFrom == null) {
if (--maxRetry <= 0) break;
continue;
}
itemName = selectFrom[rng.Next(0, selectFrom.Count)];
ItemDefinition itemDef = ItemManager.FindItemDefinition(itemName);
if (asBP && itemDef.Blueprint != null && itemDef.Blueprint.isResearchable) {
var blueprintBaseDef = ItemManager.FindItemDefinition(-1887162396);
item = ItemManager.Create(blueprintBaseDef, 1, 0uL);
item.blueprintTarget = itemDef.itemid;
}
else {
object limits;
bool DropSkinned = false;
if (lootCategoryLimits.TryGetValue(itemDef.category.ToString(), out limits)) DropSkinned = (bool)(limits as Dictionary<string, object>)["DropSkinned"];
if (DropSkinned && skinsCache[itemName].Count > 1) item = ItemManager.Create(itemDef, 1, skinsCache[itemName].GetRandom());
else item = ItemManager.CreateByName(itemName, 1);
}
if (item == null || item.info == null) continue;
break;
}
while (true);
if (item == null) return null;
object itemLimit;
if (!item.IsBlueprint() && (lootData[type] as Dictionary<string, object>).TryGetValue(item.info.shortname, out itemLimit)) {
if ((itemLimit as Dictionary<string, object>) != null) {
Dictionary<string, object> limits = itemLimit as Dictionary<string, object>;
item.amount = UnityEngine.Random.Range(Math.Min((int)limits["Min"], (int)limits["Max"]), Math.Max((int)limits["Min"], (int)limits["Max"]));
}
else if ((int)itemLimit > 1) item.amount = UnityEngine.Random.Range(Mathf.CeilToInt(Convert.ToSingle(itemLimit) / divider), (int)itemLimit);
}
if (!item.IsBlueprint() && item.info.category == ItemCategory.Weapon && weaponAmmoPreload.ContainsKey(item.info.shortname) && (int)weaponAmmoPreload[item.info.shortname] >= 0) {
var magazine = (item.GetHeldEntity() as BaseProjectile).primaryMagazine;
magazine.contents = Math.Min(magazine.capacity, (int)weaponAmmoPreload[item.info.shortname]);
}
item.OnVirginSpawn();
return item;
}
Item MightyRNGDrop(string type, int divider, int itemCount, bool blockBPs = false) {
bool asBP = (rng.NextDouble() < fancyDropBpProbability && !blockBPs);
List<string> selectFrom;
int limit = 0;
string itemName;
Item item;
if (divider < 1) divider = 1;
int maxRetry = 10 * itemCount;
do {
selectFrom = null;
item = null;
if (asBP) {
var r = rng.Next(totalBlueprintWeightDrop[type]);
for (var i = 0; i < 5; ++i) {
limit += blueprintWeightsDrop[type][i];
if (r < limit) {
selectFrom = blueprintsDrop[type][i];
break;
}
}
}
else {
var r = rng.Next(totalItemWeightDrop[type]);
for (var i = 0; i < 5; ++i) {
limit += itemWeightsDrop[type][i];
if (r < limit) {
selectFrom = itemsDrop[type][i];
break;
}
}
}
if (selectFrom == null) {
if (--maxRetry <= 0) break;
continue;
}
itemName = selectFrom[rng.Next(0, selectFrom.Count)];
ItemDefinition itemDef = ItemManager.FindItemDefinition(itemName);
if (asBP && itemDef.Blueprint != null && itemDef.Blueprint.isResearchable) {
var blueprintBaseDef = ItemManager.FindItemDefinition(-1887162396);
item = ItemManager.Create(blueprintBaseDef, 1, 0uL);
item.blueprintTarget = itemDef.itemid;
}
else {
object limits;
bool DropSkinned = false;
if (lootCategoryLimits.TryGetValue(itemDef.category.ToString(), out limits)) DropSkinned = (bool)(limits as Dictionary<string, object>)["DropSkinned"];
if (DropSkinned && skinsCache[itemName].Count > 1) item = ItemManager.Create(itemDef, 1, skinsCache[itemName].GetRandom());
else item = ItemManager.CreateByName(itemName, 1);
}
if (item == null || item.info == null) continue;
break;
}
while (true);
if (item == null) return null;
object itemLimit;
if (!item.IsBlueprint() && ((fancyDropData[type] as Dictionary<string, object>)["ItemsList"] as Dictionary<string, object>).TryGetValue(item.info.shortname, out itemLimit)) {
if ((itemLimit as Dictionary<string, object>) != null) {
Dictionary<string, object> limits = itemLimit as Dictionary<string, object>;
item.amount = UnityEngine.Random.Range(Math.Min((int)limits["Min"], (int)limits["Max"]), Math.Max((int)limits["Min"], (int)limits["Max"]));
}
else if ((int)itemLimit > 1) item.amount = UnityEngine.Random.Range(Mathf.CeilToInt(Convert.ToSingle(itemLimit) / divider), (int)itemLimit);
}
if (!item.IsBlueprint() && item.info.category == ItemCategory.Weapon && weaponAmmoPreload.ContainsKey(item.info.shortname) && (int)weaponAmmoPreload[item.info.shortname] >= 0) {
var magazine = (item.GetHeldEntity() as BaseProjectile).primaryMagazine;
magazine.contents = Math.Min(magazine.capacity, (int)weaponAmmoPreload[item.info.shortname]);
}
item.OnVirginSpawn();
return item;
}
void ClearContainer(LootContainer container) {
while (container.inventory.itemList.Count > 0) {
var item = container.inventory.itemList[0];
item.RemoveFromContainer();
item.Remove(0f);
}
}
void SuppressRefresh(LootContainer container) {
container.minSecondsBetweenRefresh = 0;
container.maxSecondsBetweenRefresh = 0;
container.GetComponent<FacepunchBehaviour>().CancelInvoke(new Action(container.SpawnLoot));
}
bool PopulateContainer(LootContainer container) {
Dictionary<string, object> con;
object containerobj;
int lootitemcount = 0;
if (lootContainers.TryGetValue(container.ShortPrefabName, out containerobj)) {
con = containerobj as Dictionary<string, object>;
if (!(bool)con["Enabled"]) {
if (debugLogEnabled) LogToFile("PopulateContainer", $"{DateTime.Now.ToString()} - CANCELED > Setting for '{container.ShortPrefabName}' not active", this);
return false;
}
object itemcount;
if (lootData.TryGetValue(container.ShortPrefabName, out itemcount)) lootitemcount = (int)(itemcount as Dictionary<string, object>).Count();
else {
if (debugLogEnabled) LogToFile("PopulateContainer", $"{DateTime.Now.ToString()} - CANCELED > no or too-few items in list for '{container.ShortPrefabName}'", this);
return false;
}
}
else {
if (debugLogEnabled) LogToFile("PopulateContainer", $"{DateTime.Now.ToString()} - FAILED > container '{container.ShortPrefabName}' is not in loottable list", this);
return false;
}
if (container.inventory == null) {
container.inventory = new ItemContainer();
container.inventory.ServerInitialize(null, 18);
container.inventory.GiveUID();
}
else {
ClearContainer(container);
container.inventory.capacity = 18;
}
SuppressRefresh(container);
int itemCount = 0;
if (con.ContainsKey("ItemsVariance") && (int)con["ItemsVariance"] != 0) itemCount = Mathf.RoundToInt(UnityEngine.Random.Range(Convert.ToSingle(Mathf.Min((int)con["Items"], (int)con["Items"] + (int)con["ItemsVariance"])) * 100f, Convert.ToSingle(Mathf.Max((int)con["Items"], (int)con["Items"] + (int)con["ItemsVariance"])) * 100f) / 100f);
else itemCount = (int)con["Items"];
if (lootitemcount > 0 && itemCount > lootitemcount && lootitemcount < 18) itemCount = lootitemcount;
var items = new List<Item>();
var itemNames = new List<string>();
var itemBlueprints = new List<int>();
var maxRetry = 20;
int divider = 1;
if (con.ContainsKey("MinAmountDivider")) divider = (int)con["MinAmountDivider"];
for (int i = 0; i < itemCount; ++i) {
if (maxRetry == 0) {
break;
// ... [Code preview truncated due to length. Full source in attached file] ...