public override void OnNPCDoStockpile(ref NPCBase.NPCState state) { state.Inventory.TryDump(usedNPC.Colony.UsedStockpile); if (todoblocks.Count < 1) { ServerManager.TryChangeBlock(position, BlockTypes.Builtin.BuiltinBlocks.Air); 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")) { ushort typeindex; if (ItemTypes.IndexLookup.TryGetIndex(TypeHelper.RotatableToBasetype(block.typename), out 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 { Chat.Send(usedNPC.Colony.Owner, string.Format("Bob here from site at {0}, the item type '{1}' does not exist. Ignoring it...", position, block.typename)); todoblocks.RemoveAt(i); } } else { shouldTakeItems = false; } } } if (todoblocks.Count < 1) { ServerManager.TryChangeBlock(position, BlockTypes.Builtin.BuiltinBlocks.Air); return; } else if (shouldTakeItems) { state.JobIsDone = false; state.SetIndicator(NPCIndicatorType.MissingItem, 6f, ItemTypes.IndexLookup.GetIndex(todoblocks[todoblocks.Count - 1].typename)); } }
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; } } } 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 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 (!placed) { BlockInventory.Dump(usedNPC.Inventory); ShouldTakeItems = true; } } }
public static void LoadBlueprints(string blueprintsPath) { long startLoadingBlueprints = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; Dictionary <string, string> prefixesBlueprints = new Dictionary <string, string> (); Dictionary <string, string> prefixesCapsules = new Dictionary <string, string> (); 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 <string, BlueprintTodoBlock> blocks = new Dictionary <string, BlueprintTodoBlock> (); 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 <int> ("x"); offy = -jsonOffset.GetAs <int> ("y"); offz = -jsonOffset.GetAs <int> ("z"); } JSONNode jsonLocalization; if (json.TryGetAs("localization", out jsonLocalization)) { foreach (KeyValuePair <string, JSONNode> 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 <JSONNode> ("types", new JSONNode()); BlueprintsLocalizations.Add(locEntry.Key, locNode); } locNode.GetAs <JSONNode> ("types").SetAs(blueprintName, labelPrefix + " " + label); locNode.GetAs <JSONNode> ("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}"); } } 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"); }
public override void OnNPCDoJob(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; ushort bluetype = ItemTypes.IndexLookup.GetIndex(fullname); ushort scaffoldType = ItemTypes.IndexLookup.GetIndex(ScaffoldsModEntries.SCAFFOLD_ITEM_TYPE); string jobname = fullname.Substring(0, fullname.Length - 2); 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; } ushort newType = ItemTypes.IndexLookup.GetIndex(todoblock.typename); ushort actualType; if (World.TryGetTypeAt(realPosition, out actualType) && actualType != newType) { ushort baseType = ItemTypes.IndexLookup.GetIndex(TypeHelper.RotatableToBasetype(todoblock.typename)); if (newType == BlockTypes.Builtin.BuiltinBlocks.Air || blockInventory.TryGetOneItem(baseType)) { todoblocks.RemoveAt(i); if (ServerManager.TryChangeBlock(realPosition, newType, ServerManager.SetBlockFlags.DefaultAudio)) { state.JobIsDone = true; if (newType == BlockTypes.Builtin.BuiltinBlocks.Air) { OverrideCooldown(ConstructionModEntries.EXCAVATION_DELAY); state.SetIndicator(NPCIndicatorType.MissingItem, ConstructionModEntries.EXCAVATION_DELAY, actualType); } else if (!blockInventory.IsEmpty && i > 0) { state.SetIndicator(NPCIndicatorType.Crafted, TimeBetweenJobs, ItemTypes.IndexLookup.GetIndex(todoblocks[i].typename)); } if (actualType != BlockTypes.Builtin.BuiltinBlocks.Air && actualType != scaffoldType) { usedNPC.Inventory.Add(ItemTypes.RemovalItems(actualType)); } placed = true; break; } } } else { todoblocks.RemoveAt(i); } } if (!placed) { blockInventory.Dump(usedNPC.Inventory); shouldTakeItems = true; } } }