C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
//#define DEBUG
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
using Oxide.Core;
using Rust;
using UnityEngine;
namespace Oxide.Plugins {
[Info("LootConfig", "Nogrod", "1.0.22")]
internal class LootConfig : RustPlugin {
private const int VersionConfig = 11;
private readonly FieldInfo ParentSpawnGroupField = typeof (SpawnPointInstance).GetField("parentSpawnGroup", BindingFlags.Instance | BindingFlags.NonPublic);
private readonly FieldInfo SpawnGroupsField = typeof (SpawnHandler).GetField("SpawnGroups", BindingFlags.Instance | BindingFlags.NonPublic);
private readonly FieldInfo SpawnPointsField = typeof(SpawnGroup).GetField("spawnPoints", BindingFlags.Instance | BindingFlags.NonPublic);
private readonly Regex _findLoot = new Regex(@"(crate[\-_](elite|mine|normal|tools)[\-_\d\w]*(food|medical)*|foodbox[\-_\d\w]*|loot[\-_](barrel|trash)[\-_\d\w]*|heli[\-_]crate[\-_\d\w]*|oil[\-_]barrel[\-_\d\w]*|supply[\-_]drop[\-_\d\w]*|trash[\-_]pile[\-_\d\w]*|/dmloot/.*|giftbox[\-_]loot|stocking[\-_](small|large)[\-_]deployed|minecart|bradley[\-_]crate[\-_\d\w]*)\.prefab", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private ConfigData _config;
private Dictionary<string, ItemDefinition> _itemsDict;
private new void LoadDefaultConfig() {
}
private new bool LoadConfig() {
try {
Config.Settings = new JsonSerializerSettings();
if (!Config.Exists()) return CreateDefaultConfig();
_config = Config.ReadObject<ConfigData>();
}
catch (Exception e) {
Puts("Config load failed: {0}{1}{2}", e.Message, Environment.NewLine, e.StackTrace);
return false;
}
return true;
}
private void OnServerInitialized() {
if (!LoadConfig()) return;
var allPrefabs = GameManifest.Current.pooledStrings.ToList().ConvertAll(p => p.str);
var prefabs = allPrefabs.Where(p => _findLoot.IsMatch(p)).ToArray();
#if DEBUG
Puts(string.Join(Environment.NewLine, allPrefabs.ToArray()));
Puts("Count: " + prefabs.Length);
#endif
foreach (var source in prefabs) {
#if DEBUG
Puts(source);
#endif
GameManager.server.FindPrefab(source);
}
if (!CheckConfig()) return;
NextTick(UpdateLoot);
}
private void OnSpawnSubCategory(LootSpawn lootSpawn) {
Puts("OnSpawnSubCategory: {0}", lootSpawn.name);
}
private void OnSubCategoryIntoContainer(LootSpawn lootSpawn) {
Puts("OnSubCategoryIntoContainer: {0}", lootSpawn.name);
}
[ConsoleCommand("loot.reload")]
private void cmdConsoleReload(ConsoleSystem.Arg arg) {
if (!LoadConfig()) return;
if (!CheckConfig()) return;
UpdateLoot();
Puts("Loot config reloaded.");
}
[ConsoleCommand("loot.dump")]
private void cmdLootDump(ConsoleSystem.Arg arg) {
LootDump();
}
[ConsoleCommand("loot.stats")]
private void cmdLootStats(ConsoleSystem.Arg arg) {
var lootContainers = Resources.FindObjectsOfTypeAll<LootContainer>();
var itemModReveal = Resources.FindObjectsOfTypeAll<ItemModReveal>();
var itemModUnwrap = Resources.FindObjectsOfTypeAll<ItemModUnwrap>();
var sb = new StringBuilder();
sb.AppendLine();
foreach (var lootContainer in lootContainers) {
sb.AppendLine(lootContainer.name);
PrintLootSpawn(lootContainer.lootDefinition, 1, sb, 1);
}
foreach (var reveal in itemModReveal) {
sb.AppendLine(reveal.name);
PrintLootSpawn(reveal.revealList, 1, sb, 1);
}
foreach (var unwrap in itemModUnwrap) {
sb.AppendLine(unwrap.name);
PrintLootSpawn(unwrap.revealList, 1, sb, 1);
}
var logname = $"oxide/logs/Loot_{DateTime.Now.ToString("yyMMdd_HHmmss")}.txt";
ConVar.Server.Log(logname, sb.ToString());
Puts("Stats written to '{0}'", logname);
}
private bool CreateDefaultConfig() {
Config.Clear();
var loot = Resources.FindObjectsOfTypeAll<LootSpawn>();
var itemModReveal = Resources.FindObjectsOfTypeAll<ItemModReveal>();
var itemModUnwrap = Resources.FindObjectsOfTypeAll<ItemModUnwrap>();
#if DEBUG
var sb = new StringBuilder();
foreach (var reveal in itemModReveal) {
var items = new List<ItemAmount>();
var stack = new Stack<LootSpawn>();
stack.Push(reveal.revealList);
while (stack.Count > 0) {
var lootSpawn = stack.Pop();
if (lootSpawn.subSpawn != null && lootSpawn.subSpawn.Length > 0) {
foreach (var entry in lootSpawn.subSpawn) {
stack.Push(entry.category);
}
continue;
}
if (lootSpawn.items != null) items.AddRange(lootSpawn.items);
}
sb.Clear();
sb.AppendLine(reveal.name);
sb.AppendLine("Items:");
foreach (var item in items) sb.AppendLine($"\t{item.itemDef.shortname}: {item.amount}");
Puts(sb.ToString());
}
Puts("LootContainer: {0} LootSpawn: {1} ItemModReveal: {2}", Resources.FindObjectsOfTypeAll<LootContainer>().Length, loot.Length, itemModReveal.Length);
#endif
var caseInsensitiveComparer = new CaseInsensitiveComparer();
Array.Sort(loot, (a, b) => caseInsensitiveComparer.Compare(a.name, b.name));
Array.Sort(itemModReveal, (a, b) => caseInsensitiveComparer.Compare(a.name, b.name));
Array.Sort(itemModUnwrap, (a, b) => caseInsensitiveComparer.Compare(a.name, b.name));
var spawnGroupsData = new Dictionary<string, Dictionary<string, LootContainer>>();
var spawnGroups = (List<SpawnGroup>)SpawnGroupsField.GetValue(SpawnHandler.Instance);
var monuments = Resources.FindObjectsOfTypeAll<MonumentInfo>();
var indexes = GetSpawnGroupIndexes(spawnGroups, monuments);
foreach (var spawnGroup in spawnGroups) {
var spawnGroupKey = GetSpawnGroupKey(spawnGroup, monuments, indexes);
if (spawnGroup.prefabs == null) continue;
foreach (var entry in spawnGroup.prefabs) {
var container = entry.prefab?.Get()?.GetComponent<LootContainer>();
if (container?.lootDefinition == null) continue;
Dictionary<string, LootContainer> spawnGroupData;
if (!spawnGroupsData.TryGetValue(spawnGroupKey, out spawnGroupData)) spawnGroupsData[spawnGroupKey] = spawnGroupData = new Dictionary<string, LootContainer>();
spawnGroupData[container.PrefabName] = container;
}
}
var containerData = new Dictionary<string, LootContainer>();
var allPrefabs = GameManifest.Current.pooledStrings.ToList().ConvertAll(p => p.str).Where(p => _findLoot.IsMatch(p)).ToArray();
Array.Sort(allPrefabs, (a, b) => caseInsensitiveComparer.Compare(a, b));
foreach (var strPrefab in allPrefabs) {
var container = GameManager.server.FindPrefab(strPrefab)?.GetComponent<LootContainer>();
if (container?.lootDefinition == null) continue;
containerData[strPrefab] = container;
}
/*foreach (var container in containers)
{
if (container.gameObject.activeInHierarchy || container.GetComponent<SpawnPointInstance>() != null) continue; //skip spawned & spawn groups
containerData[container.PrefabName] = container;
}*/
try {
Config.Settings = new JsonSerializerSettings {
ReferenceLoopHandling = ReferenceLoopHandling.Ignore, Converters = new List<JsonConverter> {
new ItemAmountRangedConverter(), new LootSpawnEntryConverter(), new LootContainerConverter(), new LootSpawnConverter(), new ItemModRevealConverter(), new ItemModUnwrapConverter()
}
}
;
Config.WriteObject(new ExportData {
Version = Protocol.network, VersionConfig = VersionConfig, WorldSize = World.Size, WorldSeed = World.Seed, LootContainers = containerData, SpawnGroups = spawnGroupsData.OrderBy(l => l.Key).ToDictionary(l => l.Key, l => l.Value), ItemModReveals = itemModReveal.ToDictionary(l => l.name), ItemModUnwraps = itemModUnwrap.Where(l => l.revealList != null).ToDictionary(l => l.name), Categories = loot.ToDictionary(l => l.name)
}
);
}
catch (Exception e) {
Puts("Config save failed: {0}{1}{2}", e.Message, Environment.NewLine, e.StackTrace);
return false;
}
Puts("Created new config");
return LoadConfig();
}
private bool CheckConfig() {
if (_config.Version == Protocol.network && _config.VersionConfig == VersionConfig && _config.WorldSize == World.Size && _config.WorldSeed == World.Seed) return true;
Puts("Incorrect config version({0}/{1}[{2}, {3}])", _config.Version, _config.VersionConfig, _config.WorldSize, _config.WorldSeed);
if (_config.Version > 0) Config.WriteObject(_config, false, $"{Config.Filename}.old");
return CreateDefaultConfig();
}
private void LootDump() {
var containers = Resources.FindObjectsOfTypeAll<LootContainer>();
Puts("Containers: {0}", containers.Length);
foreach (var container in containers) {
Puts("Container: {0} {1} {2}", container.name, container.PrefabName, container.GetInstanceID());
Puts("Loot: {0} {1}", container.lootDefinition.name, container.lootDefinition.GetInstanceID());
}
}
private static void PrintLootSpawn(LootSpawn lootSpawn, float parentChance, StringBuilder sb, int depth = 0) {
if (lootSpawn.subSpawn != null && lootSpawn.subSpawn.Length > 0) {
sb.Append('\t', depth);
sb.AppendLine($"{lootSpawn.name} {parentChance:P1}");
depth++;
var sum = lootSpawn.subSpawn.Sum(l => l.weight);
var cur = 0;
foreach (var entry in lootSpawn.subSpawn) {
cur += entry.weight;
PrintLootSpawn(entry.category, parentChance*(cur/(float) sum), sb, depth);
}
return;
}
if (lootSpawn.items != null && lootSpawn.items.Length > 0) {
foreach (var amount in lootSpawn.items) {
sb.Append('\t', depth);
sb.AppendLine($"{parentChance:P1} {amount.amount}x {amount.itemDef.shortname} ({lootSpawn.name})");
}
}
}
private void UpdateLoot() {
_itemsDict = ItemManager.itemList.ToDictionary(i => i.shortname);
var lootContainers = Resources.FindObjectsOfTypeAll<LootContainer>();
var lootSpawnsOld = Resources.FindObjectsOfTypeAll<LootSpawn>();
var itemModReveals = Resources.FindObjectsOfTypeAll<ItemModReveal>();
var itemModUnwraps = Resources.FindObjectsOfTypeAll<ItemModUnwrap>();
var monuments = Resources.FindObjectsOfTypeAll<MonumentInfo>();
#if DEBUG
Puts("LootContainer: {0} LootSpawn: {1} ItemModReveal: {2}", lootContainers.Length, lootSpawnsOld.Length, itemModReveals.Length);
#endif
var spawnGroups = (List<SpawnGroup>)SpawnGroupsField.GetValue(SpawnHandler.Instance);
var spawnGroupsEnabled = !spawnGroups.Any(spawnGroup => spawnGroup.prefabs.Any(entry => GameManager.server.FindPrefab(entry.prefab.Get().GetComponent<BaseNetworkable>().PrefabName) == entry.prefab.Get()));
var lootSpawns = new Dictionary<string, LootSpawn>();
var indexes = GetSpawnGroupIndexes(spawnGroups, monuments);
foreach (var lootContainer in lootContainers) {
#if DEBUG
Puts("Update LootContainer: {0} {1} {2}", lootContainer.name, lootContainer.PrefabName, lootContainer.GetInstanceID());
#endif
if (GameManager.server.FindPrefab(lootContainer.PrefabName) != lootContainer.gameObject) {
if (lootContainer.GetComponent<SpawnPointInstance>() != null) {
if (!spawnGroupsEnabled) {
UpdateLootContainer(_config.LootContainers, lootContainer, lootSpawns);
continue;
}
var spawnPointInstance = lootContainer.GetComponent<SpawnPointInstance>();
var parentSpawnGroup = (SpawnGroup)ParentSpawnGroupField.GetValue(spawnPointInstance);
Dictionary<string, LootContainerData> spawnGroupData;
if (!_config.SpawnGroups.TryGetValue(GetSpawnGroupKey(parentSpawnGroup, monuments, indexes), out spawnGroupData)) {
Puts("No spawngroup data found: {0}", GetSpawnGroupKey(parentSpawnGroup, monuments, indexes));
continue;
}
UpdateLootContainer(spawnGroupData, lootContainer, lootSpawns);
continue;
}
if (lootContainer.GetComponent<Spawnable>() == null) {
if (lootContainer.name.Equals(lootContainer.PrefabName) || lootContainer.name.Equals(Core.Utility.GetFileNameWithoutExtension(lootContainer.PrefabName))) {
#if DEBUG
var components = lootContainer.GetComponents<MonoBehaviour>();
Puts("Name: {0} Identical: {1}\tActiveP: {2}\tActiveC: {3}", lootContainer.name, GameManager.server.FindPrefab(lootContainer.PrefabName) == lootContainer.gameObject, GameManager.server.FindPrefab(lootContainer.PrefabName).activeInHierarchy, lootContainer.gameObject.activeInHierarchy);
Puts("Components: {0}", string.Join(",", components.Select(c => c.GetType().FullName).ToArray()));
Puts("Position: {0}", lootContainer.transform.position);
#endif
UpdateLootContainer(_config.LootContainers, lootContainer, lootSpawns);
}
continue;
}
}
UpdateLootContainer(_config.LootContainers, lootContainer, lootSpawns);
}
if (spawnGroupsEnabled) {
foreach (var spawnGroup in spawnGroups) {
var shouldEmpty = false;
foreach (var entry in spawnGroup.prefabs) if (entry.prefab.Get().GetComponent<LootContainer>()?.lootDefinition != null) shouldEmpty = true;
if (!shouldEmpty) continue;
Dictionary<string, LootContainerData> spawnGroupData;
if (!_config.SpawnGroups.TryGetValue(GetSpawnGroupKey(spawnGroup, monuments, indexes), out spawnGroupData)) {
Puts("No spawngroup data found: {0}", GetSpawnGroupKey(spawnGroup, monuments, indexes));
continue;
}
foreach (var entry in spawnGroup.prefabs) UpdateLootContainer(spawnGroupData, entry.prefab.Get().GetComponent<LootContainer>(), lootSpawns);
}
}
else {
Puts("No SpawnConfig loaded, skipping SpawnGroups...");
}
foreach (var reveal in itemModReveals) {
#if DEBUG
Puts("Update ItemModReveal: {0}", reveal.name);
#endif
ItemModRevealData revealConfig;
if (!_config.ItemModReveals.TryGetValue(reveal.name.Replace("(Clone)", ""), out revealConfig)) {
Puts("No reveal data found: {0}", reveal.name.Replace("(Clone)", ""));
continue;
}
var lootSpawn = GetLootSpawn(revealConfig.RevealList, lootSpawns);
if (lootSpawn == null) {
Puts("RevealList category '{0}' for '{1}' not found, skipping", revealConfig.RevealList, reveal.name.Replace("(Clone)", ""));
continue;
}
reveal.numForReveal = revealConfig.NumForReveal;
reveal.revealedItemAmount = revealConfig.RevealedItemAmount;
reveal.revealedItemOverride = GetItem(revealConfig.RevealedItemOverride);
reveal.revealList = lootSpawn;
}
foreach (var unwrap in itemModUnwraps) {
#if DEBUG
Puts("Update ItemModUnwrap: {0}", unwrap.name);
#endif
ItemModUnwrapData unwrapConfig;
if (!_config.ItemModUnwraps.TryGetValue(unwrap.name.Replace("(Clone)", ""), out unwrapConfig)) {
Puts("No reveal data found: {0}", unwrap.name.Replace("(Clone)", ""));
continue;
}
var lootSpawn = GetLootSpawn(unwrapConfig.RevealList, lootSpawns);
if (lootSpawn == null) {
Puts("RevealList category '{0}' for '{1}' not found, skipping", unwrapConfig.RevealList, unwrap.name.Replace("(Clone)", ""));
continue;
}
unwrap.revealList = lootSpawn;
}
_itemsDict = null;
foreach (var lootSpawn in lootSpawnsOld) UnityEngine.Object.Destroy(lootSpawn);
}
private void UpdateLootContainer(Dictionary<string, LootContainerData> containerData, LootContainer container, Dictionary<string, LootSpawn> lootSpawns) {
if (container == null) return;
LootContainerData containerConfig;
if (containerData == null || !containerData.TryGetValue(container.PrefabName, out containerConfig)) {
Puts("No container data found: {0}", container.PrefabName);
return;
}
container.maxDefinitionsToSpawn = containerConfig.MaxDefinitionsToSpawn;
container.minSecondsBetweenRefresh = containerConfig.MinSecondsBetweenRefresh;
container.maxSecondsBetweenRefresh = containerConfig.MaxSecondsBetweenRefresh;
container.destroyOnEmpty = containerConfig.DestroyOnEmpty;
container.lootDefinition = GetLootSpawn(containerConfig.LootDefinition, lootSpawns);
container.inventorySlots = containerConfig.InventorySlots;
container.SpawnType = containerConfig.SpawnType;
if (!container.gameObject.activeInHierarchy || container.inventory == null) return;
container.inventory.capacity = containerConfig.InventorySlots;
container.CancelInvoke("SpawnLoot");
container.SpawnLoot();
}
private LootSpawn GetLootSpawn(string lootSpawnName, Dictionary<string, LootSpawn> lootSpawns) {
LootSpawn lootSpawn;
if (lootSpawns.TryGetValue(lootSpawnName, out lootSpawn)) return lootSpawn;
LootSpawnData lootSpawnData;
if (!_config.Categories.TryGetValue(lootSpawnName, out lootSpawnData)) {
Puts("Loot category config not found: {0}", lootSpawnName);
return null;
}
lootSpawns[lootSpawnName] = lootSpawn = ScriptableObject.CreateInstance<LootSpawn>();
lootSpawn.name = lootSpawnName;
lootSpawn.items = new ItemAmountRanged[lootSpawnData.Items.Length];
lootSpawn.subSpawn = new LootSpawn.Entry[lootSpawnData.SubSpawn.Length];
FillItemAmount(lootSpawn.items, lootSpawnData.Items, lootSpawnName);
for (var i = 0; i < lootSpawnData.SubSpawn.Length; i++) {
var subSpawn = lootSpawnData.SubSpawn[i];
var category = GetLootSpawn(subSpawn.Category, lootSpawns);
lootSpawn.subSpawn[i] = new LootSpawn.Entry {
category = category, weight = subSpawn.Weight
}
;
}
return lootSpawn;
}
private void FillItemAmount(ItemAmountRanged[] amounts, ItemAmountRangedData[] amountRangedDatas, string parent) {
for (var i = 0; i < amountRangedDatas.Length; i++) {
var itemAmountData = amountRangedDatas[i];
var def = GetItem(itemAmountData.Shortname);
if (def == null) {
Puts("Item does not exist: {0} for: {1}", itemAmountData.Shortname, parent);
continue;
}
if (itemAmountData.Amount <= 0) {
Puts("Item amount too low: {0} for: {1}", itemAmountData.Shortname, parent);
continue;
}
amounts[i] = new ItemAmountRanged(def, itemAmountData.Amount, itemAmountData.MaxAmount);
}
}
private ItemDefinition GetItem(string shortname) {
if (string.IsNullOrEmpty(shortname) || _itemsDict == null) return null;
ItemDefinition item;
return _itemsDict.TryGetValue(shortname, out item) ? item : null;
}
private Vector3 FindCenter(SpawnGroup spawnGroup) {
var spawnPoints = (BaseSpawnPoint[])SpawnPointsField.GetValue(spawnGroup);
var centroid = new Vector3(0, 0, 0);
centroid = spawnPoints.Aggregate(centroid, (current, spawnPoint) => current + spawnPoint.transform.position);
centroid /= spawnPoints.Length;
return centroid;
}
private string GetSpawnGroupKey(SpawnGroup spawnGroup, MonumentInfo[] monuments, Dictionary<SpawnGroup, int> indexes) {
if (!indexes.ContainsKey(spawnGroup)) return "unkown";
var index = indexes[spawnGroup];
return $"{GetSpawnGroupId(spawnGroup, monuments)}{(index > 0 ? $"_ {
index
}
" : string.Empty)}";
}
private string GetSpawnGroupId(SpawnGroup spawnGroup, MonumentInfo[] monuments) {
var centroid = FindCenter(spawnGroup);
var monument = FindClosest(centroid, monuments);
return (monument == null ? $"{spawnGroup.name.Replace(" ", "_")}_{Id(centroid)}" : $"{Utility.GetFileNameWithoutExtension(monument.name)}_{spawnGroup.name.Replace(" ", "_")}_{Id(monument)}").ToLower();
}
private Dictionary<SpawnGroup, int> GetSpawnGroupIndexes(List<SpawnGroup> spawnGroups, MonumentInfo[] monuments) {
var monumentGroups = new Dictionary<string, List<SpawnGroup>>();
foreach (var spawnGroup in spawnGroups) {
var monument = GetSpawnGroupId(spawnGroup, monuments);
List<SpawnGroup> groups;
if (!monumentGroups.TryGetValue(monument, out groups)) monumentGroups[monument] = groups = new List<SpawnGroup>();
groups.Add(spawnGroup);
}
var indexes = new Dictionary<SpawnGroup, int>();
foreach (var monumentGroup in monumentGroups) {
monumentGroup.Value.Sort((a, b) => {
var centerA = FindCenter(a);
var centerB = FindCenter(b);
if (centerA.y < centerB.y) return -1;
if (centerA.y > centerB.y) return 1;
return 0;
}
);
for (var i = 0; i < monumentGroup.Value.Count; i++) indexes[monumentGroup.Value[i]] = i;
}
return indexes;
}
private static string Id(MonoBehaviour entity) {
if (entity == null) return "XYZ";
return Id(entity.transform.position);
}
private static string Id(Vector3 position) {
return $"X{Math.Ceiling(position.x)}Y{Math.Ceiling(position.y)}Z{Math.Ceiling(position.z)}";
}
private static MonumentInfo FindClosest(Vector3 point, MonumentInfo[] monumentInfos) {
MonumentInfo monument = null;
var distance = 9999f;
foreach (var monumentInfo in monumentInfos) {
if (!monumentInfo.gameObject.activeInHierarchy) continue;
var curDistance = Vector3.Distance(point, monumentInfo.transform.position);
if (!(curDistance < distance)) continue;
distance = curDistance;
monument = monumentInfo;
}
return monument;
}
#region Nested type: ConfigData
public class ConfigData {
public int Version {
get;
set;
}
public int VersionConfig {
get;
set;
}
public uint WorldSize {
get;
set;
}
public uint WorldSeed {
get;
set;
}
public Dictionary<string, LootContainerData> LootContainers {
get;
set;
}
= new Dictionary<string, LootContainerData>();
public Dictionary<string, Dictionary<string, LootContainerData>> SpawnGroups {
get;
set;
}
= new Dictionary<string, Dictionary<string, LootContainerData>>();
public Dictionary<string, ItemModRevealData> ItemModReveals {
get;
set;
}
= new Dictionary<string, ItemModRevealData>();
public Dictionary<string, ItemModUnwrapData> ItemModUnwraps {
get;
set;
}
= new Dictionary<string, ItemModUnwrapData>();
public Dictionary<string, LootSpawnData> Categories {
get;
set;
}
= new Dictionary<string, LootSpawnData>();
}
#endregion
#region Nested type: ExportData
public class ExportData {
public int Version {
get;
set;
}
public int VersionConfig {
get;
set;
}
public uint WorldSize {
get;
set;
}
public uint WorldSeed {
get;
set;
}
public Dictionary<string, LootContainer> LootContainers {
get;
set;
}
= new Dictionary<string, LootContainer>();
public Dictionary<string, Dictionary<string, LootContainer>> SpawnGroups {
get;
set;
}
= new Dictionary<string, Dictionary<string, LootContainer>>();
public Dictionary<string, ItemModReveal> ItemModReveals {
get;
set;
}
= new Dictionary<string, ItemModReveal>();
public Dictionary<string, ItemModUnwrap> ItemModUnwraps {
get;
set;
}
= new Dictionary<string, ItemModUnwrap>();
public Dictionary<string, LootSpawn> Categories {
get;
set;
}
= new Dictionary<string, LootSpawn>();
}
#endregion
#region Nested type: ItemAmountRangedConverter
private class ItemAmountRangedConverter : JsonConverter {
public override bool CanRead => false;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
var itemAmount = (ItemAmountRanged) value;
if (itemAmount.itemDef == null) return;
writer.WriteStartObject();
writer.WritePropertyName("Shortname");
writer.WriteValue(itemAmount.itemDef.shortname);
writer.WritePropertyName("Amount");
writer.WriteValue(itemAmount.amount);
writer.WritePropertyName("MaxAmount");
writer.WriteValue(itemAmount.maxAmount);
writer.WriteEndObject();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
return null;
}
public override bool CanConvert(Type objectType) {
return typeof (ItemAmountRanged).IsAssignableFrom(objectType);
}
}
#endregion
#region Nested type: ItemAmountRangedData
public class ItemAmountRangedData {
public string Shortname {
get;
set;
}
public float Amount {
get;
set;
}
public float MaxAmount {
get;
set;
}
= -1;
}
#endregion
#region Nested type: ItemModRevealConverter
private class ItemModRevealConverter : JsonConverter {
public override bool CanRead => false;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
var entry = (ItemModReveal) value;
writer.WriteStartObject();
writer.WritePropertyName("NumForReveal");
writer.WriteValue(entry.numForReveal);
writer.WritePropertyName("RevealedItemOverride");
writer.WriteValue(entry.revealedItemOverride?.shortname);
writer.WritePropertyName("RevealedItemAmount");
writer.WriteValue(entry.revealedItemAmount);
writer.WritePropertyName("RevealList");
writer.WriteValue(entry.revealList.name);
writer.WriteEndObject();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
return null;
}
public override bool CanConvert(Type objectType) {
return typeof (ItemModReveal).IsAssignableFrom(objectType);
}
}
#endregion
#region Nested type: ItemModRevealData
public class ItemModRevealData {
public int NumForReveal {
get;
set;
}
= 10;
public string RevealedItemOverride {
get;
set;
}
public int RevealedItemAmount {
get;
set;
}
= 1;
public string RevealList {
get;
set;
}
}
#endregion
#region Nested type: ItemModUnwrapConverter
private class ItemModUnwrapConverter : JsonConverter {
public override bool CanRead => false;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
var entry = (ItemModUnwrap)value;
writer.WriteStartObject();
writer.WritePropertyName("RevealList");
writer.WriteValue(entry.revealList.name);
writer.WriteEndObject();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
return null;
}
public override bool CanConvert(Type objectType) {
return typeof(ItemModUnwrap).IsAssignableFrom(objectType);
}
}
#endregion
#region Nested type: ItemModUnwrapData
public class ItemModUnwrapData {
public string RevealList {
get;
set;
}
}
#endregion
#region Nested type: LootContainerConverter
private class LootContainerConverter : JsonConverter {
public override bool CanRead => false;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
var container = (LootContainer) value;
writer.WriteStartObject();
writer.WritePropertyName("DestroyOnEmpty");
writer.WriteValue(container.destroyOnEmpty);
writer.WritePropertyName("LootDefinition");
writer.WriteValue(container.lootDefinition.name);
writer.WritePropertyName("MaxDefinitionsToSpawn");
writer.WriteValue(container.maxDefinitionsToSpawn);
writer.WritePropertyName("MinSecondsBetweenRefresh");
writer.WriteValue(container.minSecondsBetweenRefresh);
writer.WritePropertyName("MaxSecondsBetweenRefresh");
writer.WriteValue(container.maxSecondsBetweenRefresh);
writer.WritePropertyName("InitialLootSpawn");
writer.WriteValue(container.initialLootSpawn);
writer.WritePropertyName("SpawnType");
writer.WriteValue(container.SpawnType.ToString());
writer.WritePropertyName("InventorySlots");
writer.WriteValue(container.inventorySlots);
writer.WriteEndObject();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
return null;
}
public override bool CanConvert(Type objectType) {
return typeof (LootContainer).IsAssignableFrom(objectType);
}
}
#endregion
#region Nested type: LootContainerData
public class LootContainerData {
public bool DestroyOnEmpty {
get;
set;
}
= true;
public string LootDefinition {
get;
set;
}
public int MaxDefinitionsToSpawn {
get;
set;
}
public float MinSecondsBetweenRefresh {
get;
set;
}
= 3600f;
public float MaxSecondsBetweenRefresh {
get;
set;
}
= 7200f;
public LootContainer.spawnType SpawnType {
get;
set;
}
public int InventorySlots {
get;
set;
}
}
#endregion
#region Nested type: LootSpawnConverter
private class LootSpawnConverter : JsonConverter {
public override bool CanRead => false;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
var lootSpawn = (LootSpawn) value;
writer.WriteStartObject();
writer.WritePropertyName("Items");
serializer.Serialize(writer, lootSpawn.items);
writer.WritePropertyName("SubSpawn");
serializer.Serialize(writer, lootSpawn.subSpawn);
writer.WriteEndObject();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
return null;
}
public override bool CanConvert(Type objectType) {
return typeof (LootSpawn).IsAssignableFrom(objectType);
}
}
#endregion
#region Nested type: LootSpawnData
public class LootSpawnData {
public ItemAmountRangedData[] Items {
get;
set;
}
= new ItemAmountRangedData[0];
public LootSpawnEntryData[] SubSpawn {
get;
set;
}
= new LootSpawnEntryData[0];
}
#endregion
#region Nested type: LootSpawnEntryConverter
private class LootSpawnEntryConverter : JsonConverter {
public override bool CanRead => false;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
var entry = (LootSpawn.Entry) value;
writer.WriteStartObject();
writer.WritePropertyName("Category");
writer.WriteValue(entry.category.name);
writer.WritePropertyName("Weight");
writer.WriteValue(entry.weight);
writer.WriteEndObject();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
return null;
}
public override bool CanConvert(Type objectType) {
return typeof (LootSpawn.Entry).IsAssignableFrom(objectType);
}
}
#endregion
#region Nested type: LootSpawnEntryData
public class LootSpawnEntryData {
public string Category {
get;
set;
}
public int Weight {
get;
set;
}
}
#endregion
}
}