diff --git a/README.md b/README.md index 68c571e..6f6d181 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Colony Survival Construction Mod by Scarabol +Original Creator: Scarabol Existence Github: https://github.com/Scarabol/ColonyConstructionMod + ## Blueprints diff --git a/src/Architects.cs b/src/Architects.cs index 22a63c5..1ccfa1f 100644 --- a/src/Architects.cs +++ b/src/Architects.cs @@ -6,99 +6,71 @@ namespace ScarabolMods { - [ModLoader.ModManager] - public static class ArchitectsModEntries - { - public static string JOB_NAME = "scarabol.architect"; - public static string JOB_ITEM_KEY = ConstructionModEntries.MOD_PREFIX + "architects.table"; - - [ModLoader.ModCallback (ModLoader.EModCallbackType.AfterItemTypesDefined, "scarabol.architects.registerjobs")] - [ModLoader.ModCallbackProvidesFor ("pipliz.apiprovider.jobs.resolvetypes")] - public static void RegisterJobs () + [ModLoader.ModManager] + public static class ArchitectsModEntries { - BlockJobManagerTracker.Register (JOB_ITEM_KEY); - } + public static string JOB_NAME = "scarabol.architect"; + public static string JOB_ITEM_KEY = ConstructionModEntries.MOD_PREFIX + "architects.table"; - [ModLoader.ModCallback (ModLoader.EModCallbackType.AfterSelectedWorld, "scarabol.architects.registertexturemappings")] - [ModLoader.ModCallbackProvidesFor ("pipliz.server.registertexturemappingtextures")] - public static void AfterSelectedWorld () - { - var textureMapping = new ItemTypesServer.TextureMapping (new JSONNode ()); - textureMapping.AlbedoPath = MultiPath.Combine (ConstructionModEntries.AssetsDirectory, "textures", "albedo", "architectTop.png"); - ItemTypesServer.SetTextureMapping (ConstructionModEntries.MOD_PREFIX + "architecttop", textureMapping); - } + [ModLoader.ModCallback(ModLoader.EModCallbackType.AfterItemTypesDefined, "scarabol.architects.registerjobs")] + [ModLoader.ModCallbackProvidesFor("pipliz.apiprovider.jobs.resolvetypes")] + public static void RegisterJobs() + { + BlockJobManagerTracker.Register(JOB_ITEM_KEY); + //add job interface to the job + RecipeStorage.AddBlockToRecipeMapping(JOB_ITEM_KEY, JOB_NAME); + } - [ModLoader.ModCallback (ModLoader.EModCallbackType.AfterAddingBaseTypes, "scarabol.architects.addrawtypes")] - [ModLoader.ModCallbackDependsOn ("scarabol.blueprints.addrawtypes")] - public static void AfterAddingBaseTypes (Dictionary itemTypes) - { - itemTypes.Add (JOB_ITEM_KEY, new ItemTypesServer.ItemTypeRaw (JOB_ITEM_KEY, new JSONNode () - .SetAs ("onPlaceAudio", "woodPlace") - .SetAs ("onRemoveAudio", "woodDeleteLight") - .SetAs ("icon", MultiPath.Combine (ConstructionModEntries.AssetsDirectory, "icons", "architect.png")) - .SetAs ("sideall", "planks") - .SetAs ("sidey+", ConstructionModEntries.MOD_PREFIX + "architecttop") - .SetAs ("npcLimit", 0) - )); + [ModLoader.ModCallback(ModLoader.EModCallbackType.AfterItemTypesDefined, "scarabol.architects.loadrecipes")] + [ModLoader.ModCallbackDependsOn("pipliz.server.loadresearchables")] + public static void LoadRecipes() + { + //Add blueprints as recipes + foreach(string blueprintTypename in ManagerBlueprints.Blueprints.Keys) + { + RecipeStorage.AddDefaultLimitTypeRecipe(JOB_NAME, new ArchitectRecipe(blueprintTypename)); + } + } } - [ModLoader.ModCallback (ModLoader.EModCallbackType.AfterItemTypesDefined, "scarabol.architects.loadrecipes")] - [ModLoader.ModCallbackDependsOn ("pipliz.server.loadresearchables")] - public static void LoadRecipes () + public class ArchitectJob : CraftingJobBase, IBlockJobBase, INPCTypeDefiner { - RecipePlayer.AddDefaultRecipe (new Recipe (JOB_ITEM_KEY + ".recipe", new InventoryItem (BuiltinBlocks.Planks, 1), new InventoryItem (JOB_ITEM_KEY, 1), 0)); - } - } + public override string NPCTypeKey { get { return ArchitectsModEntries.JOB_NAME; } } - public class ArchitectJob : CraftingJobBase, IBlockJobBase, INPCTypeDefiner - { - public override string NPCTypeKey { get { return ArchitectsModEntries.JOB_NAME; } } + public override float CraftingCooldown { get { return 10.0f; } } - public override float CraftingCooldown { get { return 10.0f; } } + public override int MaxRecipeCraftsPerHaul { get { return 1; } } - public override int MaxRecipeCraftsPerHaul { get { return 1; } } + //Decrease the amount of blueprints to build each time that one is crafted + protected override void OnRecipeCrafted() + { + var recipeStorage = RecipeStorage.GetPlayerStorage(owner); + recipeStorage.SetLimit(selectedRecipe.Name, recipeStorage.GetRecipeSetting(selectedRecipe.Name).Limit - 1); + } - public override List GetCraftingLimitsTriggers () - { - return new List { ArchitectsModEntries.JOB_ITEM_KEY }; - } + NPCTypeStandardSettings INPCTypeDefiner.GetNPCTypeDefinition() + { + return new NPCTypeStandardSettings + { + keyName = NPCTypeKey, + printName = "Architect", + maskColor1 = new UnityEngine.Color32(220, 220, 220, 255), + type = NPCTypeID.GetNextID() + }; + } - protected override void OnRecipeCrafted () - { - var recipeStorage = RecipeStorage.GetPlayerStorage (owner); - recipeStorage.SetLimit (selectedRecipe.Name, recipeStorage.GetRecipeSetting (selectedRecipe.Name).Limit - 1); } - NPCTypeStandardSettings INPCTypeDefiner.GetNPCTypeDefinition () + public class ArchitectRecipe : Recipe { - return new NPCTypeStandardSettings { - keyName = NPCTypeKey, - printName = "Architect", - maskColor1 = new UnityEngine.Color32 (220, 220, 220, 255), - type = NPCTypeID.GetNextID () - }; - } - - public override IList GetCraftingLimitsRecipes () - { - List result = new List (); - foreach (string blueprintTypename in ManagerBlueprints.Blueprints.Keys) { - result.Add (new ArchitectRecipe (blueprintTypename)); - } - return result; - } - } + public ArchitectRecipe(string blueprintTypename) + : base(blueprintTypename + ".recipe", new InventoryItem(BuiltinBlocks.Planks, 1), new InventoryItem(blueprintTypename, 1), 0) + { + } - public class ArchitectRecipe : Recipe - { - public ArchitectRecipe (string blueprintTypename) - : base (blueprintTypename + ".recipe", new InventoryItem (BuiltinBlocks.Planks, 1), new InventoryItem (blueprintTypename, 1), 0) - { - } - - public override int ShouldBeMade (Stockpile stockpile, RecipeStorage.PlayerRecipeStorage playerStorage = null) - { - return RecipeStorage.GetPlayerStorage (stockpile.Owner).GetRecipeSetting (this.Name).Limit; + public override int ShouldBeMade(Stockpile stockpile, RecipeStorage.PlayerRecipeStorage playerStorage = null) + { + return RecipeStorage.GetPlayerStorage(stockpile.Owner).GetRecipeSetting(Name).Limit; + } } - } } diff --git a/src/Blueprints.cs b/src/Blueprints.cs index ad188a3..f66f5da 100644 --- a/src/Blueprints.cs +++ b/src/Blueprints.cs @@ -4,107 +4,104 @@ namespace ScarabolMods { - [ModLoader.ModManager] - public static class BlueprintsModEntries - { - [ModLoader.ModCallback (ModLoader.EModCallbackType.AfterSelectedWorld, "scarabol.blueprints.registertexturemappings")] - [ModLoader.ModCallbackProvidesFor ("pipliz.server.registertexturemappingtextures")] - public static void AfterSelectedWorld () + [ModLoader.ModManager] + public static class BlueprintsModEntries { - var textureMapping = new ItemTypesServer.TextureMapping (new JSONNode ()); - textureMapping.AlbedoPath = MultiPath.Combine (ConstructionModEntries.AssetsDirectory, "textures", "albedo", "blueprintsTop.png"); - ItemTypesServer.SetTextureMapping (ConstructionModEntries.MOD_PREFIX + "blueprinttop", textureMapping); + [ModLoader.ModCallback(ModLoader.EModCallbackType.AfterAddingBaseTypes, "scarabol.blueprints.addrawtypes")] + public static void AfterAddingBaseTypes(Dictionary itemTypes) + { + string iconFilepath = MultiPath.Combine(ConstructionModEntries.AssetsDirectory, "icons", "blueprint.png"); + foreach(string blueprintTypename in ManagerBlueprints.Blueprints.Keys) + { + itemTypes.Add(blueprintTypename, new ItemTypesServer.ItemTypeRaw(blueprintTypename, + new JSONNode() + .SetAs("onPlaceAudio", "woodPlace") + .SetAs("onRemoveAudio", "woodDeleteLight") + .SetAs("icon", iconFilepath) + .SetAs("sideall", "planks") + .SetAs("sidey+", "mods.scarabol.construction.blueprintTop") + .SetAs("npcLimit", "0") + .SetAs("isRotatable", "true") + .SetAs("rotatablex+", blueprintTypename + "x+") + .SetAs("rotatablex-", blueprintTypename + "x-") + .SetAs("rotatablez+", blueprintTypename + "z+") + .SetAs("rotatablez-", blueprintTypename + "z-") + )); + itemTypes.Add(blueprintTypename + "x+", new ItemTypesServer.ItemTypeRaw(blueprintTypename + "x+", + new JSONNode() + .SetAs("parentType", blueprintTypename) + )); + itemTypes.Add(blueprintTypename + "x-", new ItemTypesServer.ItemTypeRaw(blueprintTypename + "x-", + new JSONNode() + .SetAs("parentType", blueprintTypename) + )); + itemTypes.Add(blueprintTypename + "z+", new ItemTypesServer.ItemTypeRaw(blueprintTypename + "z+", + new JSONNode() + .SetAs("parentType", blueprintTypename) + )); + itemTypes.Add(blueprintTypename + "z-", new ItemTypesServer.ItemTypeRaw(blueprintTypename + "z-", + new JSONNode() + .SetAs("parentType", blueprintTypename) + )); + } + } } - [ModLoader.ModCallback (ModLoader.EModCallbackType.AfterAddingBaseTypes, "scarabol.blueprints.addrawtypes")] - public static void AfterAddingBaseTypes (Dictionary itemTypes) + public class BlueprintTodoBlock { - string iconFilepath = MultiPath.Combine (ConstructionModEntries.AssetsDirectory, "icons", "blueprint.png"); - foreach (string blueprintTypename in ManagerBlueprints.Blueprints.Keys) { - itemTypes.Add (blueprintTypename, new ItemTypesServer.ItemTypeRaw (blueprintTypename, - new JSONNode () - .SetAs ("onPlaceAudio", "woodPlace") - .SetAs ("onRemoveAudio", "woodDeleteLight") - .SetAs ("icon", iconFilepath) - .SetAs ("sideall", "planks") - .SetAs ("sidey+", ConstructionModEntries.MOD_PREFIX + "blueprinttop") - .SetAs ("npcLimit", "0") - .SetAs ("isRotatable", "true") - .SetAs ("rotatablex+", blueprintTypename + "x+") - .SetAs ("rotatablex-", blueprintTypename + "x-") - .SetAs ("rotatablez+", blueprintTypename + "z+") - .SetAs ("rotatablez-", blueprintTypename + "z-") - )); - itemTypes.Add (blueprintTypename + "x+", new ItemTypesServer.ItemTypeRaw (blueprintTypename + "x+", - new JSONNode () - .SetAs ("parentType", blueprintTypename) - )); - itemTypes.Add (blueprintTypename + "x-", new ItemTypesServer.ItemTypeRaw (blueprintTypename + "x-", - new JSONNode () - .SetAs ("parentType", blueprintTypename) - )); - itemTypes.Add (blueprintTypename + "z+", new ItemTypesServer.ItemTypeRaw (blueprintTypename + "z+", - new JSONNode () - .SetAs ("parentType", blueprintTypename) - )); - itemTypes.Add (blueprintTypename + "z-", new ItemTypesServer.ItemTypeRaw (blueprintTypename + "z-", - new JSONNode () - .SetAs ("parentType", blueprintTypename) - )); - } - } - } + public int OffsetX; + public int OffsetY; + public int OffsetZ; + public string Typename; - public class BlueprintTodoBlock - { - public int OffsetX; - public int OffsetY; - public int OffsetZ; - public string Typename; + public BlueprintTodoBlock(int offsetx, int offsety, int offsetz, string typename) + { + OffsetX = offsetx; + OffsetY = offsety; + OffsetZ = offsetz; + Typename = typename; + } - public BlueprintTodoBlock (int offsetx, int offsety, int offsetz, string typename) - { - OffsetX = offsetx; - OffsetY = offsety; - OffsetZ = offsetz; - Typename = typename; - } + public BlueprintTodoBlock(JSONNode node) + { + OffsetX = node.getAsOrElse("x", "offsetx"); + OffsetY = node.getAsOrElse("y", "offsety"); + OffsetZ = node.getAsOrElse("z", "offsetz"); + Typename = node.getAsOrElse("t", "typename"); + } - public BlueprintTodoBlock (JSONNode node) - { - OffsetX = node.getAsOrElse ("x", "offsetx"); - OffsetY = node.getAsOrElse ("y", "offsety"); - OffsetZ = node.getAsOrElse ("z", "offsetz"); - Typename = node.getAsOrElse ("t", "typename"); - } + public JSONNode GetJSON() + { + return new JSONNode() + .SetAs("x", OffsetX) + .SetAs("y", OffsetY) + .SetAs("z", OffsetZ) + .SetAs("t", Typename); + } - public JSONNode GetJSON () - { - return new JSONNode () - .SetAs ("x", OffsetX) - .SetAs ("y", OffsetY) - .SetAs ("z", OffsetZ) - .SetAs ("t", Typename); - } - - public Vector3Int GetWorldPosition (string typeBasename, Vector3Int position, ushort bluetype) - { - ushort hxm = ItemTypes.IndexLookup.GetIndex (typeBasename + "x-"); - ushort hzp = ItemTypes.IndexLookup.GetIndex (typeBasename + "z+"); - ushort hzm = ItemTypes.IndexLookup.GetIndex (typeBasename + "z-"); - int realx = OffsetZ + 1; - int realz = -OffsetX; - if (bluetype == hxm) { - realx = -OffsetZ - 1; - realz = OffsetX; - } else if (bluetype == hzp) { - realx = OffsetX; - realz = OffsetZ + 1; - } else if (bluetype == hzm) { - realx = -OffsetX; - realz = -OffsetZ - 1; - } - return position.Add (realx, OffsetY, realz); + public Vector3Int GetWorldPosition(string typeBasename, Vector3Int position, ushort bluetype) + { + ushort hxm = ItemTypes.IndexLookup.GetIndex(typeBasename + "x-"); + ushort hzp = ItemTypes.IndexLookup.GetIndex(typeBasename + "z+"); + ushort hzm = ItemTypes.IndexLookup.GetIndex(typeBasename + "z-"); + int realx = OffsetZ + 1; + int realz = -OffsetX; + if(bluetype == hxm) + { + realx = -OffsetZ - 1; + realz = OffsetX; + } + else if(bluetype == hzp) + { + realx = OffsetX; + realz = OffsetZ + 1; + } + else if(bluetype == hzm) + { + realx = -OffsetX; + realz = -OffsetZ - 1; + } + return position.Add(realx, OffsetY, realz); + } } - } } diff --git a/src/Capsules.cs b/src/Capsules.cs index 52ad1ed..1ac4c55 100644 --- a/src/Capsules.cs +++ b/src/Capsules.cs @@ -9,146 +9,172 @@ namespace ScarabolMods { - [ModLoader.ModManager] - public static class CapsulesModEntries - { - public static string CAPSULE_PERMISSION = ConstructionModEntries.MOD_PREFIX + "usecapsules"; - public static string CAPSULE_SUFFIX = ".capsule"; - - [ModLoader.ModCallback (ModLoader.EModCallbackType.AfterSelectedWorld, "scarabol.capsules.registertexturemappings")] - [ModLoader.ModCallbackProvidesFor ("pipliz.server.registertexturemappingtextures")] - public static void AfterSelectedWorld () + [ModLoader.ModManager] + public static class CapsulesModEntries { - var textureMapping = new ItemTypesServer.TextureMapping (new JSONNode ()); - textureMapping.AlbedoPath = MultiPath.Combine (ConstructionModEntries.AssetsDirectory, "textures", "albedo", "capsulesTop.png"); - ItemTypesServer.SetTextureMapping (ConstructionModEntries.MOD_PREFIX + "capsuletop", textureMapping); - } + public static string CAPSULE_PERMISSION = ConstructionModEntries.MOD_PREFIX + "usecapsules"; + public static string CAPSULE_SUFFIX = ".capsule"; - [ModLoader.ModCallback (ModLoader.EModCallbackType.AfterAddingBaseTypes, "scarabol.capsules.addrawtypes")] - [ModLoader.ModCallbackDependsOn ("scarabol.blueprints.addrawtypes")] - public static void AfterAddingBaseTypes (Dictionary itemTypes) - { - string iconFilepath = MultiPath.Combine (ConstructionModEntries.AssetsDirectory, "icons", "capsule.png"); - foreach (string blueprintTypename in ManagerBlueprints.Blueprints.Keys) { - itemTypes.Add (blueprintTypename + CAPSULE_SUFFIX, new ItemTypesServer.ItemTypeRaw (blueprintTypename + CAPSULE_SUFFIX, - new JSONNode () - .SetAs ("onPlaceAudio", "woodPlace") - .SetAs ("onRemoveAudio", "woodDeleteLight") - .SetAs ("icon", iconFilepath) - .SetAs ("sideall", "planks") - .SetAs ("sidey+", ConstructionModEntries.MOD_PREFIX + "capsuletop") - .SetAs ("isRotatable", "true") - .SetAs ("rotatablex+", blueprintTypename + CAPSULE_SUFFIX + "x+") - .SetAs ("rotatablex-", blueprintTypename + CAPSULE_SUFFIX + "x-") - .SetAs ("rotatablez+", blueprintTypename + CAPSULE_SUFFIX + "z+") - .SetAs ("rotatablez-", blueprintTypename + CAPSULE_SUFFIX + "z-") - .SetAs ("npcLimit", "0") - )); - foreach (string xz in new string [] { "x+", "x-", "z+", "z-" }) { - itemTypes.Add (blueprintTypename + CAPSULE_SUFFIX + xz, new ItemTypesServer.ItemTypeRaw (blueprintTypename + CAPSULE_SUFFIX + xz, - new JSONNode () - .SetAs ("parentType", blueprintTypename + CAPSULE_SUFFIX) - )); + [ModLoader.ModCallback(ModLoader.EModCallbackType.AfterSelectedWorld, "scarabol.capsules.registertexturemappings")] + [ModLoader.ModCallbackProvidesFor("pipliz.server.registertexturemappingtextures")] + public static void AfterSelectedWorld() + { + var textureMapping = new ItemTypesServer.TextureMapping(new JSONNode()); + textureMapping.AlbedoPath = MultiPath.Combine(ConstructionModEntries.AssetsDirectory, "textures", "albedo", "capsulesTop.png"); + ItemTypesServer.SetTextureMapping(ConstructionModEntries.MOD_PREFIX + "capsuletop", textureMapping); } - } - } - - [ModLoader.ModCallback (ModLoader.EModCallbackType.AfterItemTypesDefined, "scarabol.capsules.registertypes")] - public static void AfterItemTypesDefined () - { - foreach (string blueprintTypename in ManagerBlueprints.Blueprints.Keys) { - ItemTypesServer.RegisterOnAdd (blueprintTypename + CAPSULE_SUFFIX, CapsuleBlockCode.OnPlaceCapsule); - } - ChatCommands.CommandManager.RegisterCommand (new CapsuleChatCommand ()); - } - } - static class CapsuleBlockCode - { - public static void OnPlaceCapsule (Vector3Int position, ushort capsuleType, Players.Player causedBy) - { - if (!PermissionsManager.CheckAndWarnPermission (causedBy, CapsulesModEntries.CAPSULE_PERMISSION)) { - ServerManager.TryChangeBlock (position, BlockTypes.Builtin.BuiltinBlocks.Air, Players.GetPlayer (NetworkID.Server)); - return; - } - ThreadManager.InvokeOnMainThread (delegate () { - ushort realType; - if (World.TryGetTypeAt (position, out realType) && realType != capsuleType) { - return; - } - ServerManager.TryChangeBlock (position, BlockTypes.Builtin.BuiltinBlocks.Air, Players.GetPlayer (NetworkID.Server)); - string capsuleName = ItemTypes.IndexLookup.GetName (capsuleType); - string blueprintName = capsuleName.Substring (0, capsuleName.Length - CapsulesModEntries.CAPSULE_SUFFIX.Length - 2); - Chat.Send (causedBy, $"Starting to build '{blueprintName}' at {position}"); - List blocks; - if (ManagerBlueprints.Blueprints.TryGetValue (blueprintName, out blocks)) { - int placed = 0, removed = 0, failed = 0; - ushort bluetype; - if (ItemTypes.IndexLookup.TryGetIndex (blueprintName + capsuleName.Substring (capsuleName.Length - 2), out bluetype)) { - foreach (BlueprintTodoBlock block in blocks) { - Vector3Int realPosition = block.GetWorldPosition (blueprintName, position, bluetype); - string baseTypename = TypeHelper.RotatableToBasetype (block.Typename); - string rotatedTypename = block.Typename; - if (!baseTypename.Equals (block.Typename)) { - Vector3Int jobVec = TypeHelper.RotatableToVector (capsuleName); - Vector3Int blockVec = TypeHelper.RotatableToVector (block.Typename); - Vector3Int combinedVec = new Vector3Int (-jobVec.z * blockVec.x + jobVec.x * blockVec.z, 0, jobVec.x * blockVec.x + jobVec.z * blockVec.z); - rotatedTypename = baseTypename + TypeHelper.VectorToXZ (combinedVec); - } - ushort rotatedType; - if (realPosition.y > 0 && ItemTypes.IndexLookup.TryGetIndex (rotatedTypename, out rotatedType) && ServerManager.TryChangeBlock (realPosition, rotatedType, Players.GetPlayer (NetworkID.Server))) { - if (block.Typename.Equals ("air")) { - removed++; - } else { - placed++; + [ModLoader.ModCallback(ModLoader.EModCallbackType.AfterAddingBaseTypes, "scarabol.capsules.addrawtypes")] + [ModLoader.ModCallbackDependsOn("scarabol.blueprints.addrawtypes")] + public static void AfterAddingBaseTypes(Dictionary itemTypes) + { + string iconFilepath = MultiPath.Combine(ConstructionModEntries.AssetsDirectory, "icons", "capsule.png"); + foreach(string blueprintTypename in ManagerBlueprints.Blueprints.Keys) + { + itemTypes.Add(blueprintTypename + CAPSULE_SUFFIX, new ItemTypesServer.ItemTypeRaw(blueprintTypename + CAPSULE_SUFFIX, + new JSONNode() + .SetAs("onPlaceAudio", "woodPlace") + .SetAs("onRemoveAudio", "woodDeleteLight") + .SetAs("icon", iconFilepath) + .SetAs("sideall", "planks") + .SetAs("sidey+", ConstructionModEntries.MOD_PREFIX + "capsuletop") + .SetAs("isRotatable", "true") + .SetAs("rotatablex+", blueprintTypename + CAPSULE_SUFFIX + "x+") + .SetAs("rotatablex-", blueprintTypename + CAPSULE_SUFFIX + "x-") + .SetAs("rotatablez+", blueprintTypename + CAPSULE_SUFFIX + "z+") + .SetAs("rotatablez-", blueprintTypename + CAPSULE_SUFFIX + "z-") + .SetAs("npcLimit", "0") + )); + foreach(string xz in new string[] { "x+", "x-", "z+", "z-" }) + { + itemTypes.Add(blueprintTypename + CAPSULE_SUFFIX + xz, new ItemTypesServer.ItemTypeRaw(blueprintTypename + CAPSULE_SUFFIX + xz, + new JSONNode() + .SetAs("parentType", blueprintTypename + CAPSULE_SUFFIX) + )); } - } else { - failed++; - } } - } - Chat.Send (causedBy, $"Completed '{blueprintName}' at {position} with {placed} placed, {removed} removed and {failed} failed blocks"); - } else { - Chat.Send (causedBy, $"Blueprint '{blueprintName}' not found"); } - }, 2.0); + + [ModLoader.ModCallback(ModLoader.EModCallbackType.AfterItemTypesDefined, "scarabol.capsules.registertypes")] + public static void AfterItemTypesDefined() + { + foreach(string blueprintTypename in ManagerBlueprints.Blueprints.Keys) + { + ItemTypesServer.RegisterOnAdd(blueprintTypename + CAPSULE_SUFFIX, CapsuleBlockCode.OnPlaceCapsule); + } + ChatCommands.CommandManager.RegisterCommand(new CapsuleChatCommand()); + } } - } - public class CapsuleChatCommand : ChatCommands.IChatCommand - { - public bool IsCommand (string chat) + static class CapsuleBlockCode { - return chat.StartsWith ("/capsule "); + public static void OnPlaceCapsule(Vector3Int position, ushort capsuleType, Players.Player causedBy) + { + if(!PermissionsManager.CheckAndWarnPermission(causedBy, CapsulesModEntries.CAPSULE_PERMISSION)) + { + ServerManager.TryChangeBlock(position, BlockTypes.Builtin.BuiltinBlocks.Air, Players.GetPlayer(NetworkID.Server)); + return; + } + ThreadManager.InvokeOnMainThread(delegate () + { + ushort realType; + if(World.TryGetTypeAt(position, out realType) && realType != capsuleType) + { + return; + } + ServerManager.TryChangeBlock(position, BlockTypes.Builtin.BuiltinBlocks.Air, Players.GetPlayer(NetworkID.Server)); + string capsuleName = ItemTypes.IndexLookup.GetName(capsuleType); + string blueprintName = capsuleName.Substring(0, capsuleName.Length - CapsulesModEntries.CAPSULE_SUFFIX.Length - 2); + Chat.Send(causedBy, $"Starting to build '{blueprintName}' at {position}"); + List blocks; + if(ManagerBlueprints.Blueprints.TryGetValue(blueprintName, out blocks)) + { + int placed = 0, removed = 0, failed = 0; + ushort bluetype; + if(ItemTypes.IndexLookup.TryGetIndex(blueprintName + capsuleName.Substring(capsuleName.Length - 2), out bluetype)) + { + foreach(BlueprintTodoBlock block in blocks) + { + Vector3Int realPosition = block.GetWorldPosition(blueprintName, position, bluetype); + string baseTypename = TypeHelper.RotatableToBasetype(block.Typename); + string rotatedTypename = block.Typename; + if(!baseTypename.Equals(block.Typename)) + { + Vector3Int jobVec = TypeHelper.RotatableToVector(capsuleName); + Vector3Int blockVec = TypeHelper.RotatableToVector(block.Typename); + Vector3Int combinedVec = new Vector3Int(-jobVec.z * blockVec.x + jobVec.x * blockVec.z, 0, jobVec.x * blockVec.x + jobVec.z * blockVec.z); + rotatedTypename = baseTypename + TypeHelper.VectorToXZ(combinedVec); + } + ushort rotatedType; + if(realPosition.y > 0 && ItemTypes.IndexLookup.TryGetIndex(rotatedTypename, out rotatedType) && ServerManager.TryChangeBlock(realPosition, rotatedType, Players.GetPlayer(NetworkID.Server))) + { + if(block.Typename.Equals("air")) + { + removed++; + } + else + { + placed++; + } + } + else + { + failed++; + } + } + } + Chat.Send(causedBy, $"Completed '{blueprintName}' at {position} with {placed} placed, {removed} removed and {failed} failed blocks"); + } + else + { + Chat.Send(causedBy, $"Blueprint '{blueprintName}' not found"); + } + }, 2.0); + } } - public bool TryDoCommand (Players.Player causedBy, string chattext) + public class CapsuleChatCommand : ChatCommands.IChatCommand { - if (causedBy == null) { - return true; - } else if (!PermissionsManager.CheckAndWarnPermission (causedBy, CapsulesModEntries.CAPSULE_PERMISSION)) { - return true; - } - int amount = 1; - var matched = Regex.Match (chattext, @"/capsule (?.+) (?\d+)"); - if (!matched.Success) { - matched = Regex.Match (chattext, @"/capsule (?.+)"); - if (!matched.Success) { - Chat.Send (causedBy, "Command didn't match, use /capsule name amount"); - return true; + public bool IsCommand(string chat) + { + return chat.StartsWith("/capsule "); + } + + public bool TryDoCommand(Players.Player causedBy, string chattext) + { + if(causedBy == null) + { + return true; + } + else if(!PermissionsManager.CheckAndWarnPermission(causedBy, CapsulesModEntries.CAPSULE_PERMISSION)) + { + return true; + } + int amount = 1; + var matched = Regex.Match(chattext, @"/capsule (?.+) (?\d+)"); + if(!matched.Success) + { + matched = Regex.Match(chattext, @"/capsule (?.+)"); + if(!matched.Success) + { + Chat.Send(causedBy, "Command didn't match, use /capsule name amount"); + return true; + } + } + else + { + amount = Int32.Parse(matched.Groups["amount"].Value); + } + string blueprintName = matched.Groups["name"].Value; + string blueprintFullname = ManagerBlueprints.BLUEPRINTS_PREFIX + blueprintName; + if(!ManagerBlueprints.Blueprints.ContainsKey(blueprintFullname)) + { + Chat.Send(causedBy, $"Blueprint '{blueprintName}' not known"); + return true; + } + Stockpile.GetStockPile(causedBy).Add(ItemTypes.IndexLookup.GetIndex(blueprintFullname + CapsulesModEntries.CAPSULE_SUFFIX), amount); + Chat.Send(causedBy, $"Added {amount} emperor capsule '{blueprintName}' to your stockpile"); + return true; } - } else { - amount = Int32.Parse (matched.Groups ["amount"].Value); - } - string blueprintName = matched.Groups ["name"].Value; - string blueprintFullname = ManagerBlueprints.BLUEPRINTS_PREFIX + blueprintName; - if (!ManagerBlueprints.Blueprints.ContainsKey (blueprintFullname)) { - Chat.Send (causedBy, $"Blueprint '{blueprintName}' not known"); - return true; - } - Stockpile.GetStockPile (causedBy).Add (ItemTypes.IndexLookup.GetIndex (blueprintFullname + CapsulesModEntries.CAPSULE_SUFFIX), amount); - Chat.Send (causedBy, $"Added {amount} emperor capsule '{blueprintName}' to your stockpile"); - return true; } - } } diff --git a/src/Construction.cs b/src/Construction.cs index 257ec63..c3691ff 100644 --- a/src/Construction.cs +++ b/src/Construction.cs @@ -11,266 +11,289 @@ namespace ScarabolMods { - [ModLoader.ModManager] - public static class ConstructionModEntries - { - public static string MOD_PREFIX = "mods.scarabol.construction."; - public static string JOB_ITEM_KEY = MOD_PREFIX + "buildtool"; - public static float EXCAVATION_DELAY = 2.0f; - public static string ModDirectory; - public static string AssetsDirectory; - static Recipe buildtoolRecipe; - - [ModLoader.ModCallback (ModLoader.EModCallbackType.OnAssemblyLoaded, "scarabol.construction.assemblyload")] - public static void OnAssemblyLoaded (string path) + [ModLoader.ModManager] + public static class ConstructionModEntries { - ModDirectory = Path.GetDirectoryName (path); - AssetsDirectory = Path.Combine (ModDirectory, "assets"); - } + public static string MOD_PREFIX = "mods.scarabol.construction."; + public static string JOB_ITEM_KEY = MOD_PREFIX + "buildtool"; + public static float EXCAVATION_DELAY = 2.0f; + public static string ModDirectory; + public static string AssetsDirectory; - [ModLoader.ModCallback (ModLoader.EModCallbackType.AfterStartup, "scarabol.construction.registercallbacks")] - public static void AfterStartup () - { - Log.Write ("Loaded Construction Mod 6.0.4 by Scarabol"); - ManagerBlueprints.LoadBlueprints (Path.Combine (ModDirectory, "blueprints")); - } - - [ModLoader.ModCallback (ModLoader.EModCallbackType.AfterItemTypesDefined, "scarabol.construction.registerjobs")] - [ModLoader.ModCallbackProvidesFor ("pipliz.apiprovider.jobs.resolvetypes")] - public static void RegisterJobs () - { - foreach (string blueprintTypename in ManagerBlueprints.Blueprints.Keys) { - BlockJobManagerTracker.Register (blueprintTypename); - } - } + [ModLoader.ModCallback(ModLoader.EModCallbackType.OnAssemblyLoaded, "scarabol.construction.assemblyload")] + public static void OnAssemblyLoaded(string path) + { + ModDirectory = Path.GetDirectoryName(path); + AssetsDirectory = Path.Combine(ModDirectory, "assets"); + } - [ModLoader.ModCallback (ModLoader.EModCallbackType.AfterAddingBaseTypes, "scarabol.construction.addrawtypes")] - public static void AfterAddingBaseTypes (Dictionary itemTypes) - { - itemTypes.Add (JOB_ITEM_KEY, new ItemTypesServer.ItemTypeRaw (JOB_ITEM_KEY, new JSONNode () - .SetAs ("npcLimit", 1) - .SetAs ("icon", MultiPath.Combine (AssetsDirectory, "icons", "buildtool.png")) - .SetAs ("isPlaceable", false) - )); - } + [ModLoader.ModCallback(ModLoader.EModCallbackType.AfterStartup, "scarabol.construction.registercallbacks")] + public static void AfterStartup() + { + Log.Write("Loaded Construction Mod 6.0.4 by Scarabol"); + ManagerBlueprints.LoadBlueprints(Path.Combine(ModDirectory, "blueprints")); + } - [ModLoader.ModCallback (ModLoader.EModCallbackType.AfterItemTypesDefined, "scarabol.construction.loadrecipes")] - [ModLoader.ModCallbackDependsOn ("pipliz.server.loadresearchables")] - public static void LoadRecipes () - { - buildtoolRecipe = new Recipe (JOB_ITEM_KEY + ".recipe", new List () { - new InventoryItem (BuiltinBlocks.IronIngot, 1), - new InventoryItem (BuiltinBlocks.Planks, 1) - }, new InventoryItem (JOB_ITEM_KEY, 1), 0); - RecipeStorage.AddDefaultLimitTypeRecipe ("pipliz.crafter", buildtoolRecipe); - RecipePlayer.AddDefaultRecipe (buildtoolRecipe); - } + [ModLoader.ModCallback(ModLoader.EModCallbackType.AfterItemTypesDefined, "scarabol.construction.registerjobs")] + [ModLoader.ModCallbackProvidesFor("pipliz.apiprovider.jobs.resolvetypes")] + public static void RegisterJobs() + { + foreach(string blueprintTypename in ManagerBlueprints.Blueprints.Keys) + { + BlockJobManagerTracker.Register(blueprintTypename); + } + } - [ModLoader.ModCallback (ModLoader.EModCallbackType.AfterWorldLoad, "scarabol.construction.afterworldload")] - [ModLoader.ModCallbackDependsOn ("pipliz.server.localization.waitforloading")] - [ModLoader.ModCallbackProvidesFor ("pipliz.server.localization.convert")] - public static void AfterWorldLoad () - { - ModLocalizationHelper.Localize (Path.Combine (AssetsDirectory, "localization"), MOD_PREFIX); - foreach (KeyValuePair locEntry in ManagerBlueprints.BlueprintsLocalizations) { - try { - ModLocalizationHelper.Localize (locEntry.Key, locEntry.Value, ManagerBlueprints.BLUEPRINTS_PREFIX); - } catch (Exception exception) { - Log.WriteError ($"Exception while localization of {locEntry.Key}; {exception.Message}"); + [ModLoader.ModCallback(ModLoader.EModCallbackType.AfterWorldLoad, "scarabol.construction.afterworldload")] + [ModLoader.ModCallbackProvidesFor("pipliz.server.localization.convert")] + public static void AfterWorldLoad() + { + ModLocalizationHelper.Localize(Path.Combine(AssetsDirectory, "localization"), MOD_PREFIX); + foreach(KeyValuePair locEntry in ManagerBlueprints.BlueprintsLocalizations) + { + try + { + ModLocalizationHelper.Localize(locEntry.Key, locEntry.Value, ManagerBlueprints.BLUEPRINTS_PREFIX); + } + catch(Exception exception) + { + Log.WriteError($"Exception while localization of {locEntry.Key}; {exception.Message}"); + } + } } - } } - } - public class ConstructionJob : BlockJobBase, IBlockJobBase, INPCTypeDefiner - { - NPCInventory BlockInventory; - bool ShouldTakeItems; - string Fullname; - List Todoblocks; - public override string NPCTypeKey { get { return "scarabol.constructor"; } } + public class ConstructionJob : BlockJobBase, IBlockJobBase, INPCTypeDefiner + { + NPCInventory BlockInventory; + bool ShouldTakeItems; + string Fullname; + List Todoblocks; - public override bool NeedsItems { get { return ShouldTakeItems; } } + public override string NPCTypeKey { get { return "scarabol.constructor"; } } - public override InventoryItem RecruitementItem { get { return new InventoryItem (ConstructionModEntries.JOB_ITEM_KEY, 1); } } + public override bool NeedsItems { get { return ShouldTakeItems; } } - public override JSONNode GetJSON () - { - JSONNode jsonTodos = new JSONNode (NodeType.Array); - foreach (BlueprintTodoBlock block in Todoblocks) { - jsonTodos.AddToArray (block.GetJSON ()); - } - return base.GetJSON () - .SetAs ("inventory", BlockInventory.GetJSON ()) - .SetAs ("shouldTakeItems", ShouldTakeItems) - .SetAs ("fullname", Fullname) - .SetAs ("todoblocks", jsonTodos); - } + public override InventoryItem RecruitementItem { get { return new InventoryItem(ConstructionModEntries.JOB_ITEM_KEY, 1); } } - public ITrackableBlock InitializeOnAdd (Vector3Int position, ushort type, Players.Player player) - { - BlockInventory = new NPCInventory (10000000f); - InitializeJob (player, position, 0); - Fullname = ItemTypes.IndexLookup.GetName (type); - string blueprintTypename = Fullname.Substring (0, Fullname.Length - 2); - ManagerBlueprints.Blueprints.TryGetValue (blueprintTypename, out List blocks); - Todoblocks = new List (blocks); - Todoblocks.Reverse (); - return this; - } + public override JSONNode GetJSON() + { + JSONNode jsonTodos = new JSONNode(NodeType.Array); + foreach(BlueprintTodoBlock block in Todoblocks) + { + jsonTodos.AddToArray(block.GetJSON()); + } + return base.GetJSON() + .SetAs("inventory", BlockInventory.GetJSON()) + .SetAs("shouldTakeItems", ShouldTakeItems) + .SetAs("fullname", Fullname) + .SetAs("todoblocks", jsonTodos); + } - public override ITrackableBlock InitializeFromJSON (Players.Player player, JSONNode node) - { - BlockInventory = new NPCInventory (10000000f, node ["inventory"]); - ShouldTakeItems = false; - node.TryGetAs ("shouldTakeItems", out ShouldTakeItems); - Fullname = node.GetAs ("fullname"); - JSONNode jsonTodos = node ["todoblocks"]; - Todoblocks = new List (); - foreach (JSONNode jsonBlock in jsonTodos.LoopArray ()) { - Todoblocks.Add (new BlueprintTodoBlock (jsonBlock)); - } - InitializeJob (player, (Vector3Int)node ["position"], node.GetAs ("npcID")); - return this; - } + public ITrackableBlock InitializeOnAdd(Vector3Int position, ushort type, Players.Player player) + { + BlockInventory = new NPCInventory(10000000f); + InitializeJob(player, position, 0); + Fullname = ItemTypes.IndexLookup.GetName(type); + string blueprintTypename = Fullname.Substring(0, Fullname.Length - 2); + ManagerBlueprints.Blueprints.TryGetValue(blueprintTypename, out List blocks); + Todoblocks = new List(blocks); + Todoblocks.Reverse(); + return this; + } - public override void OnNPCAtJob (ref NPCBase.NPCState state) - { - state.JobIsDone = true; - usedNPC.LookAt (position.Vector); - if (!state.Inventory.IsEmpty) { - state.Inventory.Dump (BlockInventory); - } - if (Todoblocks.Count < 1) { - BlockInventory.Dump (usedNPC.Inventory); - ShouldTakeItems = true; - } else { - bool placed = false; - if (!ItemTypes.IndexLookup.TryGetIndex (Fullname, out ushort bluetype)) { - string msg = $"Bob here from site at {position}, the blueprint '{Fullname}' does not exist, stopped work here"; - Log.WriteError (msg); - Chat.Send (usedNPC.Colony.Owner, msg); - Todoblocks.Clear (); - return; + public override ITrackableBlock InitializeFromJSON(Players.Player player, JSONNode node) + { + BlockInventory = new NPCInventory(10000000f, node["inventory"]); + ShouldTakeItems = false; + node.TryGetAs("shouldTakeItems", out ShouldTakeItems); + Fullname = node.GetAs("fullname"); + JSONNode jsonTodos = node["todoblocks"]; + Todoblocks = new List(); + foreach(JSONNode jsonBlock in jsonTodos.LoopArray()) + { + Todoblocks.Add(new BlueprintTodoBlock(jsonBlock)); + } + InitializeJob(player, (Vector3Int)node["position"], node.GetAs("npcID")); + return this; } - ushort scaffoldType = ItemTypes.IndexLookup.GetIndex (ScaffoldsModEntries.SCAFFOLD_ITEM_TYPE); - string jobname = TypeHelper.RotatableToBasetype (Fullname); - for (int i = Todoblocks.Count - 1; i >= 0; i--) { - BlueprintTodoBlock todoblock = Todoblocks [i]; - Vector3Int realPosition = todoblock.GetWorldPosition (jobname, position, bluetype); - if (realPosition.y <= 0) { - Todoblocks.RemoveAt (i); - continue; - } - string todoblockBaseTypename = TypeHelper.RotatableToBasetype (todoblock.Typename); - string todoblockRotatedTypename = todoblock.Typename; - if (!todoblockBaseTypename.Equals (todoblock.Typename)) { - Vector3Int jobVec = TypeHelper.RotatableToVector (Fullname); - Vector3Int blockVec = TypeHelper.RotatableToVector (todoblock.Typename); - Vector3Int combinedVec = new Vector3Int (-jobVec.z * blockVec.x + jobVec.x * blockVec.z, 0, jobVec.x * blockVec.x + jobVec.z * blockVec.z); - todoblockRotatedTypename = todoblockBaseTypename + TypeHelper.VectorToXZ (combinedVec); - } - if (!LookupAndWarnItemIndex (todoblockRotatedTypename, out ushort todoblockRotatedType)) { - Todoblocks.RemoveAt (i); - } else if (!World.TryGetTypeAt (realPosition, out ushort actualType) || actualType == todoblockRotatedType) { - Todoblocks.RemoveAt (i); - } else { - if (!LookupAndWarnItemIndex (todoblockBaseTypename, out ushort todoblockBaseType)) { - Todoblocks.RemoveAt (i); - } else if (todoblockRotatedType == BuiltinBlocks.Air || BlockInventory.TryGetOneItem (todoblockBaseType)) { - Todoblocks.RemoveAt (i); - if (ServerManager.TryChangeBlock (realPosition, todoblockRotatedType, owner)) { - state.JobIsDone = true; - if (todoblockRotatedType == BuiltinBlocks.Air) { - state.SetCooldown (ConstructionModEntries.EXCAVATION_DELAY); - state.SetIndicator (new Shared.IndicatorState (ConstructionModEntries.EXCAVATION_DELAY, actualType)); - } else if (!BlockInventory.IsEmpty && i > 0) { - state.SetIndicator (new Shared.IndicatorState (0.5f, todoblockRotatedType)); + + public override void OnNPCAtJob(ref NPCBase.NPCState state) + { + state.JobIsDone = true; + usedNPC.LookAt(position.Vector); + if(!state.Inventory.IsEmpty) + { + state.Inventory.Dump(BlockInventory); + } + if(Todoblocks.Count < 1) + { + BlockInventory.Dump(usedNPC.Inventory); + ShouldTakeItems = true; + } + else + { + bool placed = false; + if(!ItemTypes.IndexLookup.TryGetIndex(Fullname, out ushort bluetype)) + { + string msg = $"Bob here from site at {position}, the blueprint '{Fullname}' does not exist, stopped work here"; + Log.WriteError(msg); + Chat.Send(usedNPC.Colony.Owner, msg); + Todoblocks.Clear(); + return; + } + ushort scaffoldType = ItemTypes.IndexLookup.GetIndex(ScaffoldsModEntries.SCAFFOLD_ITEM_TYPE); + string jobname = TypeHelper.RotatableToBasetype(Fullname); + for(int i = Todoblocks.Count - 1; i >= 0; i--) + { + BlueprintTodoBlock todoblock = Todoblocks[i]; + Vector3Int realPosition = todoblock.GetWorldPosition(jobname, position, bluetype); + if(realPosition.y <= 0) + { + Todoblocks.RemoveAt(i); + continue; + } + string todoblockBaseTypename = TypeHelper.RotatableToBasetype(todoblock.Typename); + string todoblockRotatedTypename = todoblock.Typename; + if(!todoblockBaseTypename.Equals(todoblock.Typename)) + { + Vector3Int jobVec = TypeHelper.RotatableToVector(Fullname); + Vector3Int blockVec = TypeHelper.RotatableToVector(todoblock.Typename); + Vector3Int combinedVec = new Vector3Int(-jobVec.z * blockVec.x + jobVec.x * blockVec.z, 0, jobVec.x * blockVec.x + jobVec.z * blockVec.z); + todoblockRotatedTypename = todoblockBaseTypename + TypeHelper.VectorToXZ(combinedVec); + } + if(!LookupAndWarnItemIndex(todoblockRotatedTypename, out ushort todoblockRotatedType)) + { + Todoblocks.RemoveAt(i); + } + else if(!World.TryGetTypeAt(realPosition, out ushort actualType) || actualType == todoblockRotatedType) + { + Todoblocks.RemoveAt(i); + } + else + { + if(!LookupAndWarnItemIndex(todoblockBaseTypename, out ushort todoblockBaseType)) + { + Todoblocks.RemoveAt(i); + } + else if(todoblockRotatedType == BuiltinBlocks.Air || BlockInventory.TryGetOneItem(todoblockBaseType)) + { + Todoblocks.RemoveAt(i); + if(ServerManager.TryChangeBlock(realPosition, todoblockRotatedType, owner)) + { + state.JobIsDone = true; + if(todoblockRotatedType == BuiltinBlocks.Air) + { + state.SetCooldown(ConstructionModEntries.EXCAVATION_DELAY); + state.SetIndicator(new Shared.IndicatorState(ConstructionModEntries.EXCAVATION_DELAY, actualType)); + } + else if(!BlockInventory.IsEmpty && i > 0) + { + state.SetIndicator(new Shared.IndicatorState(0.5f, todoblockRotatedType)); + } + if(actualType != BuiltinBlocks.Air && actualType != BuiltinBlocks.Water && actualType != scaffoldType) + { + usedNPC.Inventory.Add(ItemTypes.GetType(actualType).OnRemoveItems); + } + placed = true; + break; + } + } + } } - if (actualType != BuiltinBlocks.Air && actualType != BuiltinBlocks.Water && actualType != scaffoldType) { - usedNPC.Inventory.Add (ItemTypes.GetType (actualType).OnRemoveItems); + if(!placed) + { + BlockInventory.Dump(usedNPC.Inventory); + ShouldTakeItems = true; } - placed = true; - break; - } } - } } - if (!placed) { - BlockInventory.Dump (usedNPC.Inventory); - ShouldTakeItems = true; - } - } - } - bool LookupAndWarnItemIndex (string typename, out ushort type) - { - if (!ItemTypes.IndexLookup.TryGetIndex (typename, out type)) { - string msg = $"Bob here from site at {position}, the item type '{typename}' does not exist. Ignoring it..."; - Log.WriteError (msg); - Chat.Send (usedNPC.Colony.Owner, msg); - return false; - } - return true; - } + bool LookupAndWarnItemIndex(string typename, out ushort type) + { + if(!ItemTypes.IndexLookup.TryGetIndex(typename, out type)) + { + string msg = $"Bob here from site at {position}, the item type '{typename}' does not exist. Ignoring it..."; + Log.WriteError(msg); + Chat.Send(usedNPC.Colony.Owner, msg); + return false; + } + return true; + } - public override void OnNPCAtStockpile (ref NPCBase.NPCState state) - { - state.Inventory.Dump (usedNPC.Colony.UsedStockpile); - if (Todoblocks.Count < 1) { - ServerManager.TryChangeBlock (position, BuiltinBlocks.Air, owner); - return; - } - state.JobIsDone = true; - if (!ToSleep) { - ShouldTakeItems = true; - for (int i = Todoblocks.Count - 1; i >= 0; i--) { - BlueprintTodoBlock block = Todoblocks [i]; - if (!block.Typename.Equals ("air")) { - if (LookupAndWarnItemIndex (TypeHelper.RotatableToBasetype (block.Typename), out ushort typeindex)) { - if (usedNPC.Colony.UsedStockpile.TryRemove (typeindex, 1)) { - ShouldTakeItems = false; - state.Inventory.Add (typeindex, 1); - if (state.Inventory.UsedCapacity >= state.Inventory.Capacity) { // workaround for capacity issue - if (state.Inventory.TryGetOneItem (typeindex)) { - usedNPC.Colony.UsedStockpile.Add (typeindex, 1); - } - return; + public override void OnNPCAtStockpile(ref NPCBase.NPCState state) + { + state.Inventory.Dump(usedNPC.Colony.UsedStockpile); + if(Todoblocks.Count < 1) + { + ServerManager.TryChangeBlock(position, BuiltinBlocks.Air, owner); + return; + } + state.JobIsDone = true; + if(!ToSleep) + { + ShouldTakeItems = true; + for(int i = Todoblocks.Count - 1; i >= 0; i--) + { + BlueprintTodoBlock block = Todoblocks[i]; + if(!block.Typename.Equals("air")) + { + if(LookupAndWarnItemIndex(TypeHelper.RotatableToBasetype(block.Typename), out ushort typeindex)) + { + if(usedNPC.Colony.UsedStockpile.TryRemove(typeindex, 1)) + { + ShouldTakeItems = false; + state.Inventory.Add(typeindex, 1); + if(state.Inventory.UsedCapacity >= state.Inventory.Capacity) + { // workaround for capacity issue + if(state.Inventory.TryGetOneItem(typeindex)) + { + usedNPC.Colony.UsedStockpile.Add(typeindex, 1); + } + return; + } + } + } + else + { + Todoblocks.RemoveAt(i); + } + } + else + { + ShouldTakeItems = false; + } } - } - } else { - Todoblocks.RemoveAt (i); } - } else { - ShouldTakeItems = false; - } + if(Todoblocks.Count < 1) + { + ServerManager.TryChangeBlock(position, BuiltinBlocks.Air, owner); + return; + } + if(ShouldTakeItems) + { + state.JobIsDone = false; + state.SetIndicator(new Shared.IndicatorState(6f, ItemTypes.IndexLookup.GetIndex(Todoblocks[Todoblocks.Count - 1].Typename), true, false)); + } } - } - if (Todoblocks.Count < 1) { - ServerManager.TryChangeBlock (position, BuiltinBlocks.Air, owner); - return; - } - if (ShouldTakeItems) { - state.JobIsDone = false; - state.SetIndicator (new Shared.IndicatorState (6f, ItemTypes.IndexLookup.GetIndex (Todoblocks [Todoblocks.Count - 1].Typename), true, false)); - } - } - public override void OnRemove () - { - BlockInventory.Dump (Stockpile.GetStockPile (owner)); - base.OnRemove (); - } + public override void OnRemove() + { + BlockInventory.Dump(Stockpile.GetStockPile(owner)); + base.OnRemove(); + } - NPCTypeStandardSettings INPCTypeDefiner.GetNPCTypeDefinition () - { - return new NPCTypeStandardSettings { - keyName = NPCTypeKey, - printName = "Constructor", - maskColor1 = new UnityEngine.Color32 (75, 100, 140, 255), - type = NPCTypeID.GetNextID () - }; + NPCTypeStandardSettings INPCTypeDefiner.GetNPCTypeDefinition() + { + return new NPCTypeStandardSettings + { + keyName = NPCTypeKey, + printName = "Constructor", + maskColor1 = new UnityEngine.Color32(75, 100, 140, 255), + type = NPCTypeID.GetNextID() + }; + } } - } } + diff --git a/src/ManagerBlueprints.cs b/src/ManagerBlueprints.cs index 9a970f9..7ac638c 100644 --- a/src/ManagerBlueprints.cs +++ b/src/ManagerBlueprints.cs @@ -6,191 +6,250 @@ namespace ScarabolMods { - public static class ManagerBlueprints - { - public static string BLUEPRINTS_PREFIX = ConstructionModEntries.MOD_PREFIX + "blueprints."; - public static Dictionary> Blueprints = new Dictionary> (); - public static Dictionary BlueprintsLocalizations = new Dictionary (); - - public static void LoadBlueprints (string blueprintsPath) + public static class ManagerBlueprints { - long startLoadingBlueprints = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; - Dictionary prefixesBlueprints = new Dictionary (); - Dictionary prefixesCapsules = new Dictionary (); - string [] prefixFiles = Directory.GetFiles (Path.Combine (ConstructionModEntries.AssetsDirectory, "localization"), "prefixes.json", SearchOption.AllDirectories); - foreach (string filepath in prefixFiles) { - try { - JSONNode jsonPrefixes; - if (JSON.Deserialize (filepath, out jsonPrefixes, false)) { - string locName = Directory.GetParent (filepath).Name; - Pipliz.Log.Write ($"Found prefixes localization file for '{locName}' localization"); - string blueprintsPrefix; - if (jsonPrefixes.TryGetAs ("blueprints", out blueprintsPrefix)) { - prefixesBlueprints [locName] = blueprintsPrefix; - } - string capsulesPrefix; - if (jsonPrefixes.TryGetAs ("capsules", out capsulesPrefix)) { - prefixesCapsules [locName] = capsulesPrefix; - } - } - } catch (Exception exception) { - Pipliz.Log.WriteError ($"Exception reading localization from {filepath}; {exception.Message}"); - } - } - Pipliz.Log.Write ($"Loading blueprints from {blueprintsPath}"); - string [] files = Directory.GetFiles (blueprintsPath, "**.json", SearchOption.AllDirectories); - foreach (string filepath in files) { - try { - JSONNode json; - if (JSON.Deserialize (filepath, out json, false)) { - string filename = Path.GetFileName (filepath); - string blueprintName = Path.GetFileNameWithoutExtension (filepath).Replace (" ", "_").ToLower (); - int offx = 0; - int offy = 0; - int offz = 0; - Dictionary blocks = new Dictionary (); - JSONNode jsonBlocks; - if (json.NodeType == NodeType.Object) { - if (!json.TryGetAs ("blocks", out jsonBlocks)) { - Pipliz.Log.WriteError ($"Expected 'blocks' key in json {filename}"); - continue; - } - JSONNode jsonOffset; - if (json.TryGetAs ("offset", out jsonOffset)) { - offx = -jsonOffset.GetAs ("x"); - offy = -jsonOffset.GetAs ("y"); - offz = -jsonOffset.GetAs ("z"); - } - JSONNode jsonLocalization; - if (json.TryGetAs ("localization", out jsonLocalization)) { - foreach (KeyValuePair locEntry in jsonLocalization.LoopObject ()) { - string labelPrefix; - string capsulePrefix; - if (prefixesBlueprints.TryGetValue (locEntry.Key, out labelPrefix)) { - labelPrefix = labelPrefix.Trim (); - } else { - labelPrefix = "Blueprint"; - } - if (prefixesCapsules.TryGetValue (locEntry.Key, out capsulePrefix)) { - capsulePrefix = capsulePrefix.Trim (); - } else { - capsulePrefix = "Emperor Capsule"; - } - string label = ((string)locEntry.Value.BareObject).Trim (); - JSONNode locNode; - if (!BlueprintsLocalizations.TryGetValue (locEntry.Key, out locNode)) { - locNode = new JSONNode ().SetAs ("types", new JSONNode ()); - BlueprintsLocalizations.Add (locEntry.Key, locNode); - } - locNode.GetAs ("types").SetAs (blueprintName, labelPrefix + " " + label); - locNode.GetAs ("types").SetAs (blueprintName + CapsulesModEntries.CAPSULE_SUFFIX, capsulePrefix + " " + label); - } - } - } else { - jsonBlocks = json; // fallback everything is an array - Pipliz.Log.Write ($"No json object defined in '{filename}', using full content as blocks array"); - int maxx = 0, maxy = 0, maxz = 0; - foreach (JSONNode node in jsonBlocks.LoopArray ()) { - int x = getJSONInt (node, "startx", "x", 0, false); - if (x < offx) { - offx = x; - } - if (x > maxx) { - maxx = x; - } - int y = getJSONInt (node, "starty", "y", 0, false); - if (y < offy) { - offy = y; - } - if (y > maxy) { - maxy = y; + public static string BLUEPRINTS_PREFIX = ConstructionModEntries.MOD_PREFIX + "blueprints."; + public static Dictionary> Blueprints = new Dictionary>(); + public static Dictionary BlueprintsLocalizations = new Dictionary(); + + public static void LoadBlueprints(string blueprintsPath) + { + long startLoadingBlueprints = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; + Dictionary prefixesBlueprints = new Dictionary(); + Dictionary prefixesCapsules = new Dictionary(); + string[] prefixFiles = Directory.GetFiles(Path.Combine(ConstructionModEntries.AssetsDirectory, "localization"), "prefixes.json", SearchOption.AllDirectories); + foreach(string filepath in prefixFiles) + { + try + { + JSONNode jsonPrefixes; + if(JSON.Deserialize(filepath, out jsonPrefixes, false)) + { + string locName = Directory.GetParent(filepath).Name; + Pipliz.Log.Write($"Found prefixes localization file for '{locName}' localization"); + string blueprintsPrefix; + if(jsonPrefixes.TryGetAs("blueprints", out blueprintsPrefix)) + { + prefixesBlueprints[locName] = blueprintsPrefix; + } + string capsulesPrefix; + if(jsonPrefixes.TryGetAs("capsules", out capsulesPrefix)) + { + prefixesCapsules[locName] = capsulesPrefix; + } + } } - int z = getJSONInt (node, "startz", "z", 0, false); - if (z < offz) { - offz = z; + catch(Exception exception) + { + Pipliz.Log.WriteError($"Exception reading localization from {filepath}; {exception.Message}"); } - if (z > maxz) { - maxz = z; + } + Pipliz.Log.Write($"Loading blueprints from {blueprintsPath}"); + string[] files = Directory.GetFiles(blueprintsPath, "**.json", SearchOption.AllDirectories); + foreach(string filepath in files) + { + try + { + JSONNode json; + if(JSON.Deserialize(filepath, out json, false)) + { + string filename = Path.GetFileName(filepath); + string blueprintName = Path.GetFileNameWithoutExtension(filepath).Replace(" ", "_").ToLower(); + int offx = 0; + int offy = 0; + int offz = 0; + Dictionary blocks = new Dictionary(); + JSONNode jsonBlocks; + if(json.NodeType == NodeType.Object) + { + if(!json.TryGetAs("blocks", out jsonBlocks)) + { + Pipliz.Log.WriteError($"Expected 'blocks' key in json {filename}"); + continue; + } + JSONNode jsonOffset; + if(json.TryGetAs("offset", out jsonOffset)) + { + offx = -jsonOffset.GetAs("x"); + offy = -jsonOffset.GetAs("y"); + offz = -jsonOffset.GetAs("z"); + } + JSONNode jsonLocalization; + if(json.TryGetAs("localization", out jsonLocalization)) + { + foreach(KeyValuePair locEntry in jsonLocalization.LoopObject()) + { + string labelPrefix; + string capsulePrefix; + if(prefixesBlueprints.TryGetValue(locEntry.Key, out labelPrefix)) + { + labelPrefix = labelPrefix.Trim(); + } + else + { + labelPrefix = "Blueprint"; + } + if(prefixesCapsules.TryGetValue(locEntry.Key, out capsulePrefix)) + { + capsulePrefix = capsulePrefix.Trim(); + } + else + { + capsulePrefix = "Emperor Capsule"; + } + string label = ( (string)locEntry.Value.BareObject ).Trim(); + JSONNode locNode; + if(!BlueprintsLocalizations.TryGetValue(locEntry.Key, out locNode)) + { + locNode = new JSONNode().SetAs("types", new JSONNode()); + BlueprintsLocalizations.Add(locEntry.Key, locNode); + } + locNode.GetAs("types").SetAs(blueprintName, labelPrefix + " " + label); + locNode.GetAs("types").SetAs(blueprintName + CapsulesModEntries.CAPSULE_SUFFIX, capsulePrefix + " " + label); + } + } + } + else + { + jsonBlocks = json; // fallback everything is an array + Pipliz.Log.Write($"No json object defined in '{filename}', using full content as blocks array"); + int maxx = 0, maxy = 0, maxz = 0; + foreach(JSONNode node in jsonBlocks.LoopArray()) + { + int x = getJSONInt(node, "startx", "x", 0, false); + if(x < offx) + { + offx = x; + } + if(x > maxx) + { + maxx = x; + } + int y = getJSONInt(node, "starty", "y", 0, false); + if(y < offy) + { + offy = y; + } + if(y > maxy) + { + maxy = y; + } + int z = getJSONInt(node, "startz", "z", 0, false); + if(z < offz) + { + offz = z; + } + if(z > maxz) + { + maxz = z; + } + } + for(int x = 0; x <= -offx + maxx; x++) + { // add auto-clear area + for(int y = 0; y <= -offz + maxy; y++) + { + for(int z = 0; z <= -offz + maxz; z++) + { + blocks[$"{x}?{y}?{z}"] = new BlueprintTodoBlock(x, y, z, "air"); + } + } + } + } + BlueprintTodoBlock originBlock = null; + foreach(JSONNode node in jsonBlocks.LoopArray()) + { + int startx = getJSONInt(node, "startx", "x", 0, false); + int starty = getJSONInt(node, "starty", "y", 0, false); + int startz = getJSONInt(node, "startz", "z", 0, false); + string typename; + if(!node.TryGetAs("typename", out typename)) + { + if(!node.TryGetAs("t", out typename)) + { + throw new Exception($"typename not defined or not a string"); + } + } + if(typename.EndsWith("x+")) + { + typename = typename.Substring(0, typename.Length - 2) + "x-"; + } + else if(typename.EndsWith("x-")) + { + typename = typename.Substring(0, typename.Length - 2) + "x+"; + } + int width = getJSONInt(node, "width", "w", 1, true); + int height = getJSONInt(node, "height", "h", 1, true); + int depth = getJSONInt(node, "depth", "d", 1, true); + int dx = 1, dy = 1, dz = 1; + if(width < 0) + { + dx = -1; + } + if(height < 0) + { + dy = -1; + } + if(depth < 0) + { + dz = -1; + } + for(int x = startx; x * dx < ( startx + width ) * dx; x += dx) + { + for(int y = starty; y * dy < ( starty + height ) * dy; y += dy) + { + for(int z = startz; z * dz < ( startz + depth ) * dz; z += dz) + { + int absX = x - offx, absY = y - offy, absZ = z - offz; + BlueprintTodoBlock b = new BlueprintTodoBlock(absX, absY, absZ, typename); + if(absX == 0 && absY == 0 && absZ == -1) + { // do not replace the blueprint box itself (yet) + originBlock = b; + } + else + { + blocks[$"{absX}?{absY}?{absZ}"] = b; + } + } + } + } + } + if(originBlock != null) + { + blocks[$"{0}?{0}?{-1}"] = originBlock; + } + Blueprints.Add(BLUEPRINTS_PREFIX + blueprintName, blocks.Values.ToList()); + Pipliz.Log.Write($"Added blueprint '{BLUEPRINTS_PREFIX + blueprintName}' with {blocks.Count} blocks from {filename}"); + } } - } - for (int x = 0; x <= -offx + maxx; x++) { // add auto-clear area - for (int y = 0; y <= -offz + maxy; y++) { - for (int z = 0; z <= -offz + maxz; z++) { - blocks [$"{x}?{y}?{z}"] = new BlueprintTodoBlock (x, y, z, "air"); - } + catch(Exception exception) + { + Pipliz.Log.WriteError($"Exception while loading from {filepath}; {exception.Message}"); } - } } - BlueprintTodoBlock originBlock = null; - foreach (JSONNode node in jsonBlocks.LoopArray ()) { - int startx = getJSONInt (node, "startx", "x", 0, false); - int starty = getJSONInt (node, "starty", "y", 0, false); - int startz = getJSONInt (node, "startz", "z", 0, false); - string typename; - if (!node.TryGetAs ("typename", out typename)) { - if (!node.TryGetAs ("t", out typename)) { - throw new Exception ($"typename not defined or not a string"); + Pipliz.Log.Write($"Loaded blueprints in {DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond - startLoadingBlueprints} ms"); + } + + static int getJSONInt(JSONNode node, string name, string alternativeName, int defaultValue, bool optional) + { + try + { + return node[name].GetAs(); + } + catch(Exception) + { + try + { + return node[alternativeName].GetAs(); } - } - if (typename.EndsWith ("x+")) { - typename = typename.Substring (0, typename.Length - 2) + "x-"; - } else if (typename.EndsWith ("x-")) { - typename = typename.Substring (0, typename.Length - 2) + "x+"; - } - int width = getJSONInt (node, "width", "w", 1, true); - int height = getJSONInt (node, "height", "h", 1, true); - int depth = getJSONInt (node, "depth", "d", 1, true); - int dx = 1, dy = 1, dz = 1; - if (width < 0) { - dx = -1; - } - if (height < 0) { - dy = -1; - } - if (depth < 0) { - dz = -1; - } - for (int x = startx; x * dx < (startx + width) * dx; x += dx) { - for (int y = starty; y * dy < (starty + height) * dy; y += dy) { - for (int z = startz; z * dz < (startz + depth) * dz; z += dz) { - int absX = x - offx, absY = y - offy, absZ = z - offz; - BlueprintTodoBlock b = new BlueprintTodoBlock (absX, absY, absZ, typename); - if (absX == 0 && absY == 0 && absZ == -1) { // do not replace the blueprint box itself (yet) - originBlock = b; - } else { - blocks [$"{absX}?{absY}?{absZ}"] = b; + catch(Exception) + { + if(optional) + { + return defaultValue; } - } + throw new Exception($"Neither {name} nor {alternativeName} defined or not an integer"); } - } } - if (originBlock != null) { - blocks [$"{0}?{0}?{-1}"] = originBlock; - } - Blueprints.Add (BLUEPRINTS_PREFIX + blueprintName, blocks.Values.ToList ()); - Pipliz.Log.Write ($"Added blueprint '{BLUEPRINTS_PREFIX + blueprintName}' with {blocks.Count} blocks from {filename}"); - } - } catch (Exception exception) { - Pipliz.Log.WriteError ($"Exception while loading from {filepath}; {exception.Message}"); - } - } - Pipliz.Log.Write ($"Loaded blueprints in {DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond - startLoadingBlueprints} ms"); - } - - static int getJSONInt (JSONNode node, string name, string alternativeName, int defaultValue, bool optional) - { - try { - return node [name].GetAs (); - } catch (Exception) { - try { - return node [alternativeName].GetAs (); - } catch (Exception) { - if (optional) { - return defaultValue; - } - throw new Exception ($"Neither {name} nor {alternativeName} defined or not an integer"); } - } } - } } diff --git a/src/Scaffolds.cs b/src/Scaffolds.cs index 468943f..97d3b95 100644 --- a/src/Scaffolds.cs +++ b/src/Scaffolds.cs @@ -7,96 +7,129 @@ namespace ScarabolMods { - [ModLoader.ModManager] - public static class ScaffoldsModEntries - { - public static string SCAFFOLD_ITEM_TYPE = ConstructionModEntries.MOD_PREFIX + "scaffold"; - public static int MAX_PREVIEW_BLOCKS_THRESHOLD = 1000; - - [ModLoader.ModCallback (ModLoader.EModCallbackType.AfterAddingBaseTypes, "scarabol.scaffolds.addrawtypes")] - public static void AfterAddingBaseTypes (Dictionary itemTypes) + [ModLoader.ModManager] + public static class ScaffoldsModEntries { - itemTypes.Add (SCAFFOLD_ITEM_TYPE, new ItemTypesServer.ItemTypeRaw (SCAFFOLD_ITEM_TYPE, new JSONNode () - .SetAs ("onRemove", new JSONNode (NodeType.Array)) - .SetAs ("isSolid", false) - .SetAs ("mesh", MultiPath.Combine (ConstructionModEntries.AssetsDirectory, "meshes", "scaffold.obj")) - .SetAs ("sideall", "planks") - .SetAs ("destructionTime", 100) - )); - } + public static string SCAFFOLD_ITEM_TYPE = ConstructionModEntries.MOD_PREFIX + "scaffold"; + public static int PREVIEW_BLOCKS = 5000; + public const int MAX_PREVIEW = 25000; + public const int MIN_PREVIEW = 0; + public const int DEFAULT_PREVIEW = 5000; - [ModLoader.ModCallback (ModLoader.EModCallbackType.AfterItemTypesDefined, "scarabol.scaffolds.registertypes")] - public static void AfterItemTypesDefined () - { - foreach (string blueprintTypename in ManagerBlueprints.Blueprints.Keys) { - ItemTypesServer.RegisterOnAdd (blueprintTypename, ScaffoldBlockCode.AddScaffolds); - ItemTypesServer.RegisterOnAdd (blueprintTypename + CapsulesModEntries.CAPSULE_SUFFIX, ScaffoldBlockCode.AddScaffolds); - ItemTypesServer.RegisterOnRemove (blueprintTypename, ScaffoldBlockCode.RemoveScaffolds); - ItemTypesServer.RegisterOnRemove (blueprintTypename + CapsulesModEntries.CAPSULE_SUFFIX, ScaffoldBlockCode.RemoveScaffolds); - } - } - } + [ModLoader.ModCallback(ModLoader.EModCallbackType.AfterAddingBaseTypes, "scarabol.scaffolds.LoadConfig")] + public static void LoadConfig(Dictionary a) + { + try + { + JSONNode config = JSON.Deserialize(ConstructionModEntries.ModDirectory + "/config.json"); - public static class ScaffoldBlockCode - { - public static void AddScaffolds (Vector3Int position, ushort newtype, Players.Player causedBy) - { - string itemtypeFullname = ItemTypes.IndexLookup.GetName (newtype); - string blueprintBasename = itemtypeFullname.Substring (0, itemtypeFullname.Length - 2); - ushort bluetype = newtype; - if (blueprintBasename.EndsWith (CapsulesModEntries.CAPSULE_SUFFIX)) { - blueprintBasename = blueprintBasename.Substring (0, blueprintBasename.Length - CapsulesModEntries.CAPSULE_SUFFIX.Length); - bluetype = ItemTypes.IndexLookup.GetIndex (blueprintBasename + itemtypeFullname.Substring (itemtypeFullname.Length - 2)); - } - List blocks; - if (ManagerBlueprints.Blueprints.TryGetValue (blueprintBasename, out blocks)) { - if (blocks.Count > ScaffoldsModEntries.MAX_PREVIEW_BLOCKS_THRESHOLD) { - Chat.Send (causedBy, "Blueprint contains too many blocks for preview"); - return; + if(!config.TryGetAs("previewBlocks", out PREVIEW_BLOCKS)) + PREVIEW_BLOCKS = DEFAULT_PREVIEW; + + if(PREVIEW_BLOCKS > MAX_PREVIEW) + { + Log.Write(string.Format("Warning: previewBlocks must be between {0} and {1} included", MIN_PREVIEW, MAX_PREVIEW)); + PREVIEW_BLOCKS = MAX_PREVIEW; + } + else if(PREVIEW_BLOCKS < MIN_PREVIEW) + { + Log.Write(string.Format("Warning: previewBlocks must be between {0} and {1} included", MIN_PREVIEW, MAX_PREVIEW)); + PREVIEW_BLOCKS = MIN_PREVIEW; + } + } + catch(System.Exception) + { + PREVIEW_BLOCKS = DEFAULT_PREVIEW; + } } - ushort scaffoldType = ItemTypes.IndexLookup.GetIndex (ScaffoldsModEntries.SCAFFOLD_ITEM_TYPE); - foreach (BlueprintTodoBlock block in blocks) { - if (block.Typename.Equals ("air")) { - continue; - } - Vector3Int realPos = block.GetWorldPosition (blueprintBasename, position, bluetype); - if (World.TryGetTypeAt (realPos, out ushort wasType) && wasType == BuiltinBlocks.Air) { - ServerManager.TryChangeBlock (realPos, scaffoldType, causedBy); - } + + [ModLoader.ModCallback(ModLoader.EModCallbackType.AfterItemTypesDefined, "scarabol.scaffolds.registertypes")] + public static void AfterItemTypesDefined() + { + foreach(string blueprintTypename in ManagerBlueprints.Blueprints.Keys) + { + ItemTypesServer.RegisterOnAdd(blueprintTypename, ScaffoldBlockCode.AddScaffolds); + ItemTypesServer.RegisterOnAdd(blueprintTypename + CapsulesModEntries.CAPSULE_SUFFIX, ScaffoldBlockCode.AddScaffolds); + ItemTypesServer.RegisterOnRemove(blueprintTypename, ScaffoldBlockCode.RemoveScaffolds); + ItemTypesServer.RegisterOnRemove(blueprintTypename + CapsulesModEntries.CAPSULE_SUFFIX, ScaffoldBlockCode.RemoveScaffolds); + } } - ThreadManager.InvokeOnMainThread (delegate () { - if (World.TryGetTypeAt (position, out ushort actualType) && actualType == newtype) { - RemoveScaffolds (position, bluetype, causedBy); - } - }, 8.0f); - } } - public static void RemoveScaffolds (Vector3Int position, ushort wastype, Players.Player causedBy) + public static class ScaffoldBlockCode { - string itemtypeFullname = ItemTypes.IndexLookup.GetName (wastype); - string blueprintBasename = itemtypeFullname.Substring (0, itemtypeFullname.Length - 2); - ushort bluetype = wastype; - if (blueprintBasename.EndsWith (CapsulesModEntries.CAPSULE_SUFFIX)) { - blueprintBasename = blueprintBasename.Substring (0, blueprintBasename.Length - CapsulesModEntries.CAPSULE_SUFFIX.Length); - bluetype = ItemTypes.IndexLookup.GetIndex (blueprintBasename + itemtypeFullname.Substring (itemtypeFullname.Length - 2)); - } - List blocks; - if (ManagerBlueprints.Blueprints.TryGetValue (blueprintBasename, out blocks)) { - if (blocks.Count > ScaffoldsModEntries.MAX_PREVIEW_BLOCKS_THRESHOLD) { - return; + public static void AddScaffolds(Vector3Int position, ushort newtype, Players.Player causedBy) + { + string itemtypeFullname = ItemTypes.IndexLookup.GetName(newtype); + string blueprintBasename = itemtypeFullname.Substring(0, itemtypeFullname.Length - 2); + ushort bluetype = newtype; + if(blueprintBasename.EndsWith(CapsulesModEntries.CAPSULE_SUFFIX)) + { + blueprintBasename = blueprintBasename.Substring(0, blueprintBasename.Length - CapsulesModEntries.CAPSULE_SUFFIX.Length); + bluetype = ItemTypes.IndexLookup.GetIndex(blueprintBasename + itemtypeFullname.Substring(itemtypeFullname.Length - 2)); + } + List blocks; + if(ManagerBlueprints.Blueprints.TryGetValue(blueprintBasename, out blocks)) + { + if(blocks.Count > ScaffoldsModEntries.PREVIEW_BLOCKS) + { + Chat.Send(causedBy, "Blueprint contains too many blocks for preview"); + return; + } + ushort scaffoldType = ItemTypes.IndexLookup.GetIndex(ScaffoldsModEntries.SCAFFOLD_ITEM_TYPE); + foreach(BlueprintTodoBlock block in blocks) + { + if(block.Typename.Equals("air")) + { + continue; + } + Vector3Int realPos = block.GetWorldPosition(blueprintBasename, position, bluetype); + if(World.TryGetTypeAt(realPos, out ushort wasType) && wasType == BuiltinBlocks.Air) + { + ServerManager.TryChangeBlock(realPos, scaffoldType, causedBy); + } + } + ThreadManager.InvokeOnMainThread(delegate () + { + if(World.TryGetTypeAt(position, out ushort actualType) && actualType == newtype) + { + RemoveScaffolds(position, bluetype, causedBy); + } + }, 8.0f); + } } - ushort scaffoldType = ItemTypes.IndexLookup.GetIndex (ScaffoldsModEntries.SCAFFOLD_ITEM_TYPE); - foreach (BlueprintTodoBlock block in blocks) { - if (block.Typename.Equals ("air")) { - continue; - } - Vector3Int realPos = block.GetWorldPosition (blueprintBasename, position, bluetype); - if (World.TryGetTypeAt (realPos, out ushort wasType) && wasType == scaffoldType) { - ServerManager.TryChangeBlock (realPos, BuiltinBlocks.Air, causedBy); - } + + public static void RemoveScaffolds(Vector3Int position, ushort wastype, Players.Player causedBy) + { + string itemtypeFullname = ItemTypes.IndexLookup.GetName(wastype); + string blueprintBasename = itemtypeFullname.Substring(0, itemtypeFullname.Length - 2); + ushort bluetype = wastype; + if(blueprintBasename.EndsWith(CapsulesModEntries.CAPSULE_SUFFIX)) + { + blueprintBasename = blueprintBasename.Substring(0, blueprintBasename.Length - CapsulesModEntries.CAPSULE_SUFFIX.Length); + bluetype = ItemTypes.IndexLookup.GetIndex(blueprintBasename + itemtypeFullname.Substring(itemtypeFullname.Length - 2)); + } + List blocks; + if(ManagerBlueprints.Blueprints.TryGetValue(blueprintBasename, out blocks)) + { + if(blocks.Count > ScaffoldsModEntries.PREVIEW_BLOCKS) + { + return; + } + ushort scaffoldType = ItemTypes.IndexLookup.GetIndex(ScaffoldsModEntries.SCAFFOLD_ITEM_TYPE); + foreach(BlueprintTodoBlock block in blocks) + { + if(block.Typename.Equals("air")) + { + continue; + } + Vector3Int realPos = block.GetWorldPosition(blueprintBasename, position, bluetype); + if(World.TryGetTypeAt(realPos, out ushort wasType) && wasType == scaffoldType) + { + ServerManager.TryChangeBlock(realPos, BuiltinBlocks.Air, causedBy); + } + } + } } - } } - } } diff --git a/src/Util.cs b/src/Util.cs index d7d932e..0ecf06b 100644 --- a/src/Util.cs +++ b/src/Util.cs @@ -8,164 +8,189 @@ namespace ScarabolMods { - public static class ModLocalizationHelper - { - public static void Localize (string localePath, string typesprefix) + public static class ModLocalizationHelper { - try { - string [] files = Directory.GetFiles (localePath, "translation.json", SearchOption.AllDirectories); - foreach (string filepath in files) { - try { - JSONNode jsonFromMod; - if (JSON.Deserialize (filepath, out jsonFromMod, false)) { - string locName = Directory.GetParent (filepath).Name; - Localize (locName, jsonFromMod, typesprefix); - } - } catch (Exception exception) { - Log.WriteError ($"Exception reading localization from {filepath}; {exception.Message}"); - } + public static void Localize(string localePath, string typesprefix) + { + try + { + string[] files = Directory.GetFiles(localePath, "translation.json", SearchOption.AllDirectories); + foreach(string filepath in files) + { + try + { + JSONNode jsonFromMod; + if(JSON.Deserialize(filepath, out jsonFromMod, false)) + { + string locName = Directory.GetParent(filepath).Name; + Localize(locName, jsonFromMod, typesprefix); + } + } + catch(Exception exception) + { + Log.WriteError($"Exception reading localization from {filepath}; {exception.Message}"); + } + } + } + catch(DirectoryNotFoundException) + { + Log.WriteError($"Localization directory not found at {localePath}"); + } } - } catch (DirectoryNotFoundException) { - Log.WriteError ($"Localization directory not found at {localePath}"); - } - } - public static void Localize (string locName, JSONNode jsonFromMod, string typesprefix) - { - try { - JSONNode locNode; - if (Localization.LoadedTranslation.TryGetValue (locName, out locNode)) { - var toCheck = new Queue (); - toCheck.Enqueue (new NodePair ("", jsonFromMod, locNode)); - while (toCheck.Count > 0) { - var current = toCheck.Dequeue (); - foreach (KeyValuePair cNode in current.First.LoopObject ()) { - string realkey; - if (current.Parent.Equals ("types") || current.Parent.Equals ("typeuses")) { - realkey = typesprefix + cNode.Key; - } else { - realkey = cNode.Key; - } - JSONNode gameNode; - if (current.Second.TryGetChild (realkey, out gameNode)) { - toCheck.Enqueue (new NodePair (realkey, cNode.Value, gameNode)); - } else { - current.Second.SetAs (realkey, cNode.Value); - } - } - } - } else { - Localization.LoadedTranslation.Add (locName, jsonFromMod); + // Thanks to ZUN for the help with the localization + public static void Localize(string locName, JSONNode jsonFromMod, string typesprefix) + { + try + { + if(jsonFromMod.HasChild("types")) + { + JSONNode arr = jsonFromMod["types"]; + JSONNode result = new JSONNode(); + foreach(var pair in arr.LoopObject()) + { + result[typesprefix + pair.Key] = pair.Value; + } + jsonFromMod["types"] = result; + } + if(jsonFromMod.HasChild("typeuses")) + { + JSONNode arr = jsonFromMod["typeuses"]; + JSONNode result = new JSONNode(); + foreach(var pair in arr.LoopObject()) + { + result[typesprefix + pair.Key] = pair.Value; + } + jsonFromMod["typeuses"] = result; + } + Localization.QueueLocalePatch(new Localization.LocalePatch(0, jsonFromMod, locName)); + } + catch(Exception exception) + { + Log.WriteError($"Exception while localization of {locName}; {exception.Message}"); + } } - } catch (Exception) { - Log.WriteError ($"Exception while localizing {locName}"); - } - } - class NodePair - { - public string Parent { get; private set; } + class NodePair + { + public string Parent { get; private set; } - public JSONNode First { get; private set; } + public JSONNode First { get; private set; } - public JSONNode Second { get; private set; } + public JSONNode Second { get; private set; } - public NodePair (string parent, JSONNode first, JSONNode second) - { - Parent = parent; - First = first; - Second = second; - } + public NodePair(string parent, JSONNode first, JSONNode second) + { + Parent = parent; + First = first; + Second = second; + } + } } - } - public static class MultiPath - { - public static string Combine (params string [] pathParts) + public static class MultiPath { - StringBuilder result = new StringBuilder (); - foreach (string part in pathParts) { - result.Append (part.TrimEnd ('/', '\\')).Append (Path.DirectorySeparatorChar); - } - return result.ToString ().TrimEnd (Path.DirectorySeparatorChar); + public static string Combine(params string[] pathParts) + { + StringBuilder result = new StringBuilder(); + foreach(string part in pathParts) + { + result.Append(part.TrimEnd('/', '\\')).Append(Path.DirectorySeparatorChar); + } + return result.ToString().TrimEnd(Path.DirectorySeparatorChar); + } } - } - public static class TypeHelper - { - public static string RotatableToBasetype (string typename) + public static class TypeHelper { - if (typename.EndsWith ("x+") || typename.EndsWith ("x-") || typename.EndsWith ("z+") || typename.EndsWith ("z-")) { - return typename.Substring (0, typename.Length - 2); - } - return typename; - } + public static string RotatableToBasetype(string typename) + { + if(typename.EndsWith("x+") || typename.EndsWith("x-") || typename.EndsWith("z+") || typename.EndsWith("z-")) + { + return typename.Substring(0, typename.Length - 2); + } + return typename; + } - public static string GetXZFromTypename (string typename) - { - if (typename.EndsWith ("x+") || typename.EndsWith ("x-") || typename.EndsWith ("z+") || typename.EndsWith ("z-")) { - return typename.Substring (typename.Length - 2); - } - return ""; - } + public static string GetXZFromTypename(string typename) + { + if(typename.EndsWith("x+") || typename.EndsWith("x-") || typename.EndsWith("z+") || typename.EndsWith("z-")) + { + return typename.Substring(typename.Length - 2); + } + return ""; + } - public static Vector3Int RotatableToVector (string typename) - { - string xz = GetXZFromTypename (typename); - if (xz.Equals ("x+")) { - return new Vector3Int (1, 0, 0); - } - if (xz.Equals ("x-")) { - return new Vector3Int (-1, 0, 0); - } - if (xz.Equals ("y+")) { - return new Vector3Int (0, 1, 0); - } - if (xz.Equals ("y-")) { - return new Vector3Int (0, -1, 0); - } - if (xz.Equals ("z+")) { - return new Vector3Int (0, 0, 1); - } - if (xz.Equals ("z-")) { - return new Vector3Int (0, 0, -1); - } - return new Vector3Int (0, 0, 0); - } + public static Vector3Int RotatableToVector(string typename) + { + string xz = GetXZFromTypename(typename); + if(xz.Equals("x+")) + { + return new Vector3Int(1, 0, 0); + } + if(xz.Equals("x-")) + { + return new Vector3Int(-1, 0, 0); + } + if(xz.Equals("y+")) + { + return new Vector3Int(0, 1, 0); + } + if(xz.Equals("y-")) + { + return new Vector3Int(0, -1, 0); + } + if(xz.Equals("z+")) + { + return new Vector3Int(0, 0, 1); + } + if(xz.Equals("z-")) + { + return new Vector3Int(0, 0, -1); + } + return new Vector3Int(0, 0, 0); + } - public static string VectorToXZ (Vector3Int vec) - { - if (vec.x == 1) { - return "x+"; - } - if (vec.x == -1) { - return "x-"; - } - if (vec.y == 1) { - return "y+"; - } - if (vec.y == -1) { - return "y-"; - } - if (vec.z == 1) { - return "z+"; - } - if (vec.z == -1) { - return "z-"; - } - Log.WriteError ($"Malformed vector {vec}"); - return "x+"; + public static string VectorToXZ(Vector3Int vec) + { + if(vec.x == 1) + { + return "x+"; + } + if(vec.x == -1) + { + return "x-"; + } + if(vec.y == 1) + { + return "y+"; + } + if(vec.y == -1) + { + return "y-"; + } + if(vec.z == 1) + { + return "z+"; + } + if(vec.z == -1) + { + return "z-"; + } + Log.WriteError($"Malformed vector {vec}"); + return "x+"; + } } - } - public static class JsonNodeExtension - { - public static T getAsOrElse (this JSONNode node, string identifier, string otherIdentifier) + public static class JsonNodeExtension { - if (!node.TryGetAs (identifier, out T result)) { - result = node.GetAs (otherIdentifier); - } - return result; + public static T getAsOrElse(this JSONNode node, string identifier, string otherIdentifier) + { + if(!node.TryGetAs(identifier, out T result)) + { + result = node.GetAs(otherIdentifier); + } + return result; + } } - } }