Decompiled source of RomesteadContentFramework v1.0.0

BepInEx/plugins/RomesteadContentFramework.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Xml;
using BepInEx;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.NET.Common;
using Candide;
using Candide.Combat;
using Candide.Data;
using Candide.Database;
using Candide.Database.Doodad;
using Candide.GameModels;
using Candide.GameModels.Controllers;
using Candide.GameModels.Managers;
using Candide.GameModels.Models.Spells;
using Candide.Graphics.VFX;
using Candide.World;
using CandideCreator.Shared;
using CandideCreator.Shared.Graphics;
using CandideCreator.Shared.Helpers;
using CandideCreator.Shared.Models;
using CandideCreator.Shared.Models.VFX;
using CandideCreator.Shared.Serialization;
using CandideCreator.Shared.Storage;
using CandideCreator.Shared.Tiled;
using CandideServer;
using CandideServer.Buildings.BuildingControllers;
using CandideServer.Citizens;
using CandideServer.Citizens.Base;
using CandideServer.Data.DataModels;
using CandideServer.Data.ServerDataSetups;
using CandideServer.Data.SharedDataSetups;
using CandideServer.DataSystem;
using CandideServer.Database;
using CandideServer.Entities;
using CandideServer.Helpers;
using CandideServer.Models;
using CandideServer.Models.Buildings;
using CandideServer.Models.Citizen;
using CandideServer.Models.Spells;
using CandideServer.Models.WorkOrders;
using CandideServer.Saving;
using CandideServer.ServerControllers;
using CandideServer.ServerManagers;
using CandideServer.ServerSystems;
using CandideServer.SimulationModels;
using CandideServer.Simulations;
using CandideServer.World;
using CandideServer.World.Generation;
using HarmonyLib;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using RomesteadContentFramework.Api;
using RomesteadContentFramework.Runtime;
using Shared.Collision;
using Shared.Combat.Projectiles;
using Shared.Combat.Spells;
using Shared.Combat.Spells.Casting;
using Shared.Combat.Spells.Parameters;
using Shared.Data;
using Shared.Data.DataModels;
using Shared.Data.Decorations;
using Shared.Data.Furniture;
using Shared.Entity;
using Shared.Entity.Components;
using Shared.Helpers;
using Shared.Messages;
using Shared.Models;
using Shared.Models.Buildings;
using Shared.Models.Construction;
using Shared.Models.Crafting;
using Shared.Models.DropTables;
using Shared.Models.Items;
using Shared.Models.Shops;
using Shared.Models.Spells;
using Shared.Text;
using Shared.World;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Romestead Content Framework")]
[assembly: AssemblyDescription("Romestead Content Framework For Romestead by Ice Box Studio")]
[assembly: AssemblyCompany("Ice Box Studio")]
[assembly: AssemblyProduct("Romestead Content Framework")]
[assembly: AssemblyCopyright("Copyright (C) 2026 Ice Box Studio All rights reserved.")]
[assembly: ComVisible(false)]
[assembly: Guid("8e19e628-4eff-442f-9b7f-f4b975d0b306")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace RomesteadContentFramework
{
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "IceBoxStudio.Romestead.RomesteadContentFramework";

		public const string PLUGIN_NAME = "Romestead Content Framework";

		public const string PLUGIN_VERSION = "1.0.0";

		public const string PLUGIN_AUTHOR = "Ice Box Studio";

		public const string PLUGIN_AUTHOR_URL = "https://steamcommunity.com/id/ibox666/";
	}
	[BepInPlugin("IceBoxStudio.Romestead.RomesteadContentFramework", "Romestead Content Framework", "1.0.0")]
	public sealed class RomesteadContentFramework : BasePlugin
	{
		private Harmony _harmony;

		public static RomesteadContentFramework Instance { get; private set; }

		internal static ManualLogSource Logger { get; private set; }

		public override void Load()
		{
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Expected O, but got Unknown
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			Instance = this;
			Logger = ((BasePlugin)this).Log;
			bool flag = default(bool);
			try
			{
				_harmony = new Harmony("IceBoxStudio.Romestead.RomesteadContentFramework");
				_harmony.PatchAll(Assembly.GetExecutingAssembly());
				RomesteadContent.ApplyAll();
				ManualLogSource logger = Logger;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(13, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("Romestead Content Framework");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" initialized.");
				}
				logger.LogInfo(val);
			}
			catch (Exception ex)
			{
				ManualLogSource logger2 = Logger;
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(24, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("Romestead Content Framework");
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" initialization error: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("\n");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.StackTrace);
				}
				logger2.LogError(val2);
			}
		}
	}
}
namespace RomesteadContentFramework.Runtime
{
	public sealed class StandardBuildingController : AbstractBuildingController
	{
		public StandardBuildingController(BuildingSimulationModel building)
			: base(building, true)
		{
			base.JobTickRate = (RomesteadContent.TryGetStandardWorkerSettings(this, out var jobTickRate, out var _) ? jobTickRate : 0.5f);
		}

		public override void OnNewlyCreated()
		{
			RomesteadContent.StandardBuildingCreated(this);
		}

		public override void OnLoaded()
		{
			RomesteadContent.StandardBuildingLoaded(this);
		}

		public override void OnBuildingRemove()
		{
			RomesteadContent.StandardBuildingRemoved(this);
			((AbstractBuildingController)this).OnBuildingRemove();
		}

		public override void OnUpgraded(ConstructionModel upgradeConstructionModel, BuildingData upgradedBuildingData)
		{
			RomesteadContent.StandardBuildingUpgraded(this, upgradeConstructionModel, upgradedBuildingData);
		}

		public override void Update(float dt)
		{
			if (RomesteadContent.TryGetStandardWorkerSettings(this, out var jobTickRate, out var _))
			{
				base.JobTickRate = jobTickRate;
				((AbstractBuildingController)this).Update(dt);
			}
		}

		protected override void OnTickJob(CitizenModel citizen, JobModel job)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Invalid comparison between Unknown and I4
			if (!RomesteadContent.TryGetStandardWorkerSettings(this, out var _, out var qualityModifier))
			{
				return;
			}
			WorkOrderModel val = JobServerManager.ApplyCurrentOrderProgress(job, JobHelper.GetJobTickForCurrentJob(citizen, base.JobTickRate), JobHelper.GetJobQualityValueTick(citizen, job, qualityModifier));
			if (!(val.CurrentProgress < val.RequiredProgress))
			{
				WorkOrderType type = val.Output.Type;
				if ((int)type == 0 || type - 3 <= 1)
				{
					((AbstractBuildingController)this).DefaultFinishCurrentWorkOrderHandle(job, citizen);
				}
				else
				{
					RomesteadContent.WarnUnsupportedStandardWorkOrder(this, ((object)Unsafe.As<WorkOrderType, WorkOrderType>(ref val.Output.Type)/*cast due to .constrained prefix*/).ToString());
				}
			}
		}
	}
}
namespace RomesteadContentFramework.Patches
{
	[HarmonyPatch(typeof(ClientDataSetup), "SetupClientData")]
	internal static class ClientDataSetupPatch
	{
		private static void Postfix()
		{
			RomesteadContent.ApplyClientContent();
		}
	}
	[HarmonyPatch(typeof(Content), "TryLoadBackUpTexture")]
	internal static class ContentTryLoadBackUpTexturePatch
	{
		private static void Postfix(string path, ref Texture2D __result)
		{
			if (__result == null && RomesteadContent.TryLoadRegisteredLooseTexture(path, out var texture))
			{
				__result = texture;
			}
		}
	}
	[HarmonyPatch(typeof(GameState), "SetupNewGameState")]
	internal static class GameStateSetupNewGameStatePatch
	{
		private static void Postfix()
		{
			RomesteadContent.ApplyPlayerRecipeUnlocks();
		}
	}
	[HarmonyPatch(typeof(WorldFlagsController), "SynchWorldFlagChanged")]
	internal static class WorldFlagsControllerSynchWorldFlagChangedPatch
	{
		private static void Postfix()
		{
			RomesteadContent.ApplyPlayerRecipeUnlocks();
		}
	}
	[HarmonyPatch(typeof(WorldFlagsController), "SyncFullGameState")]
	internal static class WorldFlagsControllerSyncFullGameStatePatch
	{
		private static void Postfix()
		{
			RomesteadContent.ApplyPlayerRecipeUnlocks();
		}
	}
	[HarmonyPatch(typeof(CitizenControllerDataBase), "GetControllerOrNullForJob", new Type[] { typeof(string) })]
	internal static class CustomJobCitizenControllerPatch
	{
		private static void Postfix(string __0, ref AbstractCitizenController __result)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Expected O, but got Unknown
			if (__result == null && RomesteadContent.IsRegisteredJob(__0))
			{
				__result = (AbstractCitizenController)new GenericServerCitizenController();
			}
		}
	}
	[HarmonyPatch(typeof(GenericServerCitizenController), "HasActiveWorkOrder", new Type[] { typeof(CitizenSlotModel) })]
	internal static class GenericServerCitizenControllerPatch
	{
		private static void Postfix(CitizenSlotModel __0, ref bool __result)
		{
			if (!__result && __0.AssociatedJobId.HasValue && ServerGameState.Jobs.TryGetValue(__0.AssociatedJobId.Value, out var value) && RomesteadContent.IsRegisteredJob(value.BaseId))
			{
				string text = value.CurrentWorkOrder?.RecipeId;
				if (!string.IsNullOrEmpty(text) && !(text == "recipe:constructing") && !(text == "recipe:repairing"))
				{
					__result = true;
				}
			}
		}
	}
	[HarmonyPatch(typeof(ItemRecipeManager), "GetLocalPlayerRecipesForStation")]
	internal static class ItemRecipeManagerGetLocalPlayerRecipesForStationPatch
	{
		private static void Postfix(HashSet<string> list, string[] stationIds)
		{
			IReadOnlyList<ItemRecipe> unlocked = RomesteadContent.Recipes.GetUnlocked();
			for (int i = 0; i < unlocked.Count; i++)
			{
				ItemRecipe val = unlocked[i];
				if (val != null && MatchesStation(val, stationIds))
				{
					list.Add(val.Id);
				}
			}
		}

		private static bool MatchesStation(ItemRecipe recipe, string[] stationIds)
		{
			if (stationIds == null)
			{
				return string.IsNullOrWhiteSpace(recipe.RequiredCraftingStation);
			}
			for (int i = 0; i < stationIds.Length; i++)
			{
				if (stationIds[i] == recipe.RequiredCraftingStation)
				{
					return true;
				}
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(ServerDataSetup), "Setup")]
	internal static class ServerDataSetupPatch
	{
		private static void Postfix()
		{
			RomesteadContent.ApplyServerContent();
		}
	}
	[HarmonyPatch(typeof(ServerWorldDataManager), "LoadMapFiles", new Type[] { })]
	internal static class ServerWorldDataManagerLoadMapFilesPatch
	{
		private static void Postfix()
		{
			RomesteadContent.MarkServerMapsReady();
			RomesteadContent.ApplyMaps();
		}
	}
	[HarmonyPatch(typeof(ServerWorldDataManager), "GetWorldDataOrNull")]
	internal static class ServerWorldDataManagerGetWorldDataOrNullPatch
	{
		private static void Postfix(string mapName, ref ServerWorldData __result)
		{
			if (__result == null && RomesteadContent.TryGetFallbackServerWorldData(mapName, out var worldData))
			{
				__result = worldData;
			}
		}
	}
	[HarmonyPatch(typeof(GameSaveManager), "LoadGame")]
	internal static class GameSaveManagerLoadGamePatch
	{
		private static void Postfix()
		{
			RomesteadContent.ApplyServerContent();
		}
	}
	[HarmonyPatch(typeof(SharedDataSetup), "Setup")]
	internal static class SharedDataSetupSetupPatch
	{
		private static void Postfix()
		{
			RomesteadContent.ApplySharedContent();
		}
	}
	[HarmonyPatch(typeof(SharedDataSetup), "SharedSetup")]
	internal static class ServerSharedDataSetupPatch
	{
		private static void Postfix()
		{
			RomesteadContent.ApplyServerSharedContent();
		}
	}
	[HarmonyPatch(typeof(LocalizationManager), "SetLocalization")]
	internal static class LocalizationManagerSetLocalizationPatch
	{
		private static void Postfix()
		{
			RomesteadContent.ApplyLocalization();
		}
	}
	[HarmonyPatch(typeof(TownServerSystem), "OnNewDay")]
	internal static class StandardBuildingBehaviorNewDayPatch
	{
		private static void Postfix()
		{
			RomesteadContent.HandleStandardBuildingNewDay();
		}
	}
	[HarmonyPatch(typeof(WorldLoader), "LoadWorld")]
	internal static class WorldLoaderPatch
	{
		private static bool Prefix(string mapName, ref World __result)
		{
			if (!RomesteadContent.TryLoadClientWorld(mapName, out var world))
			{
				return true;
			}
			__result = world;
			return false;
		}
	}
}
namespace RomesteadContentFramework.Api
{
	public static class RomesteadContent
	{
		public sealed class BuildingContentRegistry
		{
			public void RegisterStandardType(string id, string name, Action<StandardBuildingBehaviorOptions> configure)
			{
				//IL_0075: Unknown result type (might be due to invalid IL or missing references)
				//IL_007a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0081: Unknown result type (might be due to invalid IL or missing references)
				//IL_008d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0092: Unknown result type (might be due to invalid IL or missing references)
				//IL_0097: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c2: Expected O, but got Unknown
				if (string.IsNullOrWhiteSpace(id))
				{
					throw new ArgumentException("Building type id cannot be empty.", "id");
				}
				if (configure == null)
				{
					throw new ArgumentNullException("configure");
				}
				StandardBuildingBehaviorOptions standardBuildingBehaviorOptions = new StandardBuildingBehaviorOptions();
				configure(standardBuildingBehaviorOptions);
				standardBuildingBehaviorOptions.Validate(id);
				RegistrationSource registrationSource = GetRegistrationSource();
				lock (Sync)
				{
					StandardBuildingBehaviors[id] = new StandardBuildingBehaviorRegistration(id, standardBuildingBehaviorOptions.Clone(), registrationSource);
				}
				RegisterType(new BuildingTypeData
				{
					Id = id,
					Name = StringId.op_Implicit(id + "*building_type:name"),
					CreateController = (BuildingSimulationModel building) => (AbstractBuildingController)(object)new StandardBuildingController(building)
				}, name);
			}

			public void RegisterConstructionGroup(ConstructionsGroupData group)
			{
				if (group == null)
				{
					throw new ArgumentNullException("group");
				}
				if (string.IsNullOrWhiteSpace(group.Id))
				{
					throw new ArgumentException("Construction group id cannot be empty.", "group");
				}
				if (group.ConstructionIds == null)
				{
					throw new ArgumentException("Construction group must define ConstructionIds.", "group");
				}
				lock (Sync)
				{
					ConstructionGroupRegistrations[group.Id] = new ConstructionGroupRegistration(group);
				}
				if (IsSharedContentReady())
				{
					ApplyBuildings();
				}
			}

			public void RegisterConstructionResource(ConstructionResourceDataModel resource, string name = null, string description = null)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_0038: Unknown result type (might be due to invalid IL or missing references)
				//IL_0050: Unknown result type (might be due to invalid IL or missing references)
				//IL_006e: Unknown result type (might be due to invalid IL or missing references)
				if (string.IsNullOrWhiteSpace(resource.Id))
				{
					throw new ArgumentException("Construction resource id cannot be empty.", "resource");
				}
				lock (Sync)
				{
					ConstructionResourceRegistrations[resource.Id] = new ConstructionResourceRegistration(resource);
					if (!string.IsNullOrEmpty(name))
					{
						Strings[ConstructionResourceNameKey(resource.Id)] = name;
					}
					if (!string.IsNullOrEmpty(description))
					{
						Strings[ConstructionResourceDescriptionKey(resource.Id)] = description;
					}
				}
				ApplyLocalization();
				if (IsSharedContentReady())
				{
					ApplyBuildings();
				}
			}

			public void RegisterCraftingStation(CraftingStationData station, string name = null)
			{
				if (station == null)
				{
					throw new ArgumentNullException("station");
				}
				if (string.IsNullOrWhiteSpace(station.Id))
				{
					throw new ArgumentException("Crafting station id cannot be empty.", "station");
				}
				lock (Sync)
				{
					CraftingStationRegistrations[station.Id] = new CraftingStationRegistration(station);
					if (!string.IsNullOrEmpty(name))
					{
						Strings[CraftingStationNameKey(station.Id)] = name;
					}
				}
				ApplyLocalization();
				if (IsSharedContentReady())
				{
					ApplyBuildings();
				}
			}

			public void RegisterDecoration(DecorationData decoration)
			{
				if (decoration == null)
				{
					throw new ArgumentNullException("decoration");
				}
				if (string.IsNullOrWhiteSpace(decoration.Id))
				{
					throw new ArgumentException("Decoration id cannot be empty.", "decoration");
				}
				lock (Sync)
				{
					DecorationRegistrations[decoration.Id] = new DecorationRegistration(decoration);
				}
				if (IsSharedContentReady())
				{
					ApplyBuildings();
				}
			}

			public void RegisterFurniture(FurnitureData furniture, string name = null, string description = null)
			{
				//IL_009b: Unknown result type (might be due to invalid IL or missing references)
				if (furniture == null)
				{
					throw new ArgumentNullException("furniture");
				}
				if (string.IsNullOrWhiteSpace(furniture.Id))
				{
					throw new ArgumentException("Furniture id cannot be empty.", "furniture");
				}
				if (furniture.Rotations == null)
				{
					throw new ArgumentException("Furniture must define Rotations.", "furniture");
				}
				lock (Sync)
				{
					FurnitureRegistrations[furniture.Id] = new FurnitureRegistration(furniture);
					if (!string.IsNullOrEmpty(name))
					{
						Strings[FurnitureNameKey(furniture.Id)] = name;
					}
					if (!string.IsNullOrEmpty(description))
					{
						furniture.DescriptionKey = StringId.op_Implicit(FurnitureDescriptionKey(furniture.Id));
						Strings[FurnitureDescriptionKey(furniture.Id)] = description;
					}
				}
				ApplyLocalization();
				if (IsSharedContentReady())
				{
					ApplyBuildings();
				}
			}

			public void RegisterType(BuildingTypeData buildingType, string name = null)
			{
				if (buildingType == null)
				{
					throw new ArgumentNullException("buildingType");
				}
				if (string.IsNullOrWhiteSpace(buildingType.Id))
				{
					throw new ArgumentException("Building type id cannot be empty.", "buildingType");
				}
				lock (Sync)
				{
					BuildingTypeRegistrations[buildingType.Id] = new BuildingTypeRegistration(buildingType, name);
					if (!string.IsNullOrEmpty(name))
					{
						Strings[BuildingTypeNameKey(buildingType.Id)] = name;
					}
				}
				ApplyLocalization();
				if (IsSharedContentReady())
				{
					ApplyBuildings();
				}
			}

			public void RegisterBuilding(BuildingData building)
			{
				if (building == null)
				{
					throw new ArgumentNullException("building");
				}
				if (string.IsNullOrWhiteSpace(building.Id))
				{
					throw new ArgumentException("Building id cannot be empty.", "building");
				}
				if (string.IsNullOrWhiteSpace(building.BuildingTypeId))
				{
					throw new ArgumentException("Building type id cannot be empty.", "building");
				}
				ApplyStandardBuildingDefaults(building);
				lock (Sync)
				{
					BuildingRegistrations[building.Id] = new BuildingRegistration(building);
				}
				if (IsSharedContentReady())
				{
					ApplyBuildings();
				}
			}

			public void RegisterConstruction(ConstructionModel construction, string name = null, string description = null, bool unlockedByDefault = true)
			{
				RegisterConstruction(construction, delegate(ConstructionRegistrationOptions options)
				{
					options.Name = name;
					options.Description = description;
					options.UnlockedByDefault = unlockedByDefault;
				});
			}

			public void RegisterConstruction(ConstructionModel construction, Action<ConstructionRegistrationOptions> configure)
			{
				//IL_008c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0091: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
				if (construction == null)
				{
					throw new ArgumentNullException("construction");
				}
				if (configure == null)
				{
					throw new ArgumentNullException("configure");
				}
				if (string.IsNullOrWhiteSpace(construction.Id))
				{
					throw new ArgumentException("Construction id cannot be empty.", "construction");
				}
				ConstructionRegistrationOptions constructionRegistrationOptions = new ConstructionRegistrationOptions();
				configure(constructionRegistrationOptions);
				ValidateConstruction(construction);
				lock (Sync)
				{
					ConstructionRegistrations[construction.Id] = new ConstructionRegistration(construction, constructionRegistrationOptions);
					if (!string.IsNullOrEmpty(constructionRegistrationOptions.Name))
					{
						construction.Name = StringId.op_Implicit(ConstructionNameKey(construction.Id));
						Strings[ConstructionNameKey(construction.Id)] = constructionRegistrationOptions.Name;
					}
					if (!string.IsNullOrEmpty(constructionRegistrationOptions.Description))
					{
						construction.Description = StringId.op_Implicit(ConstructionDescriptionKey(construction.Id));
						Strings[ConstructionDescriptionKey(construction.Id)] = constructionRegistrationOptions.Description;
					}
					if (constructionRegistrationOptions.UnlockedByDefault)
					{
						DefaultUnlockedConstructionIds.Add(construction.Id);
					}
					else
					{
						DefaultUnlockedConstructionIds.Remove(construction.Id);
					}
				}
				ApplyLocalization();
				if (IsSharedContentReady())
				{
					ApplyBuildings();
				}
				if (IsServerContentReady())
				{
					ApplyConstructionUnlocks();
				}
			}

			public void UnlockConstruction(string constructionId)
			{
				if (string.IsNullOrWhiteSpace(constructionId))
				{
					throw new ArgumentException("Construction id cannot be empty.", "constructionId");
				}
				lock (Sync)
				{
					DefaultUnlockedConstructionIds.Add(constructionId);
				}
				if (IsServerContentReady())
				{
					ApplyConstructionUnlocks();
				}
			}

			public void LockConstruction(string constructionId)
			{
				if (string.IsNullOrWhiteSpace(constructionId))
				{
					throw new ArgumentException("Construction id cannot be empty.", "constructionId");
				}
				lock (Sync)
				{
					DefaultUnlockedConstructionIds.Remove(constructionId);
				}
			}
		}

		public sealed class StandardBuildingBehaviorOptions
		{
			private readonly List<StandardItemProduction> productions = new List<StandardItemProduction>();

			internal bool HasStorageInventory { get; private set; }

			internal bool HasOutputInventory { get; private set; }

			internal ItemFlag StorageItemFlags { get; private set; }

			internal ItemFlag OutputItemFlags { get; private set; }

			public BuildingLogisticsConfig? InputLogistics { get; set; }

			public BuildingLogisticsConfig? OutputLogistics { get; set; }

			public StandardBuildingProductionMode ProductionMode { get; private set; }

			public float WorkerJobTickRate { get; private set; } = 0.5f;

			public float WorkerQualityModifier { get; private set; } = -0.5f;

			public Action<StandardBuildingContext> OnCreated { get; set; }

			public Action<StandardBuildingContext> OnLoaded { get; set; }

			public Action<StandardBuildingContext> OnNewDay { get; set; }

			public Action<StandardBuildingUpgradeContext> OnUpgraded { get; set; }

			public Action<StandardBuildingContext> OnRemoved { get; set; }

			internal IReadOnlyList<StandardItemProduction> Productions => productions;

			public void CreateStorageInventory(ItemFlag acceptedItemFlags = (ItemFlag)0)
			{
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_001f: Unknown result type (might be due to invalid IL or missing references)
				HasStorageInventory = true;
				StorageItemFlags = acceptedItemFlags;
				if (!InputLogistics.HasValue)
				{
					InputLogistics = BuildingLogisticsConfig.CraftingBuildingDefaultInput;
				}
			}

			public void CreateOutputInventory(ItemFlag acceptedItemFlags = (ItemFlag)0)
			{
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_001f: Unknown result type (might be due to invalid IL or missing references)
				HasOutputInventory = true;
				OutputItemFlags = acceptedItemFlags;
				if (!OutputLogistics.HasValue)
				{
					OutputLogistics = BuildingLogisticsConfig.ResourceAndItemProducingDefaultOutput;
				}
			}

			public void ProduceItemDaily(string itemId, int amount = 1, int firstDayDelay = 1)
			{
				ProduceItemEveryDays(itemId, amount, 1, firstDayDelay);
			}

			public void ProduceItemEveryDays(string itemId, int amount, int everyDays, int firstDayDelay = 1)
			{
				if (ProductionMode == StandardBuildingProductionMode.WorkerJob)
				{
					throw new InvalidOperationException("Worker-job production and automatic timed production cannot be configured on the same standard building type.");
				}
				if (string.IsNullOrWhiteSpace(itemId))
				{
					throw new ArgumentException("Produced item id cannot be empty.", "itemId");
				}
				if (amount <= 0)
				{
					throw new ArgumentOutOfRangeException("amount", "Produced item amount must be greater than zero.");
				}
				if (everyDays <= 0)
				{
					throw new ArgumentOutOfRangeException("everyDays", "Production interval must be greater than zero.");
				}
				if (firstDayDelay < 0)
				{
					throw new ArgumentOutOfRangeException("firstDayDelay", "First production delay cannot be negative.");
				}
				ProductionMode = StandardBuildingProductionMode.AutomaticDaily;
				if (!HasOutputInventory)
				{
					CreateOutputInventory((ItemFlag)0);
				}
				productions.Add(new StandardItemProduction(itemId, amount, everyDays, firstDayDelay));
			}

			public void UseWorkerJobs(float jobTickRate = 0.5f, float qualityModifier = -0.5f)
			{
				if (productions.Count > 0 || ProductionMode == StandardBuildingProductionMode.AutomaticDaily)
				{
					throw new InvalidOperationException("Automatic timed production and worker-job production cannot be configured on the same standard building type.");
				}
				if (jobTickRate <= 0f)
				{
					throw new ArgumentOutOfRangeException("jobTickRate", "Worker job tick rate must be greater than zero.");
				}
				ProductionMode = StandardBuildingProductionMode.WorkerJob;
				WorkerJobTickRate = jobTickRate;
				WorkerQualityModifier = qualityModifier;
				if (!HasStorageInventory)
				{
					CreateStorageInventory((ItemFlag)0);
				}
				if (!HasOutputInventory)
				{
					CreateOutputInventory((ItemFlag)0);
				}
			}

			internal void Validate(string buildingTypeId)
			{
				if (productions.Count > 0 && !HasOutputInventory)
				{
					throw new InvalidOperationException("Standard building type '" + buildingTypeId + "' produces items but has no output inventory.");
				}
			}

			internal StandardBuildingBehaviorOptions Clone()
			{
				//IL_001f: Unknown result type (might be due to invalid IL or missing references)
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				StandardBuildingBehaviorOptions standardBuildingBehaviorOptions = new StandardBuildingBehaviorOptions();
				standardBuildingBehaviorOptions.HasStorageInventory = HasStorageInventory;
				standardBuildingBehaviorOptions.HasOutputInventory = HasOutputInventory;
				standardBuildingBehaviorOptions.StorageItemFlags = StorageItemFlags;
				standardBuildingBehaviorOptions.OutputItemFlags = OutputItemFlags;
				standardBuildingBehaviorOptions.InputLogistics = InputLogistics;
				standardBuildingBehaviorOptions.OutputLogistics = OutputLogistics;
				standardBuildingBehaviorOptions.ProductionMode = ProductionMode;
				standardBuildingBehaviorOptions.WorkerJobTickRate = WorkerJobTickRate;
				standardBuildingBehaviorOptions.WorkerQualityModifier = WorkerQualityModifier;
				standardBuildingBehaviorOptions.OnCreated = OnCreated;
				standardBuildingBehaviorOptions.OnLoaded = OnLoaded;
				standardBuildingBehaviorOptions.OnNewDay = OnNewDay;
				standardBuildingBehaviorOptions.OnUpgraded = OnUpgraded;
				standardBuildingBehaviorOptions.OnRemoved = OnRemoved;
				standardBuildingBehaviorOptions.productions.AddRange(productions);
				return standardBuildingBehaviorOptions;
			}
		}

		public enum StandardBuildingProductionMode
		{
			None,
			AutomaticDaily,
			WorkerJob
		}

		public sealed class StandardBuildingContext
		{
			public BuildingSimulationModel Building { get; }

			public BuildingInstanceModel Instance => Building.InstanceModel;

			public int Day => TimeServerSystem.Day;

			public int UpgradeLevel => ConstructionDataBase.GetConstructionOrMissing(Instance.ConstructionId).UpgradeLevel;

			public SharedInventoryModel StorageInventory
			{
				get
				{
					SharedInventoryModel result = default(SharedInventoryModel);
					if (!Instance.StorageInventoryId.HasValue || !ServerGameState.TryGetInventory(Instance.StorageInventoryId.Value, ref result))
					{
						return null;
					}
					return result;
				}
			}

			public SharedInventoryModel OutputInventory
			{
				get
				{
					SharedInventoryModel result = default(SharedInventoryModel);
					if (!Instance.OutputInventoryId.HasValue || !ServerGameState.TryGetInventory(Instance.OutputInventoryId.Value, ref result))
					{
						return null;
					}
					return result;
				}
			}

			internal StandardBuildingContext(BuildingSimulationModel building)
			{
				Building = building;
			}

			public bool TryAddOutputItem(string itemId, int amount, string auraId = null)
			{
				if (string.IsNullOrWhiteSpace(itemId))
				{
					throw new ArgumentException("Item id cannot be empty.", "itemId");
				}
				if (amount <= 0)
				{
					throw new ArgumentOutOfRangeException("amount", "Item amount must be greater than zero.");
				}
				if (!Instance.OutputInventoryId.HasValue || ItemDataBase.GetItemDataOrNull(itemId) == null)
				{
					return false;
				}
				return SimpleInventoryServerManager.TryAddItemAmounts(Instance.OutputInventoryId.Value, itemId, amount, auraId, false, (int?)null, true);
			}

			public string GetState(string key, string fallback = null)
			{
				ValidateStateKey(key);
				if (Instance.Parameters == null || !Instance.Parameters.TryGetValue("romestead_content_framework:state:" + key, out var value))
				{
					return fallback;
				}
				return value;
			}

			public void SetState(string key, string value)
			{
				ValidateStateKey(key);
				if (value == null)
				{
					throw new ArgumentNullException("value");
				}
				EnsureParameters(Instance)["romestead_content_framework:state:" + key] = value;
			}

			public bool RemoveState(string key)
			{
				ValidateStateKey(key);
				if (Instance.Parameters != null)
				{
					return Instance.Parameters.Remove("romestead_content_framework:state:" + key);
				}
				return false;
			}

			private static void ValidateStateKey(string key)
			{
				if (string.IsNullOrWhiteSpace(key))
				{
					throw new ArgumentException("State key cannot be empty.", "key");
				}
			}
		}

		public sealed class StandardBuildingUpgradeContext
		{
			public StandardBuildingContext Building { get; }

			public ConstructionModel UpgradeConstruction { get; }

			public BuildingData UpgradedBuildingData { get; }

			internal StandardBuildingUpgradeContext(BuildingSimulationModel building, ConstructionModel upgradeConstruction, BuildingData upgradedBuildingData)
			{
				Building = new StandardBuildingContext(building);
				UpgradeConstruction = upgradeConstruction;
				UpgradedBuildingData = upgradedBuildingData;
			}
		}

		private sealed class StandardBuildingBehaviorRegistration
		{
			public string Id { get; }

			public StandardBuildingBehaviorOptions Options { get; }

			public RegistrationSource Source { get; }

			public StandardBuildingBehaviorRegistration(string id, StandardBuildingBehaviorOptions options, RegistrationSource source)
			{
				Id = id;
				Options = options;
				Source = source;
			}
		}

		internal sealed class StandardItemProduction
		{
			public string ItemId { get; }

			public int Amount { get; }

			public int EveryDays { get; }

			public int FirstDayDelay { get; }

			public StandardItemProduction(string itemId, int amount, int everyDays, int firstDayDelay)
			{
				ItemId = itemId;
				Amount = amount;
				EveryDays = everyDays;
				FirstDayDelay = firstDayDelay;
			}
		}

		private sealed class ConstructionGroupRegistration
		{
			public ConstructionsGroupData Group { get; }

			public ConstructionGroupRegistration(ConstructionsGroupData group)
			{
				Group = group;
			}
		}

		private sealed class ConstructionResourceRegistration
		{
			public ConstructionResourceDataModel Resource { get; }

			public ConstructionResourceRegistration(ConstructionResourceDataModel resource)
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				Resource = resource;
			}
		}

		private sealed class CraftingStationRegistration
		{
			public CraftingStationData Station { get; }

			public CraftingStationRegistration(CraftingStationData station)
			{
				Station = station;
			}
		}

		private sealed class DecorationRegistration
		{
			public DecorationData Decoration { get; }

			public DecorationRegistration(DecorationData decoration)
			{
				Decoration = decoration;
			}
		}

		private sealed class FurnitureRegistration
		{
			public FurnitureData Furniture { get; }

			public FurnitureRegistration(FurnitureData furniture)
			{
				Furniture = furniture;
			}
		}

		public sealed class ConstructionRegistrationOptions
		{
			public string Name { get; set; }

			public string Description { get; set; }

			public bool UnlockedByDefault { get; set; } = true;
		}

		private sealed class BuildingTypeRegistration
		{
			public BuildingTypeData BuildingType { get; }

			public string Name { get; }

			public BuildingTypeRegistration(BuildingTypeData buildingType, string name)
			{
				BuildingType = buildingType;
				Name = name;
			}
		}

		private sealed class BuildingRegistration
		{
			public BuildingData Building { get; }

			public BuildingRegistration(BuildingData building)
			{
				Building = building;
			}
		}

		private sealed class ConstructionRegistration
		{
			public ConstructionModel Construction { get; }

			public string Name { get; }

			public string Description { get; }

			public bool UnlockedByDefault { get; }

			public ConstructionRegistration(ConstructionModel construction, ConstructionRegistrationOptions options)
			{
				Construction = construction;
				Name = options.Name;
				Description = options.Description;
				UnlockedByDefault = options.UnlockedByDefault;
			}
		}

		public sealed class DropTableContentRegistry
		{
			public void Register(string id, DropTableModel model)
			{
				if (string.IsNullOrWhiteSpace(id))
				{
					throw new ArgumentException("Drop table id cannot be empty.", "id");
				}
				if (model == null)
				{
					throw new ArgumentNullException("model");
				}
				lock (Sync)
				{
					DropTables[id] = new DropTableRegistration(id, model);
				}
				if (IsServerContentReady())
				{
					ApplyDropTables();
				}
			}

			public void AddItem(string dropTableId, DropTableItemSpawnModel item)
			{
				if (string.IsNullOrWhiteSpace(dropTableId))
				{
					throw new ArgumentException("Drop table id cannot be empty.", "dropTableId");
				}
				if (item == null)
				{
					throw new ArgumentNullException("item");
				}
				lock (Sync)
				{
					DropTableItems.Add(new DropTableItemRegistration(dropTableId, item));
				}
				if (IsServerContentReady())
				{
					ApplyDropTables();
				}
			}
		}

		private sealed class DropTableRegistration
		{
			public string Id { get; }

			public DropTableModel Model { get; }

			public DropTableRegistration(string id, DropTableModel model)
			{
				Id = id;
				Model = model;
			}
		}

		private sealed class DropTableItemRegistration
		{
			public string DropTableId { get; }

			public DropTableItemSpawnModel Item { get; }

			public DropTableItemRegistration(string dropTableId, DropTableItemSpawnModel item)
			{
				DropTableId = dropTableId;
				Item = item;
			}
		}

		public sealed class IconContentRegistry
		{
			public void RegisterPng(string id, string path)
			{
				Register(id, delegate(IconRegistrationOptions icon)
				{
					icon.UsePng(path);
				});
			}

			public void RegisterSpriteSheetPng(string id, string path, int spriteSize, int frame = 0)
			{
				RegisterSpriteSheetPng(id, path, spriteSize, spriteSize, frame);
			}

			public void RegisterSpriteSheetPng(string id, string path, int spriteWidth, int spriteHeight, int frame = 0)
			{
				Register(id, delegate(IconRegistrationOptions icon)
				{
					icon.UseSpriteSheetPng(path, spriteWidth, spriteHeight, frame);
				});
			}

			public void Register(string id, Action<IconRegistrationOptions> configure)
			{
				if (string.IsNullOrWhiteSpace(id))
				{
					throw new ArgumentException("Icon id cannot be empty.", "id");
				}
				if (configure == null)
				{
					throw new ArgumentNullException("configure");
				}
				IconRegistrationOptions iconRegistrationOptions = new IconRegistrationOptions();
				configure(iconRegistrationOptions);
				lock (Sync)
				{
					IconRegistrations[id] = new IconRegistration(id, iconRegistrationOptions.Clone());
				}
				if (IsClientContentReady())
				{
					ApplyIcons();
				}
			}
		}

		public sealed class IconRegistrationOptions
		{
			public IconVariantRegistration Small { get; } = new IconVariantRegistration(16, 16);

			public IconVariantRegistration Medium { get; } = new IconVariantRegistration(24, 24);

			public IconVariantRegistration Large { get; } = new IconVariantRegistration(32, 32);

			public IconVariantRegistration Huge { get; } = new IconVariantRegistration(96, 96);

			public void UsePng(string path)
			{
				Small.SetScaledFull(path, 16, 16);
				Medium.SetScaledFull(path, 24, 24);
				Large.SetScaledFull(path, 32, 32);
				Huge.SetScaledFull(path, 96, 96);
			}

			public void UseSpriteSheetPng(string path, int spriteSize, int frame = 0)
			{
				UseSpriteSheetPng(path, spriteSize, spriteSize, frame);
			}

			public void UseSpriteSheetPng(string path, int spriteWidth, int spriteHeight, int frame = 0)
			{
				Small.SetScaled(path, spriteWidth, spriteHeight, 16, 16, frame);
				Medium.SetScaled(path, spriteWidth, spriteHeight, 24, 24, frame);
				Large.SetScaled(path, spriteWidth, spriteHeight, 32, 32, frame);
				Huge.SetScaled(path, spriteWidth, spriteHeight, 96, 96, frame);
			}

			public void SetSmall(string path, int spriteWidth = 16, int spriteHeight = 16, int frame = 0)
			{
				Small.Set(path, spriteWidth, spriteHeight, frame);
			}

			public void SetMedium(string path, int spriteWidth = 24, int spriteHeight = 24, int frame = 0)
			{
				Medium.Set(path, spriteWidth, spriteHeight, frame);
			}

			public void SetLarge(string path, int spriteWidth = 32, int spriteHeight = 32, int frame = 0)
			{
				Large.Set(path, spriteWidth, spriteHeight, frame);
			}

			public void SetHuge(string path, int spriteWidth = 96, int spriteHeight = 96, int frame = 0)
			{
				Huge.Set(path, spriteWidth, spriteHeight, frame);
			}

			internal IconRegistrationOptions Clone()
			{
				IconRegistrationOptions iconRegistrationOptions = new IconRegistrationOptions();
				iconRegistrationOptions.Small.CopyFrom(Small);
				iconRegistrationOptions.Medium.CopyFrom(Medium);
				iconRegistrationOptions.Large.CopyFrom(Large);
				iconRegistrationOptions.Huge.CopyFrom(Huge);
				return iconRegistrationOptions;
			}
		}

		public sealed class IconVariantRegistration
		{
			public string Path { get; set; }

			public int SpriteWidth { get; set; }

			public int SpriteHeight { get; set; }

			public int Frame { get; set; }

			internal int TargetWidth { get; private set; }

			internal int TargetHeight { get; private set; }

			internal bool ScaleToTarget { get; private set; }

			internal bool UseFullSource { get; private set; }

			internal IconVariantRegistration(int spriteWidth, int spriteHeight)
			{
				SpriteWidth = spriteWidth;
				SpriteHeight = spriteHeight;
			}

			internal void Set(string path, int spriteWidth, int spriteHeight, int frame)
			{
				SetCore(path, spriteWidth, spriteHeight, spriteWidth, spriteHeight, frame, scaleToTarget: false, useFullSource: false);
			}

			internal void SetScaled(string path, int spriteWidth, int spriteHeight, int targetWidth, int targetHeight, int frame)
			{
				SetCore(path, spriteWidth, spriteHeight, targetWidth, targetHeight, frame, scaleToTarget: true, useFullSource: false);
			}

			internal void SetScaledFull(string path, int targetWidth, int targetHeight)
			{
				SetCore(path, targetWidth, targetHeight, targetWidth, targetHeight, 0, scaleToTarget: true, useFullSource: true);
			}

			private void SetCore(string path, int spriteWidth, int spriteHeight, int targetWidth, int targetHeight, int frame, bool scaleToTarget, bool useFullSource)
			{
				if (string.IsNullOrWhiteSpace(path))
				{
					throw new ArgumentException("Icon path cannot be empty.", "path");
				}
				if (spriteWidth <= 0)
				{
					throw new ArgumentOutOfRangeException("spriteWidth", "Icon sprite width must be greater than zero.");
				}
				if (spriteHeight <= 0)
				{
					throw new ArgumentOutOfRangeException("spriteHeight", "Icon sprite height must be greater than zero.");
				}
				if (targetWidth <= 0)
				{
					throw new ArgumentOutOfRangeException("targetWidth", "Icon target width must be greater than zero.");
				}
				if (targetHeight <= 0)
				{
					throw new ArgumentOutOfRangeException("targetHeight", "Icon target height must be greater than zero.");
				}
				if (frame < 0)
				{
					throw new ArgumentOutOfRangeException("frame", "Icon frame cannot be negative.");
				}
				Path = path;
				SpriteWidth = spriteWidth;
				SpriteHeight = spriteHeight;
				Frame = frame;
				TargetWidth = targetWidth;
				TargetHeight = targetHeight;
				ScaleToTarget = scaleToTarget;
				UseFullSource = useFullSource;
			}

			internal void CopyFrom(IconVariantRegistration other)
			{
				Path = other.Path;
				SpriteWidth = other.SpriteWidth;
				SpriteHeight = other.SpriteHeight;
				Frame = other.Frame;
				TargetWidth = other.TargetWidth;
				TargetHeight = other.TargetHeight;
				ScaleToTarget = other.ScaleToTarget;
				UseFullSource = other.UseFullSource;
			}
		}

		private sealed class IconRegistration
		{
			public string Id { get; }

			public IconRegistrationOptions Options { get; }

			public IconRegistration(string id, IconRegistrationOptions options)
			{
				Id = id;
				Options = options;
			}
		}

		public sealed class ItemContentRegistry
		{
			public void Register(string id, string name, Action<ItemData> configure)
			{
				if (string.IsNullOrWhiteSpace(id))
				{
					throw new ArgumentException("Item id cannot be empty.", "id");
				}
				if (configure == null)
				{
					throw new ArgumentNullException("configure");
				}
				RegistrationSource registrationSource = GetRegistrationSource();
				lock (Sync)
				{
					ItemRegistrations[id] = new ItemRegistration(id, name, null, configure, registrationSource);
					if (!string.IsNullOrEmpty(name))
					{
						Strings[ItemNameKey(id)] = name;
					}
				}
				LogItemRegistration(registrationSource, id);
				ApplyLocalization();
				if (IsSharedContentReady())
				{
					ApplyItems();
				}
			}

			public void Register(string id, string name, string description, Action<ItemData> configure)
			{
				if (string.IsNullOrWhiteSpace(id))
				{
					throw new ArgumentException("Item id cannot be empty.", "id");
				}
				if (configure == null)
				{
					throw new ArgumentNullException("configure");
				}
				RegistrationSource registrationSource = GetRegistrationSource();
				lock (Sync)
				{
					ItemRegistrations[id] = new ItemRegistration(id, name, description, configure, registrationSource);
					if (!string.IsNullOrEmpty(name))
					{
						Strings[ItemNameKey(id)] = name;
					}
					if (!string.IsNullOrEmpty(description))
					{
						Strings[ItemDescriptionKey(id)] = description;
					}
				}
				LogItemRegistration(registrationSource, id);
				ApplyLocalization();
				if (IsSharedContentReady())
				{
					ApplyItems();
				}
			}

			public void RegisterTombstone(string id, string name, string description = null, string icon = "sam", int maxStackSize = 99)
			{
				Register(id, name, description ?? "This item belongs to missing or removed mod content.", delegate(ItemData item)
				{
					item.Icon = (string.IsNullOrWhiteSpace(icon) ? "sam" : icon);
					item.MaxStackSize = Math.Max(1, maxStackSize);
				});
			}
		}

		private sealed class ItemRegistration
		{
			public string Id { get; }

			public string Name { get; }

			public string Description { get; }

			public Action<ItemData> Configure { get; }

			public RegistrationSource Source { get; }

			public ItemRegistration(string id, string name, string description, Action<ItemData> configure)
				: this(id, name, description, configure, new RegistrationSource("Unknown mod", "unknown", "unknown"))
			{
			}

			public ItemRegistration(string id, string name, string description, Action<ItemData> configure, RegistrationSource source)
			{
				Id = id;
				Name = name;
				Description = description;
				Configure = configure;
				Source = source;
			}
		}

		public sealed class JobContentRegistry
		{
			public void Register(JobData job, string name, string feminineName = null)
			{
				if (job == null)
				{
					throw new ArgumentNullException("job");
				}
				if (string.IsNullOrWhiteSpace(job.Id))
				{
					throw new ArgumentException("Job id cannot be empty.", "job");
				}
				if (job.MaxLevelUpgradeSteps == null || job.MaxLevelUpgradeSteps.Length == 0)
				{
					throw new ArgumentException("Job must define at least one level upgrade step.", "job");
				}
				lock (Sync)
				{
					JobRegistrations[job.Id] = new JobRegistration(job, name, feminineName ?? name);
					if (!string.IsNullOrEmpty(name))
					{
						Strings[JobNameKey(job.Id)] = name;
					}
					if (!string.IsNullOrEmpty(feminineName ?? name))
					{
						Strings[JobFeminineNameKey(job.Id)] = feminineName ?? name;
					}
				}
				ApplyLocalization();
				if (IsSharedContentReady())
				{
					ApplyJobs();
				}
			}
		}

		private sealed class JobRegistration
		{
			public JobData Job { get; }

			public string Name { get; }

			public string FeminineName { get; }

			public JobRegistration(JobData job, string name, string feminineName)
			{
				Job = job;
				Name = name;
				FeminineName = feminineName;
			}
		}

		public sealed class LocalizationContentRegistry
		{
			public void Register(string key, string text)
			{
				if (string.IsNullOrWhiteSpace(key))
				{
					throw new ArgumentException("Localization key cannot be empty.", "key");
				}
				if (text == null)
				{
					throw new ArgumentNullException("text");
				}
				lock (Sync)
				{
					Strings[key] = text;
				}
				ApplyLocalization();
			}
		}

		private readonly struct RegistrationSource
		{
			public string Name { get; }

			public string Guid { get; }

			public string AssemblyName { get; }

			public string DisplayName
			{
				get
				{
					if (!string.IsNullOrWhiteSpace(Guid))
					{
						string.Equals(Name, Guid, StringComparison.Ordinal);
					}
					return Name;
				}
			}

			public RegistrationSource(string name, string guid, string assemblyName)
			{
				Name = (string.IsNullOrWhiteSpace(name) ? assemblyName : name);
				Guid = (string.IsNullOrWhiteSpace(guid) ? assemblyName : guid);
				AssemblyName = assemblyName;
			}
		}

		public sealed class MapContentRegistry
		{
			public void Register(string id, string cmxPath, string tmxPath)
			{
				Register(id, delegate(MapRegistrationOptions options)
				{
					options.CmxPath = cmxPath;
					options.TmxPath = tmxPath;
				});
			}

			public void Register(string id, Action<MapRegistrationOptions> configure)
			{
				if (string.IsNullOrWhiteSpace(id))
				{
					throw new ArgumentException("Map id cannot be empty.", "id");
				}
				if (configure == null)
				{
					throw new ArgumentNullException("configure");
				}
				MapRegistrationOptions mapRegistrationOptions = new MapRegistrationOptions();
				configure(mapRegistrationOptions);
				mapRegistrationOptions.Normalize();
				string text = NormalizeMapId(id);
				ValidateMapRegistration(text, mapRegistrationOptions);
				lock (Sync)
				{
					MapRegistrations[text] = new MapRegistration(text, mapRegistrationOptions.Clone());
				}
				ClearClientExteriorWorldCache(text);
				if (AreServerMapsReady())
				{
					ApplyMaps();
				}
			}
		}

		public sealed class MapRegistrationOptions
		{
			public string CmxPath { get; set; }

			public string TmxPath { get; set; }

			public string ContentRoot { get; set; }

			internal void Normalize()
			{
				CmxPath = NormalizePath(CmxPath);
				TmxPath = NormalizePath(TmxPath);
				ContentRoot = NormalizePath(ContentRoot);
			}

			internal MapRegistrationOptions Clone()
			{
				return new MapRegistrationOptions
				{
					CmxPath = CmxPath,
					TmxPath = TmxPath,
					ContentRoot = ContentRoot
				};
			}
		}

		private sealed class MapRegistration
		{
			public string Id { get; }

			public string CmxPath { get; }

			public string TmxPath { get; }

			public string ContentRoot { get; }

			public MapRegistration(string id, MapRegistrationOptions options)
			{
				Id = id;
				CmxPath = options.CmxPath;
				TmxPath = options.TmxPath;
				ContentRoot = options.ContentRoot;
			}
		}

		public sealed class ItemRecipeContentRegistry
		{
			public void Register(ItemRecipe recipe, bool unlockedByDefault = true)
			{
				RegisterCore(recipe, unlockedByDefault, null);
			}

			public void Register(ItemRecipe recipe, Action<ItemRecipeRegistrationOptions> configure)
			{
				if (configure == null)
				{
					throw new ArgumentNullException("configure");
				}
				ItemRecipeRegistrationOptions itemRecipeRegistrationOptions = new ItemRecipeRegistrationOptions();
				configure(itemRecipeRegistrationOptions);
				RegisterCore(recipe, itemRecipeRegistrationOptions.UnlockedByDefault, itemRecipeRegistrationOptions.UnlockConditions);
			}

			public bool Unlock(string recipeId)
			{
				return SetUnlocked(recipeId, unlocked: true);
			}

			public int UnlockMany(params string[] recipeIds)
			{
				return SetUnlockedMany(recipeIds, unlocked: true);
			}

			public bool Lock(string recipeId)
			{
				return SetUnlocked(recipeId, unlocked: false);
			}

			public int LockMany(params string[] recipeIds)
			{
				return SetUnlockedMany(recipeIds, unlocked: false);
			}

			public bool IsUnlocked(string recipeId)
			{
				if (string.IsNullOrWhiteSpace(recipeId))
				{
					return false;
				}
				lock (Sync)
				{
					ItemRecipeRegistration value;
					return ItemRecipes.TryGetValue(recipeId, out value) && IsRecipeUnlocked(value);
				}
			}

			public IReadOnlyList<ItemRecipe> GetUnlocked()
			{
				lock (Sync)
				{
					List<ItemRecipe> list = new List<ItemRecipe>();
					foreach (ItemRecipeRegistration value in ItemRecipes.Values)
					{
						if (IsRecipeUnlocked(value))
						{
							list.Add(value.Recipe);
						}
					}
					return list;
				}
			}

			public void RefreshUnlocks()
			{
				ApplyPlayerRecipeUnlocks();
			}

			private static void RegisterCore(ItemRecipe recipe, bool unlockedByDefault, IReadOnlyList<Func<bool>> unlockConditions)
			{
				if (recipe == null)
				{
					throw new ArgumentNullException("recipe");
				}
				if (string.IsNullOrWhiteSpace(recipe.Id))
				{
					throw new ArgumentException("Recipe id cannot be empty.", "recipe");
				}
				RegistrationSource registrationSource = GetRegistrationSource();
				lock (Sync)
				{
					ItemRecipes[recipe.Id] = new ItemRecipeRegistration(recipe, unlockedByDefault, unlockConditions, registrationSource);
				}
				if (IsSharedContentReady())
				{
					ApplyItemRecipes();
				}
			}

			private static bool SetUnlocked(string recipeId, bool unlocked)
			{
				if (string.IsNullOrWhiteSpace(recipeId))
				{
					throw new ArgumentException("Recipe id cannot be empty.", "recipeId");
				}
				bool flag;
				lock (Sync)
				{
					if (!ItemRecipes.TryGetValue(recipeId, out var value))
					{
						LogWarning($"Cannot {(unlocked ? "unlock" : "lock")} missing recipe '{recipeId}'.");
						return false;
					}
					flag = value.UnlockOverride != unlocked;
					value.UnlockOverride = unlocked;
				}
				if (flag)
				{
					ApplyPlayerRecipeUnlocks();
				}
				return flag;
			}

			private static int SetUnlockedMany(string[] recipeIds, bool unlocked)
			{
				if (recipeIds == null)
				{
					throw new ArgumentNullException("recipeIds");
				}
				int num = 0;
				for (int i = 0; i < recipeIds.Length; i++)
				{
					if (SetUnlocked(recipeIds[i], unlocked))
					{
						num++;
					}
				}
				return num;
			}
		}

		public sealed class ItemRecipeRegistrationOptions
		{
			private readonly List<Func<bool>> unlockConditions = new List<Func<bool>>();

			public bool UnlockedByDefault { get; set; } = true;

			internal IReadOnlyList<Func<bool>> UnlockConditions => unlockConditions;

			public void UnlockWhen(Func<bool> condition)
			{
				if (condition == null)
				{
					throw new ArgumentNullException("condition");
				}
				unlockConditions.Add(condition);
			}

			public void UnlockWhenWorldFlag(string flagName)
			{
				if (string.IsNullOrWhiteSpace(flagName))
				{
					throw new ArgumentException("World flag cannot be empty.", "flagName");
				}
				UnlockWhen(() => GameState.WorldFlags != null && WorldFlagsHelper.HasFlag(GameState.WorldFlags, flagName));
			}

			public void UnlockWhenWorldFlagIntAtLeast(string flagName, int value)
			{
				if (string.IsNullOrWhiteSpace(flagName))
				{
					throw new ArgumentException("World flag cannot be empty.", "flagName");
				}
				UnlockWhen(() => GameState.WorldFlags != null && WorldFlagsHelper.GetIntValue(GameState.WorldFlags, flagName, 0) >= value);
			}

			public void UnlockWhenWorldFlagIntEquals(string flagName, int value)
			{
				if (string.IsNullOrWhiteSpace(flagName))
				{
					throw new ArgumentException("World flag cannot be empty.", "flagName");
				}
				UnlockWhen(() => GameState.WorldFlags != null && WorldFlagsHelper.GetIntValue(GameState.WorldFlags, flagName, 0) == value);
			}

			public void UnlockWhenWorldFlagFloatAtLeast(string flagName, float value)
			{
				if (string.IsNullOrWhiteSpace(flagName))
				{
					throw new ArgumentException("World flag cannot be empty.", "flagName");
				}
				UnlockWhen(() => GameState.WorldFlags != null && WorldFlagsHelper.GetFloatValue(GameState.WorldFlags, flagName, 0f) >= value);
			}
		}

		private sealed class ItemRecipeRegistration
		{
			public ItemRecipe Recipe { get; }

			public bool UnlockedByDefault { get; }

			public bool? UnlockOverride { get; set; }

			public IReadOnlyList<Func<bool>> UnlockConditions { get; }

			public RegistrationSource Source { get; }

			public ItemRecipeRegistration(ItemRecipe recipe, bool unlocked, IReadOnlyList<Func<bool>> unlockConditions)
				: this(recipe, unlocked, unlockConditions, new RegistrationSource("Unknown mod", "unknown", "unknown"))
			{
			}

			public ItemRecipeRegistration(ItemRecipe recipe, bool unlocked, IReadOnlyList<Func<bool>> unlockConditions, RegistrationSource source)
			{
				Recipe = recipe;
				UnlockedByDefault = unlocked;
				IReadOnlyList<Func<bool>> readOnlyList2;
				if (unlockConditions != null)
				{
					IReadOnlyList<Func<bool>> readOnlyList = new List<Func<bool>>(unlockConditions);
					readOnlyList2 = readOnlyList;
				}
				else
				{
					IReadOnlyList<Func<bool>> readOnlyList = Array.Empty<Func<bool>>();
					readOnlyList2 = readOnlyList;
				}
				UnlockConditions = readOnlyList2;
				Source = source;
			}
		}

		public sealed class ShopContentRegistry
		{
			public void Register(Shop shop)
			{
				if (shop == null)
				{
					throw new ArgumentNullException("shop");
				}
				if (string.IsNullOrWhiteSpace(shop.Id))
				{
					throw new ArgumentException("Shop id cannot be empty.", "shop");
				}
				lock (Sync)
				{
					ShopRegistrations[shop.Id] = new ShopRegistration(shop);
				}
				if (IsSharedContentReady())
				{
					ApplyShops();
				}
			}

			public void AddItem(string shopId, string itemId)
			{
				if (string.IsNullOrWhiteSpace(shopId))
				{
					throw new ArgumentException("Shop id cannot be empty.", "shopId");
				}
				if (string.IsNullOrWhiteSpace(itemId))
				{
					throw new ArgumentException("Item id cannot be empty.", "itemId");
				}
				lock (Sync)
				{
					ShopItems.Add(new ShopItemRegistration(shopId, itemId));
				}
				if (IsSharedContentReady())
				{
					ApplyShops();
				}
			}
		}

		private sealed class ShopRegistration
		{
			public Shop Shop { get; }

			public ShopRegistration(Shop shop)
			{
				Shop = shop;
			}
		}

		private sealed class ShopItemRegistration
		{
			public string ShopId { get; }

			public string ItemId { get; }

			public ShopItemRegistration(string shopId, string itemId)
			{
				ShopId = shopId;
				ItemId = itemId;
			}
		}

		public sealed class SpellContentRegistry
		{
			public void RegisterEffect(string id, string displayName, Action<CustomEffectRegistrationOptions> configure)
			{
				if (string.IsNullOrWhiteSpace(id))
				{
					throw new ArgumentException("Spell id cannot be empty.", "id");
				}
				if (configure == null)
				{
					throw new ArgumentNullException("configure");
				}
				CustomEffectRegistrationOptions customEffectRegistrationOptions = new CustomEffectRegistrationOptions();
				configure(customEffectRegistrationOptions);
				lock (Sync)
				{
					SpellRegistrations[id] = new SpellRegistration(id, displayName, customEffectRegistrationOptions.Clone());
					if (!string.IsNullOrEmpty(displayName))
					{
						Strings[SpellNameKey(id)] = displayName;
					}
				}
				ApplyLocalization();
				if (IsSharedContentReady())
				{
					ApplySpells();
				}
				if (IsClientContentReady())
				{
					ApplyClientSpells();
				}
				if (IsServerContentReady())
				{
					ApplyServerSpells();
				}
			}
		}

		public sealed class CustomEffectRegistrationOptions
		{
			public Func<CustomClientEffectContext, CanCastSpellResult> CanCastClient { get; set; }

			public Action<CustomClientEffectContext> OnClientCast { get; set; }

			public Func<CustomServerEffectContext, CanCastSpellResult> CanCastServer { get; set; }

			public Action<CustomServerEffectContext> OnServerCast { get; set; }

			public string CastSoundEffect { get; set; }

			public float SpellDuration { get; set; }

			internal CustomEffectRegistrationOptions Clone()
			{
				return new CustomEffectRegistrationOptions
				{
					CanCastClient = CanCastClient,
					OnClientCast = OnClientCast,
					CanCastServer = CanCastServer,
					OnServerCast = OnServerCast,
					CastSoundEffect = CastSoundEffect,
					SpellDuration = SpellDuration
				};
			}
		}

		public readonly struct CustomClientEffectContext
		{
			public SpellCastingContext Context { get; }

			public CastSpellArgs CastSpellArgs { get; }

			internal CustomClientEffectContext(SpellCastingContext context, CastSpellArgs castSpellArgs)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				Context = context;
				CastSpellArgs = castSpellArgs;
			}
		}

		public readonly struct CustomServerEffectContext
		{
			public ServerSpellCastingContext Context { get; }

			public CastSpellArgs CastSpellArgs { get; }

			internal CustomServerEffectContext(ServerSpellCastingContext context, CastSpellArgs castSpellArgs)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				Context = context;
				CastSpellArgs = castSpellArgs;
			}
		}

		private sealed class CustomClientEffectSpell : AbstractSpell
		{
			public override CanCastSpellResult CanCast(SpellCastingContext context)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_005f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0062: Unknown result type (might be due to invalid IL or missing references)
				//IL_002e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0035: Unknown result type (might be due to invalid IL or missing references)
				//IL_003a: Unknown result type (might be due to invalid IL or missing references)
				SpellRegistration spellRegistration = GetSpellRegistration(context.SpellTypeArgs);
				if (spellRegistration == null)
				{
					LogWarning("Cannot cast missing custom client effect.");
					return (CanCastSpellResult)1;
				}
				Func<CustomClientEffectContext, CanCastSpellResult> canCastClient = spellRegistration.Options.CanCastClient;
				if (canCastClient == null)
				{
					return (CanCastSpellResult)0;
				}
				try
				{
					return canCastClient(new CustomClientEffectContext(context, null));
				}
				catch (Exception ex)
				{
					LogWarning("Custom client effect '" + spellRegistration.Id + "' CanCast failed: " + ex.Message);
					return (CanCastSpellResult)2;
				}
			}

			protected override void Cast(ClientProjectileSystem projectileSystem, SpellCastingContext context, CastSpellArgs castSpellArgs)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				SpellRegistration spellRegistration = GetSpellRegistration(context.SpellTypeArgs);
				if (spellRegistration == null)
				{
					return;
				}
				Action<CustomClientEffectContext> onClientCast = spellRegistration.Options.OnClientCast;
				if (onClientCast == null)
				{
					return;
				}
				try
				{
					onClientCast(new CustomClientEffectContext(context, castSpellArgs));
				}
				catch (Exception ex)
				{
					LogWarning("Custom client effect '" + spellRegistration.Id + "' failed: " + ex.Message);
				}
			}
		}

		private sealed class CustomServerEffectSpell : AbstractServerSpell
		{
			public override CanCastSpellResult CanCast(ServerSpellCastingContext context)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0064: Unknown result type (might be due to invalid IL or missing references)
				//IL_0067: Unknown result type (might be due to invalid IL or missing references)
				//IL_0033: Unknown result type (might be due to invalid IL or missing references)
				//IL_003a: Unknown result type (might be due to invalid IL or missing references)
				//IL_003f: Unknown result type (might be due to invalid IL or missing references)
				SpellRegistration spellRegistration = GetSpellRegistration(context.Context.SpellTypeArgs);
				if (spellRegistration == null)
				{
					LogWarning("Cannot cast missing custom server effect.");
					return (CanCastSpellResult)1;
				}
				Func<CustomServerEffectContext, CanCastSpellResult> canCastServer = spellRegistration.Options.CanCastServer;
				if (canCastServer == null)
				{
					return (CanCastSpellResult)0;
				}
				try
				{
					return canCastServer(new CustomServerEffectContext(context, null));
				}
				catch (Exception ex)
				{
					LogWarning("Custom server effect '" + spellRegistration.Id + "' CanCast failed: " + ex.Message);
					return (CanCastSpellResult)2;
				}
			}

			protected override void DoCast(ProjectileSystem projectileSystem, ServerSpellCastingContext context, CastSpellArgs castSpellArgs)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				SpellRegistration spellRegistration = GetSpellRegistration(context.Context.SpellTypeArgs);
				if (spellRegistration == null)
				{
					return;
				}
				Action<CustomServerEffectContext> onServerCast = spellRegistration.Options.OnServerCast;
				if (onServerCast == null)
				{
					return;
				}
				try
				{
					onServerCast(new CustomServerEffectContext(context, castSpellArgs));
				}
				catch (Exception ex)
				{
					LogWarning("Custom server effect '" + spellRegistration.Id + "' failed: " + ex.Message);
				}
			}
		}

		private sealed class SpellRegistration
		{
			public string Id { get; }

			public string DisplayName { get; }

			public CustomEffectRegistrationOptions Options { get; }

			public SpellRegistration(string id, string displayName, CustomEffectRegistrationOptions options)
			{
				Id = id;
				DisplayName = displayName;
				Options = options;
			}
		}

		public sealed class VfxContentRegistry
		{
			public void RegisterSpriteSheetPng(string id, string path, int spriteSize, int frameCount, int frameDuration = 2)
			{
				RegisterSpriteSheetPng(id, path, spriteSize, spriteSize, frameCount, frameDuration);
			}

			public void RegisterSpriteSheetPng(string id, string path, int spriteWidth, int spriteHeight, int frameCount, int frameDuration = 2)
			{
				Register(id, delegate(VfxRegistrationOptions vfx)
				{
					vfx.UseSpriteSheetPng(path, spriteWidth, spriteHeight, frameCount, frameDuration);
				});
			}

			public void Register(string id, Action<VfxRegistrationOptions> configure)
			{
				if (string.IsNullOrWhiteSpace(id))
				{
					throw new ArgumentException("VFX id cannot be empty.", "id");
				}
				if (configure == null)
				{
					throw new ArgumentNullException("configure");
				}
				VfxRegistrationOptions vfxRegistrationOptions = new VfxRegistrationOptions();
				configure(vfxRegistrationOptions);
				lock (Sync)
				{
					VfxRegistrations[id] = new VfxRegistration(id, vfxRegistrationOptions.Clone());
				}
				if (IsClientContentReady())
				{
					ApplyVfx();
				}
			}

			public void Play(string id, Vector3 position, float angle = 0f, float scale = 1f, SpriteEffects spriteEffects = (SpriteEffects)0)
			{
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				VfxSpritesAnimationModel animation = GetAnimation(id);
				if (!(animation == (VfxSpritesAnimationModel)null))
				{
					VfxPlayer.PlayAnimation(animation, position, angle, scale, spriteEffects);
				}
			}

			public void Play(string id, EntityWrapper target, float angle = 0f, float scale = 1f, SpriteEffects spriteEffects = (SpriteEffects)0)
			{
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				VfxSpritesAnimationModel animation = GetAnimation(id);
				if (!(animation == (VfxSpritesAnimationModel)null))
				{
					VfxPlayer.PlayAnimation(animation, target, angle, scale, spriteEffects);
				}
			}

			private static VfxSpritesAnimationModel GetAnimation(string id)
			{
				if (string.IsNullOrWhiteSpace(id))
				{
					throw new ArgumentException("VFX id cannot be empty.", "id");
				}
				VfxSpritesAnimationModel vfxSpritesAnimationOrNull = VfxSpritesAnimationDataBase.GetVfxSpritesAnimationOrNull(id);
				if (vfxSpritesAnimationOrNull == (VfxSpritesAnimationModel)null && IsClientContentReady())
				{
					ApplyVfx();
					vfxSpritesAnimationOrNull = VfxSpritesAnimationDataBase.GetVfxSpritesAnimationOrNull(id);
				}
				if (vfxSpritesAnimationOrNull == (VfxSpritesAnimationModel)null)
				{
					LogWarning("Cannot play missing VFX animation '" + id + "'.");
				}
				return vfxSpritesAnimationOrNull;
			}
		}

		public sealed class VfxRegistrationOptions
		{
			public string Path { get; set; }

			public int SpriteWidth { get; set; } = 32;

			public int SpriteHeight { get; set; } = 32;

			public int FirstFrame { get; set; }

			public int FrameCount { get; set; } = 1;

			public int FrameDuration { get; set; } = 2;

			public float Scale { get; set; } = 1f;

			public float Opacity { get; set; } = 1f;

			public Vector3 Offset { get; set; } = Vector3.Zero;

			public bool Is3D { get; set; }

			public bool IsHorizontalPlane { get; set; }

			public void UseSpriteSheetPng(string path, int spriteSize, int frameCount, int frameDuration = 2)
			{
				UseSpriteSheetPng(path, spriteSize, spriteSize, frameCount, frameDuration);
			}

			public void UseSpriteSheetPng(string path, int spriteWidth, int spriteHeight, int frameCount, int frameDuration = 2)
			{
				if (string.IsNullOrWhiteSpace(path))
				{
					throw new ArgumentException("VFX path cannot be empty.", "path");
				}
				if (spriteWidth <= 0)
				{
					throw new ArgumentOutOfRangeException("spriteWidth", "VFX sprite width must be greater than zero.");
				}
				if (spriteHeight <= 0)
				{
					throw new ArgumentOutOfRangeException("spriteHeight", "VFX sprite height must be greater than zero.");
				}
				if (frameCount <= 0)
				{
					throw new ArgumentOutOfRangeException("frameCount", "VFX frame count must be greater than zero.");
				}
				if (frameDuration <= 0)
				{
					throw new ArgumentOutOfRangeException("frameDuration", "VFX frame duration must be greater than zero.");
				}
				Path = path;
				SpriteWidth = spriteWidth;
				SpriteHeight = spriteHeight;
				FrameCount = frameCount;
				FrameDuration = frameDuration;
			}

			internal VfxRegistrationOptions Clone()
			{
				//IL_0067: Unknown result type (might be due to invalid IL or missing references)
				return new VfxRegistrationOptions
				{
					Path = Path,
					SpriteWidth = SpriteWidth,
					SpriteHeight = SpriteHeight,
					FirstFrame = FirstFrame,
					FrameCount = FrameCount,
					FrameDuration = FrameDuration,
					Scale = Scale,
					Opacity = Opacity,
					Offset = Offset,
					Is3D = Is3D,
					IsHorizontalPlane = IsHorizontalPlane
				};
			}
		}

		private sealed class VfxRegistration
		{
			public string Id { get; }

			public VfxRegistrationOptions Options { get; }

			public VfxRegistration(string id, VfxRegistrationOptions options)
			{
				Id = id;
				Options = options;
			}
		}

		public sealed class WorkRecipeContentRegistry
		{
			public void Register(WorkRecipeModel recipe, string name = null, string description = null)
			{
				WorkRecipeRegistrationOptions options = new WorkRecipeRegistrationOptions
				{
					Name = name,
					Description = description
				};
				RegisterCore(recipe, options);
			}

			public void Register(WorkRecipeModel recipe, Action<WorkRecipeRegistrationOptions> configure)
			{
				if (configure == null)
				{
					throw new ArgumentNullException("configure");
				}
				WorkRecipeRegistrationOptions workRecipeRegistrationOptions = new WorkRecipeRegistrationOptions();
				configure(workRecipeRegistrationOptions);
				RegisterCore(recipe, workRecipeRegistrationOptions);
			}

			private static void RegisterCore(WorkRecipeModel recipe, WorkRecipeRegistrationOptions options)
			{
				//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
				//IL_0102: Unknown result type (might be due to invalid IL or missing references)
				if (recipe == null)
				{
					throw new ArgumentNullException("recipe");
				}
				if (string.IsNullOrWhiteSpace(recipe.Id))
				{
					throw new ArgumentException("Work recipe id cannot be empty.", "recipe");
				}
				if (options.LevelRequirement.HasValue)
				{
					if (options.LevelRequirement.Value < 0)
					{
						throw new ArgumentOutOfRangeException("options", "Work recipe level requirement cannot be negative.");
					}
					recipe.LevelRequirement = options.LevelRequirement.Value;
				}
				lock (Sync)
				{
					WorkRecipeRegistrations[recipe.Id] = new WorkRecipeRegistration(recipe, options);
					if (!string.IsNullOrEmpty(options.Name))
					{
						recipe.Name = StringId.op_Implicit(recipe.Id + "*work_recipe:name");
						Strings[recipe.Id + "*work_recipe:name"] = options.Name;
					}
					if (!string.IsNullOrEmpty(options.Description))
					{
						recipe.Description = StringId.op_Implicit(recipe.Id + "*work_recipe:description");
						Strings[recipe.Id + "*work_recipe:description"] = options.Description;
					}
				}
				ApplyLocalization();
				if (IsSharedContentReady())
				{
					ApplyWorkRecipes();
				}
				if (AreWorkRecipeGroupsReady())
				{
					ApplyWorkRecipeGroups();
				}
				if (IsServerContentReady())
				{
					ApplyWorkRecipeUnlocks();
				}
			}
		}

		public sealed class WorkRecipeRegistrationOptions
		{
			private readonly List<string> unlockJobIds = new List<string>();

			private readonly List<WorkRecipeJobLevelGroup> jobLevelGroups = new List<WorkRecipeJobLevelGroup>();

			public string Name { get; set; }

			public string Description { get; set; }

			public int? LevelRequirement { get; set; }

			internal IReadOnlyList<string> UnlockJobIds => unlockJobIds;

			internal IReadOnlyList<WorkRecipeJobLevelGroup> JobLevelGroups => jobLevelGroups;

			public void AddToJobGroup(string jobId, int groupLevel, WorkRecipePlacement placement = null)
			{
				if (string.IsNullOrWhiteSpace(jobId))
				{
					throw new ArgumentException("Job id cannot be empty.", "jobId");
				}
				if (groupLevel <= 0)
				{
					throw new ArgumentOutOfRangeException("groupLevel", "Work recipe group level must be greater than zero.");
				}
				WorkRecipeJobLevelGroup item = new WorkRecipeJobLevelGroup(jobId, groupLevel, placement ?? WorkRecipePlacement.End);
				if (!jobLevelGroups.Contains(item))
				{
					jobLevelGroups.Add(item);
				}
			}

			public void UnlockForJob(string jobId)
			{
				if (string.IsNullOrWhiteSpace(jobId))
				{
					throw new ArgumentException("Job id cannot be empty.", "jobId");
				}
				if (!unlockJobIds.Contains(jobId))
				{
					unlockJobIds.Add(jobId);
				}
			}
		}

		public sealed class WorkRecipePlacement
		{
			public static WorkRecipePlacement End { get; } = new WorkRecipePlacement(WorkRecipePlacementKind.End, null);

			public static WorkRecipePlacement Start { get; } = new WorkRecipePlacement(WorkRecipePlacementKind.Start, null);

			internal WorkRecipePlacementKind Kind { get; }

			internal string AnchorRecipeId { get; }

			private WorkRecipePlacement(WorkRecipePlacementKind kind, string anchorRecipeId)
			{
				Kind = kind;
				AnchorRecipeId = anchorRecipeId;
			}

			public static WorkRecipePlacement Before(string recipeId)
			{
				if (string.IsNullOrWhiteSpace(recipeId))
				{
					throw new ArgumentException("Anchor recipe id cannot be empty.", "recipeId");
				}
				return new WorkRecipePlacement(WorkRecipePlacementKind.Before, recipeId);
			}

			public static WorkRecipePlacement After(string recipeId)
			{
				if (string.IsNullOrWhiteSpace(recipeId))
				{
					throw new ArgumentException("Anchor recipe id cannot be empty.", "recipeId");
				}
				return new WorkRecipePlacement(WorkRecipePlacementKind.After, recipeId);
			}

			public override bool Equals(object obj)
			{
				if (obj is WorkRecipePlacement workRecipePlacement && Kind == workRecipePlacement.Kind)
				{
					return string.Equals(AnchorRecipeId, workRecipePlacement.AnchorRecipeId, StringComparison.Ordinal);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return ((int)Kind * 397) ^ ((AnchorRecipeId != null) ? StringComparer.Ordinal.GetHashCode(AnchorRecipeId) : 0);
			}
		}

		internal enum WorkRecipePlacementKind
		{
			End,
			Start,
			Before,
			After
		}

		internal readonly struct WorkRecipeJobLevelGroup : IEquatable<WorkRecipeJobLevelGroup>
		{
			public string JobId { get; }

			public int Level { get; }

			public WorkRecipePlacement Placement { get; }

			public WorkRecipeJobLevelGroup(string jobId, int level, WorkRecipePlacement placement)
			{
				JobId = jobId;
				Level = level;
				Placement = placement;
			}

			public string GetGroupId()
			{
				return $"{JobId}:{Level}";
			}

			public bool Equals(WorkRecipeJobLevelGroup other)
			{
				if (string.Equals(JobId, other.JobId, StringComparison.Ordinal) && Level == other.Level)
				{
					return Placement.Equals(other.Placement);
				}
				return false;
			}

			public override bool Equals(object obj)
			{
				if (obj is WorkRecipeJobLevelGroup other)
				{
					return Equals(other);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return (((((JobId != null) ? StringComparer.Ordinal.GetHashCode(JobId) : 0) * 397) ^ Level) * 397) ^ Placement.GetHashCode();
			}
		}

		private readonly struct WorkRecipeJobUnlock
		{
			public string RecipeId { get; }

			public string JobId { get; }

			public WorkRecipeJobUnlock(string recipeId, string jobId)
			{
				RecipeId = recipeId;
				JobId = jobId;
			}
		}

		private sealed class WorkRecipeRegistration
		{
			public WorkRecipeModel Recipe { get; }

			public string Name { get; }

			public string Description { get; }

			public IReadOnlyList<string> UnlockJobIds { get; }

			public IReadOnlyList<WorkRecipeJobLevelGroup> JobGroups { get; }

			public WorkRecipeRegistration(WorkRecipeModel recipe, WorkRecipeRegistrationOptions options)
			{
				Recipe = recipe;
				Name = options.Name;
				Description = options.Description;
				UnlockJobIds = new List<string>(options.UnlockJobIds);
				JobGroups = new List<WorkRecipeJobLevelGroup>(options.JobLevelGroups);
			}
		}

		private const string StandardCreatedDayStateKey = "romestead_content_framework:standard:created_day";

		private const string StandardLastDayStateKey = "romestead_content_framework:standard:last_day";

		private const string StandardUserStatePrefix = "romestead_content_framework:state:";

		private const int StandardStorageInventorySize = 24;

		private const int StandardOutputInventorySize = 18;

		private const string StandardStorageInventoryNameKey = "Object_Storage";

		private const string StandardOutputInventoryNameKey = "Buildings_Output";

		private static readonly HashSet<string> StandardBehaviorWarnings = new HashSet<string>(StringComparer.Ordinal);

		internal const string CustomEffectSpellTypeId = "romestead_content_framework:spelltype:custom_effect";

		private static readonly object Sync = new object();

		private static readonly Dictionary<string, ItemRegistration> ItemRegistrations = new Dictionary<string, ItemRegistration>(StringComparer.Ordinal);

		private static readonly Dictionary<string, string> Strings = new Dictionary<string, string>(StringComparer.Ordinal);

		private static readonly Dictionary<string, SpellRegistration> SpellRegistrations = new Dictionary<string, SpellRegistration>(StringComparer.Ordinal);

		private static readonly Dictionary<string, BuildingTypeRegistration> BuildingTypeRegistrations = new Dictionary<string, BuildingTypeRegistration>(StringComparer.Ordinal);

		private static readonly Dictionary<string, StandardBuildingBehaviorRegistration> StandardBuildingBehaviors = new Dictionary<string, StandardBuildingBehaviorRegistration>(StringComparer.Ordinal);

		private static readonly Dictionary<string, BuildingRegistration> BuildingRegistrations = new Dictionary<string, BuildingRegistration>(StringComparer.Ordinal);

		private static readonly Dictionary<string, ConstructionRegistration> ConstructionRegistrations = new Dictionary<string, ConstructionRegistration>(StringComparer.Ordinal);

		private static readonly Dictionary<string, ConstructionGroupRegistration> ConstructionGroupRegistrations = new Dictionary<string, ConstructionGroupRegistration>(StringComparer.Ordinal);

		private static readonly Dictionary<string, ConstructionResourceRegistration> ConstructionResourceRegistrations = new Dictionary<string, ConstructionResourceRegistration>(StringComparer.Ordinal);

		private static readonly Dictionary<string, CraftingStationRegistration> CraftingStationRegistrations = new Dictionary<string, CraftingStationRegistration>(StringComparer.Ordinal);

		private static readonly Dictionary<string, DecorationRegistration> DecorationRegistrations = new Dictionary<string, DecorationRegistration>(StringComparer.Ordinal);

		private static readonly Dictionary<string, FurnitureRegistration> FurnitureRegistrations = new Dictionary<string, FurnitureRegistration>(StringComparer.Ordinal);

		private static readonly Dictionary<string, MapRegistration> MapRegistrations = new Dictionary<string, MapRegistration>(StringComparer.OrdinalIgnoreCase);

		private static readonly HashSet<string> DefaultUnlockedConstructionIds = new HashSet<string>(StringComparer.Ordinal);

		private static readonly Dictionary<string, ItemRecipeRegistration> ItemRecipes = new Dictionary<string, ItemRecipeRegistration>(StringComparer.Ordinal);

		private static readonly Dictionary<string, WorkRecipeRegistration> WorkRecipeRegistrations = new Dictionary<string, WorkRecipeRegistration>(StringComparer.Ordinal);

		private static readonly Dictionary<string, JobRegistration> JobRegistrations = new Dictionary<string, JobRegistration>(StringComparer.Ordinal);

		private static readonly Dictionary<string, ShopRegistration> ShopRegistrations = new Dictionary<string, ShopRegistration>(StringComparer.Ordinal);

		private static readonly List<ShopItemRegistration> ShopItems = new List<ShopItemRegistration>();

		private static readonly Dictionary<string, DropTableRegistration> DropTables = new Dictionary<string, DropTableRegistration>(StringComparer.Ordinal);

		private static readonly List<DropTableItemRegistration> DropTableItems = new List<DropTableItemRegistration>();

		private static readonly Dictionary<string, IconRegistration> IconRegistrations = new Dictionary<string, IconRegistration>(StringComparer.Ordinal);

		private static readonly Dictionary<string, VfxRegistration> VfxRegistrations = new Dictionary<string, VfxRegistration>(StringComparer.Ordinal);

		private static readonly HashSet<string> AppliedItemIds = new HashSet<string>(StringComparer.Ordinal);

		private static readonly HashSet<string> AppliedSpellIds = new HashSet<string>(StringComparer.Ordinal);

		private static readonly HashSet<string> AppliedBuildingTypeIds = new HashSet<string>(StringComparer.Ordinal);

		private static readonly HashSet<string> AppliedBuildingIds = new HashSet<string>(StringComparer.Ordinal);

		private static readonly HashSet<string> AppliedConstructionIds = new HashSet<string>(StringComparer.Ordinal);

		private static readonly HashSet<string> AppliedConstructionGroupIds = new HashSet<string>(StringComparer.Ordinal);

		private static readonly HashSet<string> AppliedConstructionResourceIds = new HashSet<string>(StringComparer.Ordinal);

		private static readonly HashSet<string> AppliedCraftingStationIds = new HashSet<string>(StringComparer.Ordinal);

		private static readonly HashSet<string> AppliedDecorationIds = new HashSet<string>(StringComparer.Ordinal);

		private static readonly HashSet<string> AppliedFurnitureIds = new HashSet<string>(StringComparer.Ordinal);

		private static readonly HashSet<string> AppliedMapIds = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static readonly HashSet<string> AppliedItemRecipeIds = new HashSet<string>(StringComparer.Ordinal);

		private static readonly HashSet<string> AppliedWorkRecipeIds = new HashSet<string>(StringComparer.Ordinal);

		private static readonly HashSet<string> AppliedJobIds = new HashSet<string>(StringComparer.Ordinal);

		private static readonly HashSet<string> AppliedShopIds = new HashSet<string>(StringComparer.Ordinal);

		private static readonly HashSet<string> AppliedDropTableIds = new HashSet<string>(StringComparer.Ordinal);

		private static readonly HashSet<string> AppliedIconIds = new HashSet<string>(StringComparer.Ordinal);

		private static readonly HashSet<string> AppliedVfxIds = new HashSet<string>(StringComparer.Ordinal);

		private static bool SharedContentReady;

		private static bool WorkRecipeGroupsReady;

		private static bool ServerContentReady;

		private static bool ClientContentReady;

		private static bool ServerMapsReady;

		private static readonly Assembly FrameworkAssembly = typeof(RomesteadContent).Assembly;

		private const string MissingExteriorMapFallback = "maps/building_exteriors/leatherworker_1";

		private const string MissingInteriorMapFallback = "maps/interiors_new/leather_1";

		private static readonly HashSet<string> MissingMapFallbackWarnings = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, string> ClientCustomDoodadDatabaseSources = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, HashSet<Guid>> ClientCustomDoodadDatabaseGuids = new Dictionary<string, HashSet<Guid>>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, string> ServerCustomDoodadDatabaseSources = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, HashSet<Guid>> ServerCustomDoodadDatabaseGuids = new Dictionary<string, HashSet<Guid>>(StringComparer.OrdinalIgnoreCase);

		public static ItemContentRegistry Items { get; } = new ItemContentRegistry();

		public static LocalizationContentRegistry Localization { get; } = new LocalizationContentRegistry();

		public static SpellContentRegistry Spells { get; } = new SpellContentRegistry();

		public static BuildingContentRegistry Buildings { get; } = new BuildingContentRegistry();

		public static MapContentRegistry Maps { get; } = new MapContentRegistry();

		public static ItemRecipeContentRegistry Recipes { get; } = new ItemRecipeContentRegistry();

		public static WorkRecipeContentRegistry WorkRecipes { get; } = new WorkRecipeContentRegistry();

		public static JobContentRegistry Jobs { get; } = new JobContentRegistry();

		public static ShopContentRegistry Shops { get; } = new ShopContentRegistry();

		public static DropTableContentRegistry Drops { get; } = new DropTableContentRegistry();

		public static IconContentRegistry Icons { get; } = new IconContentRegistry();

		public static VfxContentRegistry Vfx { get; } = new VfxContentRegistry();

		internal static void StandardBuildingCreated(StandardBuildingController controller)
		{
			StandardBuildingBehaviorRegistration standardBuildingBehavior = GetStandardBuildingBehavior(controller);
			if (standardBuildingBehavior != null)
			{
				EnsureStandardInventories(((AbstractBuildingController)controller).Building, standardBuildingBehavior);
				SetInternalDay(((AbstractBuildingController)controller).Building.InstanceModel, "romestead_content_framework:standard:created_day", TimeServerSystem.Day, overwrite: false);
				InvokeStandardCallback(standardBuildingBehavior, "OnCreated", standardBuildingBehavior.Options.OnCreated, ((AbstractBuildingController)controller).Building);
			}
		}

		internal static void StandardBuildingLoaded(StandardBuildingController controller)
		{
			StandardBuildingBehaviorRegistration standardBuildingBehavior = GetStandardBuildingBehavior(controller);
			if (standardBuildingBehavior != null)
			{
				((AbstractBuildingController)controller).JobTickRate = standardBuildingBehavior.Options.WorkerJobTickRate;
				InvokeStandardCallback(standardBuildingBehavior, "OnLoaded", standardBuildingBehavior.Options.OnLoaded, ((AbstractBuildingController)controller).Building);
			}
		}

		internal static void StandardBuildingRemoved(StandardBuildingController controller)
		{
			StandardBuildingBehaviorRegistration standardBuildingBehavior = GetStandardBuildingBehavior(controller);
			if (standardBuildingBehavior != null)
			{
				InvokeStandardCallback(standardBuildingBehavior, "OnRemoved", standardBuildingBehavior.Options.OnRemoved, ((AbstractBuildingController)controller).Building);
			}
		}

		internal static void StandardBuildingUpgraded(StandardBuildingController controller, ConstructionModel upgradeConstruction, BuildingData upgradedBuildingData)
		{
			StandardBuildingBehaviorRegistration standardBuildingBehavior = GetStandardBuildingBehavior(controller);
			if (standardBuildingBehavior == null || standardBuildingBehavior.Options.OnUpgraded == null)
			{
				return;
			}
			try
			{
				standardBuildingBehavior.Options.OnUpgraded(new StandardBuildingUpgradeContext(((AbstractBuildingController)controller).Building, upgradeConstruction, upgradedBuildingData));
			}
			catch (Exception ex)
			{
				LogWarning(standardBuildingBehavior.Source, "Standard building '" + standardBuildingBehavior.Id + "' OnUpgraded callback failed: " + ex.Message);
			}
		}

		internal static void HandleStandardBuildingNewDay()
		{
			List<BuildingSimulationModel> list = new List<BuildingSimulationModel>(ServerGameState.Buildings.Values);
			for (int i = 0; i < list.Count; i++)
			{
				if (list[i].Controller is StandardBuildingController controller)
				{
					HandleStandardBuildingNewDay(controller);
				}
			}
		}

		internal static bool TryGetStandardWorkerSettings(StandardBuildingController controller, out float jobTickRate, out float qualityModifier)
		{
			StandardBuildingBehaviorRegistration standardBuildingBehavior = GetStandardBuildingBehavior(controller);
			if (standardBuildingBehavior == null || standardBuildingBehavior.Options.ProductionMode != StandardBuildingProductionMode.WorkerJob)
			{
				jobTickRate = 0.5f;
				qualityModifier = -0.5f;
				return false;
			}
			jobTickRate = standardBuildingBehavior.Options.WorkerJobTickRate;
			qualityModifier = standardBuildingBehavior.Options.WorkerQualityModifier;
			return true;
		}

		internal static void WarnUnsupportedStandardWorkOrder(StandardBuildingController controller, string outputType)
		{
			StandardBuildingBehaviorRegistration standardBuildingBehavior = GetStandardBuildingBehavior(controller);
			if (standardBuildingBehavior != null)
			{
				LogWarning(standardBuildingBehavior.Source, $"Standard worker building '{standardBuildingBehavior.Id}' cannot finish work-order output type '{outputType}'.");
			}
		}

		private static void HandleStandardBuildingNewDay(StandardBuildingController controller)
		{
			StandardBuildingBehaviorRegistration standardBuildingBehavior = GetStandardBuildingBehavior(controller);
			if (standardBuildingBehavior == null)
			{
				return;
			}
			BuildingInstanceModel instanceModel = ((AbstractBuildingController)controller).Building.InstanceModel;
			int day = TimeServerSystem.Day;
			if (GetInternalDay(instanceModel, "romestead_content_framework:standard:last_day", int.MinValue) == day)
			{
				return;
			}
			SetInternalDay(instanceModel, "romestead_content_framework:standard:last_day", day, overwrite: true);
			int internalDay = GetInternalDay(instanceModel, "romestead_content_framework:standard:created_day", day);
			IReadOnlyList<StandardItemProduction> productions = standardBuildingBehavior.Options.Productions;
			int num = 0;
			while (standardBuildingBehavior.Options.ProductionMode == StandardBuildingProductionMode.AutomaticDaily && num < productions.Count)
			{
				StandardItemProduction standardItemProduction = productions[num];
				int num2 = day - internalDay;
				if (num2 >= standardItemProduction.FirstDayDelay && (num2 - standardItemProduction.FirstDayDelay) % standardItemProduction.EveryDays == 0)
				{
					if (ItemDataBase.GetItemDataOrNull(standardItemProduction.ItemId) == null)
					{
						WarnStandardOnce(standardBuildingBehavior.Id + ":missing-item:" + standardItemProduction.ItemId, $"Standard building '{standardBuildingBehavior.Id}' cannot produce missing item '{standardItemProduction.ItemId}'. Source: {standardBuildingBehavior.Source.DisplayName}.");
					}
					else
					{
						new StandardBuildingContext(((AbstractBuildingController)controller).Building).TryAddOutputItem(standardItemProduction.ItemId, standardItemProduction.Amount);
					}
				}
				num++;
			}
			InvokeStandardCallback(standardBuildingBehavior, "OnNewDay", standardBuildingBehavior.Options.OnNewDay, ((AbstractBuildingController)controller).Building);
		}

		private static void ApplyStandardBuildingDefaults(BuildingData building)
		{
			StandardBuildingBehaviorRegistration value;
			lock (Sync)
			{
				if (!StandardBuildingBehaviors.TryGetValue(building.BuildingTypeId, out value))
				{
					return;
				}
			}
			if (!building.Input.HasValue && value.Options.InputLogistics.HasValue)
			{
				building.Input = value.Options.InputLogistics;
			}
			if (!building.Output.HasValue && value.Options.OutputLogistics.HasValue)
			{
				building.Output = value.Options.OutputLogistics;
			}
		}

		private static StandardBuildingBehaviorRegistration GetStandardBuildingBehavior(StandardBuildingController controller)
		{
			StandardBuildingBehaviorRegistration value;
			lock (Sync)
			{
				StandardBuildingBehaviors.TryGetValue(((AbstractBuildingController)controller).Building.InstanceModel.BuildingTypeId, out value);
			}
			if (value == null)
			{
				WarnStandardOnce(((AbstractBuildingController)controller).Building.InstanceModel.BuildingTypeId + ":missing-registration", "Cannot run missing standard building behavior '" + ((AbstractBuildingController)controller).Building.InstanceModel.BuildingTypeId + "'.");
			}
			return value;
		}

		private static void EnsureStandardInventories(BuildingSimulationModel building, StandardBuildingBehaviorRegistration registration)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Expected O, but got Unknown
			StandardBuildingBehaviorOptions options = registration.Options;
			try
			{
				if (options.HasStorageInventory && !building.InstanceModel.StorageInventoryId.HasValue)
				{
					BuildingsSController.CreateBuildingInventory(building.InstanceModel, new CreateNewInventoryMessage
					{
						InventorySize = 24,
						InventoryType = (InventoryType)0,
						NewId = Guid.NewGuid(),
						NameId = StringId.op_Implicit("Object_Storage"),
						FilteredItemFlags = options.StorageItemFlags
					}, (IOInventoryCreationType)0);
				}
				if (options.HasOutputInventory && !building.InstanceModel.OutputInventoryId.HasValue)
				{
					BuildingsSController.CreateBuildingInventory(building.InstanceModel, new CreateNewInventoryMessage
					{
						InventorySize = 18,
						InventoryType = (InventoryType)2,
						NewId = Guid.NewGuid(),
						NameId = StringId.op_Implicit("Buildings_Output"),
						FilteredItemFlags = options.OutputItemFlags
					}, (IOInventoryCreationType)1);
				}
			}
			catch (Exception ex)
			{
				LogWarning(registration.Source, "Cannot create inventories for standard building '" + registration.Id + "': " + ex.Message);
			}
		}

		private static void InvokeStandardCallback(StandardBuildingBehaviorRegistration registration, string callbackName, Action<StandardBuildingContext> callback, BuildingSimulationModel building)
		{
			if (callback == null)
			{
				return;
			}
			try
			{
				callback(new StandardBuildingContext(building));
			}
			catch (Exception ex)
			{
				LogWarning(registration.Source, $"Standard building '{registration.Id}' {callbackName} callback failed: {ex.Message}");
			}
		}

		private static Dictionary<string, string> EnsureParameters(BuildingInstanceModel instance)
		{
			if (instance.Parameters == null)
			{
				instance.Parameters = new Dictionary<string, string>();
			}
			return instance.Parameters;
		}

		private static int GetInternalDay(BuildingInstanceModel instance, string key, int fallback)
		{
			if (instance.Parameters == null || !instance.Parameters.TryGetValue(key, out var value) || !int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
			{
				return fallback;
			}
			return result;
		}

		private static void SetInternalDay(BuildingInstanceModel instance, string key, int day, bool overwrite)
		{
			Dictionary<string, string> dictionary = EnsureParameters(instance);
			if (overwrite || !dictionary.ContainsKey(key))
			{
				dictionary[key] = day.ToString(CultureInfo.InvariantCulture);
			}
		}

		private static void WarnStandardOnce(string key, string message)
		{
			lock (Sync)
			{
				if (!StandardBehaviorWarnings.Add(key))
				{
					return;
				}
			}
			LogWarning(message);
		}

		private static void ApplyBuildingCatalogLocked()
		{
			ApplyConstructionGroupsLocked();
			ApplyConstructionResourcesLocked();
			ApplyCraftingStationsLocked();
			ApplyDecorationsLocked();
			ApplyFurnitureLocked();
		}

		private static void ApplyConstructionGroupsLocked()
		{
			foreach (ConstructionGroupRegistration value in ConstructionGroupRegistrations.Values)
			{
				string id = value.Group.Id;
				if (PrepareDatabaseId(id, AppliedConstructionGroupIds, ConstructionsGroupDataBase.ConstructionsGroupDataMap, "construction group"))
				{
					ConstructionsGroupDataBase.AddData(new List<ConstructionsGroupData> { value.Group });
					AppliedConstructionGroupIds.Add(id);
				}
			}
		}

		private static void ApplyConstructionResourcesLocked()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			foreach (ConstructionResourceRegistration value in ConstructionResourceRegistrations.Values)
			{
				string id = value.Resource.Id;
				if (PrepareDatabaseId(id, AppliedConstructionResourceIds, ConstructionResourcesDataBase.DataMap, "construction resource"))
				{
					ConstructionResourcesDataBase.AddConstructionMaterials(new List<ConstructionResourceDataModel> { value.Resource });
					AppliedConstructionResourceIds.Add(id);
				}
			}
		}

		private static void ApplyCraftingStationsLocked()
		{
			foreach (CraftingStationRegistration value in CraftingStationRegistrations.Values)
			{
				string id = value.Station.Id;
				if (PrepareDatabaseId(id, AppliedCraftingStationIds, CraftingStationDataBase.DataMap, "crafting station"))
				{
					CraftingStationDataBase.AddCraftingStations(new List<CraftingStationData> { value.Station });
					AppliedCraftingStationIds.Add(id);
				}
			}
		}

		private static void ApplyDecorationsLocked()
		{
			foreach (DecorationRegistration value in DecorationRegistrations.Values)
			{
				string id = value.Decoration.Id;
				if (PrepareDatabaseId(id, AppliedDecorationIds, DecorationsDataBase.DecorationDataMap, "decoration"))
				{
					DecorationsDataBase.AddData(new List<DecorationData> { value.Decoration });
					AppliedDecorationIds.Add(id);
				}
			}
		}

		private static void ApplyFurnitureLocked()
		{
			foreach (FurnitureRegistration value2 in FurnitureRegistrations.Values)
			{
				string id = value2.Furniture.Id;
				if (FurnitureDataBase.DataMap.TryGetValue(id, out var value))
				{
					if (!AppliedFurnitureIds.Contains(id) || value !=