public override void FinishLoading() { base.FinishLoading(); if (legacyJSON != null) { foreach (var pair in legacyJSON.LoopObject()) { try { Players.Player player = Players.GetPlayer(NetworkID.Parse(pair.Key)); for (int i = 0; i < pair.Value.ChildCount; i++) { JSONNode jobNode = pair.Value[i]; int npcID = jobNode.GetAsOrDefault("npcID", 0); Vector3Int min = (Vector3Int)jobNode["positionMin"]; Vector3Int max = (Vector3Int)jobNode["positionMax"]; var job = new DefaultFarmerAreaJob <TemperateForesterDefinition>(player, min, max, npcID); if (!AreaJobTracker.RegisterAreaJob(job)) { job.OnRemove(); } } } catch (System.Exception e) { Log.WriteException("Exception loading legacy area job data", e); } } legacyJSON = null; } }
public static void OpenMenu(Players.Player player, PlayerClickedData playerClickData) { if (ItemTypes.IndexLookup.TryGetIndex(SchematicTool.NAME, out var schematicItem) && playerClickData.TypeSelected == schematicItem) { if (player.ActiveColony == null) { PandaChat.Send(player, _localizationHelper, "ErrorOpening", ChatColor.red); return; } if (!_awaitingClick.ContainsKey(player)) { SendMainMenu(player); } else { var tuple = _awaitingClick[player]; _awaitingClick.Remove(player); switch (tuple.Item1) { case SchematicClickType.Build: Vector3Int location = playerClickData.GetVoxelHit().BlockHit.Add(0, 1, 0); var args = new JSONNode(); args.SetAs("constructionType", GameLoader.NAMESPACE + ".SchematicBuilder"); args.SetAs(SchematicBuilderLoader.NAME + ".SchematicName", tuple.Item2); args.SetAs(SchematicBuilderLoader.NAME + ".Rotation", tuple.Item3); if (SchematicReader.TryGetSchematic(tuple.Item2, player.ActiveColony.ColonyID, location, out var schematic)) { if (tuple.Item3 >= Schematic.Rotation.Right) { schematic.Rotate(); } if (tuple.Item3 >= Schematic.Rotation.Back) { schematic.Rotate(); } if (tuple.Item3 >= Schematic.Rotation.Left) { schematic.Rotate(); } var maxSize = location.Add(schematic.XMax - 1, schematic.YMax - 1, schematic.ZMax - 1); AreaJobTracker.CreateNewAreaJob("pipliz.constructionarea", args, player.ActiveColony, location, maxSize); AreaJobTracker.SendData(player); } break; case SchematicClickType.Archetect: break; } } } }
bool CreateFieldAndJob(Vector3Int center) { if (!IsClear(center.Add(-5, 0, -5), 11, 2, 11)) { return(false); } var crateZ = -4 + Random.Next(10); BlockPlacementHelper.PlaceBlock(center.Add(-5, 0, crateZ), BuiltinBlocks.Crate, Owner); BlockPlacementHelper.PlaceBlock(center.Add(-5, 1, crateZ), BuiltinBlocks.TorchYP, Owner); var min = center.Add(-4, 0, -4); var max = center.Add(5, 0, 5); for (int x = min.x; x < max.x; x++) { for (int z = min.z; z < max.z; z++) { bool solid; if (!World.TryIsSolid(new Vector3Int(x, center.y - 1, z), out solid) || !solid) { return(false); } } } AreaJobTracker.CreateNewAreaJob("pipliz.wheatfarm", Owner, min, max); return(true); }
public void SetCorner2(Vector3Int newPos, Players.Player player) { pos2 = newPos; corner1 = Vector3Int.Min(pos1, pos2); corner2 = Vector3Int.Max(pos1, pos2); AreaJobTracker.SendData(player); }
// add player to list public static bool Add(Players.Player player) { if (playerList.Contains(player)) { return(false); } playerList.Add(player); AreaJobTracker.SendData(player); return(true); }
// remove player from list public static bool Remove(Players.Player player) { if (playerList.Contains(player)) { playerList.Remove(player); AreaJobTracker.SendData(player); return(true); } return(false); }
public static void OnTryChangeBlockUser(ModLoader.OnTryChangeBlockData userData) { if (userData.TypeNew == ItemTypes.IndexLookup.GetIndex("Ulfric.ColonyAddOns.Blocks.AppleBasket") && userData.TypeOld == BuiltinBlocks.Air) { Logger.Log("Check if area is clear for AppleFarmer"); Vector3Int position = userData.Position; int xlen = 7; int zlen = 7; int radius = 3; //set NW corner Vector3Int nwcorner = new Vector3Int(position.x - radius, position.y, position.z - radius); Vector3Int secorner = new Vector3Int(position.x + radius, position.y, position.z + radius); bool blocked = false; for (int x = 0; x <= xlen; x++) { for (int z = 0; z <= zlen; z++) { if (World.TryGetTypeAt(nwcorner.Add(x, 0, z), out ushort val) && val != BuiltinBlocks.Air) { blocked = true; } } } if (blocked) { Chat.Send(userData.RequestedByPlayer, "Apple Farmer 9 x 9 area is blocked."); } else { AreaJobTracker.CreateNewAreaJob("Ulfric.ColonyAddOns.AreaJobs.AppleFarm", userData.RequestedByPlayer, nwcorner, secorner); ThreadManager.InvokeOnMainThread(delegate() { ServerManager.TryChangeBlock(position, userData.TypeNew); }, 0.1f); } } if (userData.TypeOld == ItemTypes.IndexLookup.GetIndex("Ulfric.ColonyAddOns.Blocks.AppleBasket") && userData.TypeNew == BuiltinBlocks.Air) { Logger.Log("Remove job"); Vector3Int position = userData.Position; int xlen = 7; int zlen = 7; int radius = 3; //set NW corner Vector3Int nwcorner = new Vector3Int(position.x - radius, position.y, position.z - radius); Vector3Int secorner = new Vector3Int(position.x + radius, position.y, position.z + radius); AreaJobTracker.RemoveJobAt(nwcorner, secorner); } }
static void Load() { if (queuedDefinitions != null) { for (int i = 0; i < queuedDefinitions.Count; i++) { try { AreaJobTracker.RegisterAreaJobDefinition((IAreaJobDefinition)Activator.CreateInstance(queuedDefinitions[i])); } catch (Exception e) { Log.WriteException(e); } } queuedDefinitions = null; } }
public virtual void LoadJSON(JSONNode node) { JSONNode table = node.GetAs <JSONNode>("table"); foreach (var pair in table.LoopObject()) { Players.Player player = Players.GetPlayer(NetworkID.Parse(pair.Key)); JSONNode array = pair.Value; for (int i = 0; i < array.ChildCount; i++) { var job = CreateAreaJob(player, array[i]); if (!AreaJobTracker.RegisterAreaJob(job)) { job.OnRemove(); } } } }
private static void CleanupJob(IIterationType iterationType, IAreaJob areaJob, ConstructionJobInstance job, ArchitectIterator bpi, int prvX, int prvY, int prvZ) { if (_needsChunkLoaded.Contains(bpi)) { _needsChunkLoaded.Remove(bpi); } if (bpi.PreviousPosition != Pipliz.Vector3Int.invalidPos && prvX <= bpi.BuilderSchematic.XMax && prvY <= bpi.BuilderSchematic.YMax && prvZ <= bpi.BuilderSchematic.ZMax && !bpi.BuilderSchematic.Blocks[prvX, prvY, prvZ].BlockID.Contains("bedend")) { ServerManager.TryChangeBlock(bpi.PreviousPosition, ItemId.GetItemId(bpi.BuilderSchematic.Blocks[prvX, prvY, prvZ].BlockID).Id, new BlockChangeRequestOrigin(job.Owner), ESetBlockFlags.DefaultAudio); } SchematicReader.SaveSchematic(areaJob.Owner, bpi.BuilderSchematic); AreaJobTracker.RemoveJob(areaJob); }
public void OnAssemblyLoaded(string path) { //Register loader for Construction job callback ConstructionArea.RegisterLoader((IConstructionLoader) new ReplacerSpecialLoader()); ConstructionArea.RegisterLoader((IConstructionLoader) new ShapeBuilderLoader("wingdings.walls")); ConstructionArea.RegisterLoader((IConstructionLoader) new ShapeBuilderLoader("wingdings.pyramid")); ConstructionArea.RegisterLoader((IConstructionLoader) new ShapeBuilderLoader("wingdings.circle")); //Override identifier so we can create our own callback using the Construction Job AreaJobTracker.RegisterAreaJobDefinition(new CustomConstructionAreaJobDefinition()); CommandToolManager.AddAreaJobSettings(new ConstructionAreaToolSettings("wingdings.tooljob.walls", "wingdings.walls", "wingdings.builder.2d", EConstructionKind.Builder, 1, EAreaItemSelectionFilter.ComboBuildable)); CommandToolManager.AddAreaJobSettings(new ConstructionAreaToolSettings("wingdings.tooljob.pyramid", "wingdings.pyramid", "wingdings.builder.3d", EConstructionKind.Builder, 1, EAreaItemSelectionFilter.ComboBuildable)); CommandToolManager.AddAreaJobSettings(new ConstructionAreaToolSettings("wingdings.tooljob.circle", "wingdings.circle", "wingdings.builder.2d", EConstructionKind.Builder, 1, EAreaItemSelectionFilter.ComboBuildable)); //dictionary.Add("pipliz.digger", ("popup.tooljob.diggera", "popup.tooljob.diggerb")); CommandToolManager.AddButtonTooltip("wingdings.tooljob.replacer", "wingdings.tooljob.replacera", "wingdings.tooljob.replacerb"); CommandToolManager.AddButtonTooltip("wingdings.tooljob.walls", "wingdings.tooljob.wallsa", "wingdings.tooljob.wallsb"); CommandToolManager.AddButtonTooltip("wingdings.tooljob.pyramid", "wingdings.tooljob.pyramida", "wingdings.tooljob.pyramidb"); CommandToolManager.AddButtonTooltip("wingdings.tooljob.circle", "wingdings.tooljob.circlea", "wingdings.tooljob.circleb"); }
public bool TryDoCommand(Players.Player causedBy, string chattext, List <string> splits) { if (!splits[0].Equals("/areashow")) { return(false); } if (!PermissionsManager.CheckAndWarnPermission(causedBy, AntiGrief.MOD_PREFIX + "areashow")) { return(true); } // if parameter action given toggle all areas shown Match m = Regex.Match(chattext, @"/areashow ?(?<action>.+)?"); string action = m.Groups["action"].Value; if (action.Equals("add")) { if (AreaShowManager.Add(causedBy)) { Chat.Send(causedBy, "You now see area jobs of all players"); } return(true); } else if (action.Equals("remove")) { if (AreaShowManager.Remove(causedBy)) { Chat.Send(causedBy, "You no longer see area jobs of all players"); } return(true); } // without action parameter just trigger a data send AreaJobTracker.SendData(causedBy); return(true); }
public override void OnNPCAtJob(ref NPCBase.NPCState state) { if (constructionArea != null && !constructionArea.IsValid) { constructionArea = null; } if (worldTypeChecked) { Vector3 pos = usedNPC.Position.Vector; if (worldType == BuiltinBlocks.ConstructionJobXP) { usedNPC.LookAt(pos + Vector3.right); } else if (worldType == BuiltinBlocks.ConstructionJobXN) { usedNPC.LookAt(pos + Vector3.left); } else if (worldType == BuiltinBlocks.ConstructionJobZP) { usedNPC.LookAt(pos + Vector3.forward); } else if (worldType == BuiltinBlocks.ConstructionJobZN) { usedNPC.LookAt(pos + Vector3.back); } } if (constructionArea == null) { List <IAreaJob> jobs; if (AreaJobTracker.ExistingAreaAt(position.Add(-1, -1, -1), position.Add(1, 1, 1), out jobs)) { for (int i = 0; i < jobs.Count; i++) { ConstructionArea neighbourArea = jobs[i] as ConstructionArea; if (neighbourArea != null) { constructionArea = neighbourArea; break; } } AreaJobTracker.AreaJobListPool.Return(jobs); } if (constructionArea == null) { if (isAreaPresenceTestDone) { state.SetCooldown(0.5); ServerManager.TryChangeBlock(position, 0); } else { state.SetIndicator(new Shared.IndicatorState(Random.NextFloat(3f, 5f), BuiltinBlocks.ErrorIdle)); isAreaPresenceTestDone = true; } return; } } Assert.IsNotNull(constructionArea); constructionArea.DoJob(this, ref state); }
public void DoJob(IIterationType iterationType, IAreaJob areaJob, ConstructionJobInstance job, ref NPCBase.NPCState state) { int i = 0; var bpi = iterationType as ArchitectIterator; if (bpi == null) { SettlersLogger.Log(ChatColor.yellow, "iterationType must be of type ArchitectIterator for the ArchitectBuilder."); state.SetIndicator(new Shared.IndicatorState(5f, ColonyBuiltIn.ItemTypes.ERRORIDLE.Name)); AreaJobTracker.RemoveJob(areaJob); return; } while (true) // move past air { if (i > 4000) { break; } i++; var adjX = iterationType.CurrentPosition.x - bpi.BuilderSchematic.StartPos.x; var adjY = iterationType.CurrentPosition.y - bpi.BuilderSchematic.StartPos.y; var adjZ = iterationType.CurrentPosition.z - bpi.BuilderSchematic.StartPos.z; var prvX = bpi.PreviousPosition.x - bpi.BuilderSchematic.StartPos.x; var prvY = bpi.PreviousPosition.y - bpi.BuilderSchematic.StartPos.y; var prvZ = bpi.PreviousPosition.z - bpi.BuilderSchematic.StartPos.z; if (World.TryGetTypeAt(iterationType.CurrentPosition, out ItemTypes.ItemType foundType)) { state.SetCooldown(2); state.SetIndicator(new Shared.IndicatorState(2, foundType.Name)); if (foundType.ItemIndex == ColonyBuiltIn.ItemTypes.AIR || foundType.Name == ColonyBuiltIn.ItemTypes.BANNER) { if (!MoveNext(iterationType, areaJob, job, bpi, prvX, prvY, prvZ)) { return; } continue; } try { bpi.BuilderSchematic.Blocks[adjX, adjY, adjZ].BlockID = foundType.Name; } catch (IndexOutOfRangeException) { SettlersLogger.Log(ChatColor.red, $"Index out of range on ArchitectBuilder {adjX}, {adjY}, {adjZ} to a max of {bpi.BuilderSchematic.Blocks.GetLength(0)}, {bpi.BuilderSchematic.Blocks.GetLength(1)}, {bpi.BuilderSchematic.Blocks.GetLength(2)}."); CleanupJob(iterationType, areaJob, job, bpi, prvX, prvY, prvZ); break; } if (!foundType.Name.Contains("bedend")) { ServerManager.TryChangeBlock(iterationType.CurrentPosition, SettlersBuiltIn.ItemTypes.SELECTOR.Id, new BlockChangeRequestOrigin(job.Owner), ESetBlockFlags.DefaultAudio); } MoveNext(iterationType, areaJob, job, bpi, prvX, prvY, prvZ); } else { if (!_needsChunkLoaded.Contains(bpi)) { _needsChunkLoaded.Add(bpi); } ChunkQueue.QueuePlayerSurrounding(iterationType.CurrentPosition.ToChunk()); state.SetIndicator(new Shared.IndicatorState(5f, ColonyBuiltIn.ItemTypes.ERRORIDLE.Name)); } break; } }
public virtual void OnNPCAtJob(IAreaJob job, ref Vector3Int positionSub, ref NPCBase.NPCState state, ref bool shouldDumpInventory) { if (stages == null || stages.Length < 2) { state.SetCooldown(1.0); return; } state.JobIsDone = true; if (positionSub.IsValid) { ushort type; if (World.TryGetTypeAt(positionSub, out type)) { ushort typeSeeds = stages[0]; ushort typeFinal = stages[stages.Length - 1]; if (type == 0) { if (state.Inventory.TryGetOneItem(typeSeeds) || job.NPC.Colony.UsedStockpile.TryRemove(typeSeeds)) { ushort typeBelow; if (World.TryGetTypeAt(positionSub.Add(0, -1, 0), out typeBelow)) { // check for fertile below if (ItemTypes.GetType(typeBelow).IsFertile) { ServerManager.TryChangeBlock(positionSub, typeSeeds, job.Owner, ServerManager.SetBlockFlags.DefaultAudio); state.SetCooldown(1.0); shouldDumpInventory = false; } else { // not fertile below AreaJobTracker.RemoveJob(job); state.SetCooldown(2.0); } } else { // didn't load this part of the world state.SetCooldown(Random.NextFloat(3f, 6f)); } } else { state.SetIndicator(new Shared.IndicatorState(2f, typeSeeds, true, false)); shouldDumpInventory = state.Inventory.UsedCapacity > 0f; } } else if (type == typeFinal) { if (ServerManager.TryChangeBlock(positionSub, 0, job.Owner, ServerManager.SetBlockFlags.DefaultAudio)) { GatherResults.Clear(); var results = ItemTypes.GetType(typeFinal).OnRemoveItems; for (int i = 0; i < results.Count; i++) { GatherResults.Add(results[i]); } ModLoader.TriggerCallbacks(ModLoader.EModCallbackType.OnNPCGathered, job as IJob, positionSub, GatherResults); job.NPC.Inventory.Add(GatherResults); } state.SetCooldown(1.0); shouldDumpInventory = false; } else { shouldDumpInventory = state.Inventory.UsedCapacity > 0f; Server.GrowableBlocks.IGrowableBlock block; if (Server.GrowableBlocks.GrowableBlockManager.TryGetGrowableBlock(positionSub, out block)) { state.SetCooldown(5.0); } else { bool found = false; for (int i = 0; i < stages.Length; i++) { if (stages[i] == type) { ItemTypesServer.OnChange(positionSub, 0, type, null); state.SetIndicator(new Shared.IndicatorState(2f, type)); state.SetCooldown(0.2); found = true; break; } } if (!found) { state.SetCooldown(5.0); } } } } else { state.SetCooldown(Random.NextFloat(3f, 6f)); } positionSub = Vector3Int.invalidPos; } else { state.SetCooldown(10.0); } }
public virtual void DoJob(IJob job, ref NPCBase.NPCState state) { while (iterationChunk0.y >= (positionMin.y & -16)) { while (iterationChunk0.x <= (positionMax.x & -16)) { while (iterationChunk0.z <= (positionMax.z & -16)) { while (iterationChunk1.y >= iterationChunk0.y) { while (iterationChunk1.x < iterationChunk0.x + 16) { while (iterationChunk1.z < iterationChunk0.z + 16) { while (iterationChunk2.y >= iterationChunk1.y) { while (iterationChunk2.x < iterationChunk1.x + 8) { while (iterationChunk2.z < iterationChunk1.z + 8) { while (iterationPosition.y >= 0) { while (iterationPosition.x < 4) { while (iterationPosition.z < 4) { Vector3Int pos = iterationChunk2 + iterationPosition; if (DoJobAt(job, ref state, ref pos)) { return; } } iterationPosition.z = 0; iterationPosition.x++; } iterationPosition.x = 0; iterationPosition.y--; } // completed 4x4x4 box, increment z & reset iteration position iterationPosition = new Vector3Int(0, 4, 0); iterationChunk2.z += 4; } // completed 4x4x4 box row, increment x & reset z to start the new row iterationChunk2.x += 4; iterationChunk2.z = iterationChunk1.z; } // completed 4x4x4 box layer, decrement y & reset x to start the new layer iterationChunk2.y -= 4; iterationChunk2.x = iterationChunk1.x; } // completed 8x8x8 box, increment z & reset sub-boxes iterationChunk1.z += 8; iterationChunk2 = iterationChunk1.Add(0, 4, 0); } // completed 8x8x8 box row, increment x & reset z to start the new row iterationChunk1.x += 8; iterationChunk1.z = iterationChunk0.z; iterationChunk2 = iterationChunk1.Add(0, 4, 0); } // completed 8x8x8 box layer, restart at lower level iterationChunk1.x = iterationChunk0.x; iterationChunk1.y -= 8; iterationChunk2 = iterationChunk1.Add(0, 4, 0); } // completed 16x16x16 chunk, increment z & reset 8x8x8 cube position iterationChunk0.z += 16; iterationChunk1 = iterationChunk0.Add(0, 8, 0); iterationChunk2 = iterationChunk0.Add(0, 8 + 4, 0); } // completed 16x16x16 chunk row, increment x & reset z to start the new row iterationChunk0.z = positionMin.z & -16; iterationChunk0.x += 16; iterationChunk1 = iterationChunk0.Add(0, 8, 0); iterationChunk2 = iterationChunk0.Add(0, 8 + 4, 0); } // completed 16x16x16 chunk layer, decrement y iterationChunk0.x = positionMin.x & -16; iterationChunk0.y -= 16; iterationChunk1 = iterationChunk0.Add(0, 8, 0); iterationChunk2 = iterationChunk0.Add(0, 8 + 4, 0); } // completed area, remove it state.SetIndicator(new Shared.IndicatorState(5f, BuiltinBlocks.ErrorIdle)); AreaJobTracker.RemoveJob(this); }
public void DoJob(IIterationType iterationType, IAreaJob job, ref NPC.NPCBase.NPCState state) { if (iterationType == null) { AreaJobTracker.RemoveJob(job); return; } while (true) { Vector3Int jobPosition = iterationType.CurrentPosition; ushort foundTypeIndex; if (World.TryGetTypeAt(jobPosition, out foundTypeIndex)) { if (!iterationType.MoveNext()) { // failed to find next position to do job at, self-destruct state.SetIndicator(new Shared.IndicatorState(5f, BuiltinBlocks.ErrorIdle)); AreaJobTracker.RemoveJob(job); return; } if (foundTypeIndex != 0) { ItemTypes.ItemType foundType = ItemTypes.GetType(foundTypeIndex); if (!foundType.IsDestructible) { continue; // skip this block, retry } if (ServerManager.TryChangeBlock(jobPosition, 0, job.Owner, ServerManager.SetBlockFlags.DefaultAudio)) { InventoryItem typeDropped = InventoryItem.Empty; var onRemoveItems = ItemTypes.GetType(foundTypeIndex).OnRemoveItems; for (int i = 0; i < onRemoveItems.Count; i++) { if (Random.NextDouble() <= onRemoveItems[i].chance) { typeDropped = onRemoveItems[i].item; state.Inventory.Add(typeDropped); } } float blockDestructionTime = GetCooldown(foundType.DestructionTime * 0.001f); if (typeDropped.Amount > 0) { state.SetIndicator(new Shared.IndicatorState(blockDestructionTime, typeDropped.Type)); } else { state.SetCooldown(blockDestructionTime); } } else { state.SetIndicator(new Shared.IndicatorState(5f, BuiltinBlocks.ErrorMissing, true, false)); } return; // either changed a block or set indicator, job done } else { continue; // found air, try next loop } // unreachable } else { state.SetIndicator(new Shared.IndicatorState(5f, BuiltinBlocks.ErrorMissing, true, false)); return; // end loop, wait for world to load } // unreachable } // unreachable }
public void DoJob(IIterationType iterationType, IAreaJob areaJob, ConstructionJob job, ref NPC.NPCBase.NPCState state) { if (iterationType == null || buildType == null || buildType.ItemIndex == 0) { AreaJobTracker.RemoveJob(areaJob); return; } int iMax = 4096; while (iMax-- > 0) { Vector3Int jobPosition = iterationType.CurrentPosition; ushort foundTypeIndex; if (World.TryGetTypeAt(jobPosition, out foundTypeIndex)) { if (foundTypeIndex == 0 || foundTypeIndex == BuiltinBlocks.Water) { Stockpile ownerStockPile = Stockpile.GetStockPile(areaJob.Owner); if (ownerStockPile.Contains(buildType.ItemIndex)) { if (ServerManager.TryChangeBlock(jobPosition, buildType.ItemIndex, areaJob.Owner, ServerManager.SetBlockFlags.DefaultAudio)) { if (--job.storedItems == 0) { state.JobIsDone = true; } ownerStockPile.TryRemove(buildType.ItemIndex); if (iterationType.MoveNext()) { state.SetIndicator(new Shared.IndicatorState(GetCooldown(), buildType.ItemIndex)); } else { // failed to find next position to do job at, self-destruct state.SetIndicator(new Shared.IndicatorState(5f, BuiltinBlocks.ErrorIdle)); AreaJobTracker.RemoveJob(areaJob); } return; } else { // shouldn't really happen, world not loaded (just checked) state.SetIndicator(new Shared.IndicatorState(5f, BuiltinBlocks.ErrorMissing, true, false)); } } else { // missing building item state.SetIndicator(new Shared.IndicatorState(Random.NextFloat(5f, 8f), buildType.ItemIndex, true, false)); } return; // either changed a block or set indicator, job done } else { // move iterator, not placing at non-air blocks if (iterationType.MoveNext()) { continue; // found non-air, try next loop } else { // failed to find next position to do job at, self-destruct state.SetIndicator(new Shared.IndicatorState(5f, BuiltinBlocks.ErrorIdle)); AreaJobTracker.RemoveJob(areaJob); return; } } // unreachable } else { state.SetIndicator(new Shared.IndicatorState(5f, BuiltinBlocks.ErrorMissing, true, false)); return; // end loop, wait for world to load } // unreachable } // reached loop count limit Assert.IsTrue(iMax <= 0); state.SetCooldown(1.0); }
private static void Right_Click(Players.Player player) { int forester = last_forester.GetValueOrDefault(player.ID, 0); AreaJobTracker.CommandToolTypeData data = new AreaJobTracker.CommandToolTypeData(); switch (forester) { default: case 0: data.LocaleEntry = "popup.tooljob.cherryforester"; data.AreaType = "Khanx.CherryForester"; break; case 1: data.LocaleEntry = "popup.tooljob.taigaforester"; data.AreaType = "Khanx.TaigaForester"; break; case 2: data.LocaleEntry = "popup.tooljob.oliveforester"; data.AreaType = "Khanx.OliveForester"; break; case 3: data.LocaleEntry = "popup.tooljob.autumredforester"; data.AreaType = "Khanx.AutummRedForester"; break; case 4: data.LocaleEntry = "popup.tooljob.autummorangeforester"; data.AreaType = "Khanx.AutummOrangeForester"; break; case 5: data.LocaleEntry = "popup.tooljob.autumyellowforester"; data.AreaType = "Khanx.AutummYellowForester"; break; case 6: data.LocaleEntry = "popup.tooljob.darktemperateforester"; data.AreaType = "Khanx.DarkTemperateForester"; break; case 7: data.LocaleEntry = "popup.tooljob.temperateforester"; data.AreaType = "Khanx.TemperateForester"; break; case 8: data.LocaleEntry = "popup.tooljob.lighttemperateforester"; data.AreaType = "Khanx.LightTemperateForester"; break; } data.Minimum3DBlockCount = 36; data.Maximum3DBlockCount = 100; data.Minimum2DBlockCount = 36; data.Maximum2DBlockCount = 100; data.MinimumHeight = 1; data.MaximumHeight = 3; data.OneAreaOnly = true; AreaJobTracker.StartCommandToolSelection(player, data); }
public void DoJob(IIterationType iterationType, IAreaJob areaJob, ConstructionJobInstance job, ref NPCBase.NPCState state) { int i = 0; var bpi = iterationType as SchematicIterator; if (bpi == null) { SettlersLogger.Log(ChatColor.yellow, "iterationType must be of type SchematicIterator for the SchematicBuilder."); state.SetIndicator(new Shared.IndicatorState(5f, ColonyBuiltIn.ItemTypes.ERRORIDLE.Name)); AreaJobTracker.RemoveJob(areaJob); return; } while (true) // This is to move past air. { if (i > 4000) { break; } var adjX = iterationType.CurrentPosition.x - bpi.BuilderSchematic.StartPos.x; var adjY = iterationType.CurrentPosition.y - bpi.BuilderSchematic.StartPos.y; var adjZ = iterationType.CurrentPosition.z - bpi.BuilderSchematic.StartPos.z; var block = bpi.BuilderSchematic.GetBlock(adjX, adjY, adjZ); var mapped = block.MappedBlock; var buildType = ItemTypes.GetType(mapped.CSIndex); if (buildType == null) { state.SetIndicator(new Shared.IndicatorState(5f, ColonyBuiltIn.ItemTypes.ERRORIDLE.Name)); AreaJobTracker.RemoveJob(areaJob); return; } if (World.TryGetTypeAt(iterationType.CurrentPosition, out ushort foundTypeIndex)) { i++; var founditemId = ItemId.GetItemId(foundTypeIndex); if (foundTypeIndex == buildType.ItemIndex || buildType.Name.Contains("bedend") || (founditemId.Name.Contains("bedend") && buildType.ItemIndex == ColonyBuiltIn.ItemTypes.AIR)) // check if the blocks are the same, if they are, move past. Most of the time this will be air. { if (iterationType.MoveNext()) { continue; } else { if (_needsChunkLoaded.Contains(bpi)) { _needsChunkLoaded.Remove(bpi); } state.SetIndicator(new Shared.IndicatorState(5f, ColonyBuiltIn.ItemTypes.ERRORIDLE.Name)); AreaJobTracker.RemoveJob(areaJob); return; } } Stockpile ownerStockPile = areaJob.Owner.Stockpile; bool stockpileContainsBuildItem = buildType.ItemIndex == ColonyBuiltIn.ItemTypes.AIR.Id; if (!stockpileContainsBuildItem && ownerStockPile.Contains(buildType.ItemIndex)) { stockpileContainsBuildItem = true; } if (!stockpileContainsBuildItem && buildType.Name.Contains("bed") && ownerStockPile.Contains(ItemId.GetItemId("bed"))) { stockpileContainsBuildItem = true; } if (!stockpileContainsBuildItem && !string.IsNullOrWhiteSpace(buildType.ParentType) && ownerStockPile.Contains(buildType.ParentItemType.ItemIndex)) { stockpileContainsBuildItem = true; } if (stockpileContainsBuildItem) { if (foundTypeIndex != ColonyBuiltIn.ItemTypes.AIR.Id && foundTypeIndex != ColonyBuiltIn.ItemTypes.WATER.Id) { var foundItem = ItemTypes.GetType(foundTypeIndex); if (foundItem != null && foundItem.ItemIndex != ColonyBuiltIn.ItemTypes.AIR.Id && foundItem.OnRemoveItems != null && foundItem.OnRemoveItems.Count > 0) { ownerStockPile.Add(foundItem.OnRemoveItems.Select(itm => itm.item).ToList()); } } var changeResult = ServerManager.TryChangeBlock(iterationType.CurrentPosition, buildType.ItemIndex, new BlockChangeRequestOrigin(job.Owner), ESetBlockFlags.DefaultAudio); if (changeResult == EServerChangeBlockResult.Success) { if (buildType.ItemIndex != ColonyBuiltIn.ItemTypes.AIR.Id) { if (--job.StoredItemCount <= 0) { job.ShouldTakeItems = true; state.JobIsDone = true; } ownerStockPile.TryRemove(buildType.ItemIndex); if (buildType.Name.Contains("bed")) { ownerStockPile.TryRemove(ItemId.GetItemId("bed")); } } } else if (changeResult != EServerChangeBlockResult.CancelledByCallback) { if (!_needsChunkLoaded.Contains(bpi)) { _needsChunkLoaded.Add(bpi); } state.SetIndicator(new Shared.IndicatorState(5f, buildType.Name)); ChunkQueue.QueuePlayerSurrounding(iterationType.CurrentPosition.ToChunk()); return; } } else { state.SetIndicator(new Shared.IndicatorState(5f, buildType.Name, true, false)); return; } } else { if (!_needsChunkLoaded.Contains(bpi)) { _needsChunkLoaded.Add(bpi); } ChunkQueue.QueuePlayerSurrounding(iterationType.CurrentPosition.ToChunk()); state.SetIndicator(new Shared.IndicatorState(5f, ColonyBuiltIn.ItemTypes.ERRORIDLE.Name)); return; } if (iterationType.MoveNext()) { if (buildType.ItemIndex != ColonyBuiltIn.ItemTypes.AIR.Id) { state.SetIndicator(new Shared.IndicatorState(GetCooldown(), buildType.ItemIndex)); } else { state.SetIndicator(new Shared.IndicatorState(GetCooldown(), foundTypeIndex)); } return; } else { if (_needsChunkLoaded.Contains(bpi)) { _needsChunkLoaded.Remove(bpi); } // failed to find next position to do job at, self-destruct state.SetIndicator(new Shared.IndicatorState(5f, ColonyBuiltIn.ItemTypes.ERRORIDLE.Name)); AreaJobTracker.RemoveJob(areaJob); return; } } if (iterationType.MoveNext()) { state.SetIndicator(new Shared.IndicatorState(5f, ColonyBuiltIn.ItemTypes.ERRORIDLE.Name)); return; } else { if (_needsChunkLoaded.Contains(bpi)) { _needsChunkLoaded.Remove(bpi); } // failed to find next position to do job at, self-destruct state.SetIndicator(new Shared.IndicatorState(5f, ColonyBuiltIn.ItemTypes.ERRORIDLE.Name)); AreaJobTracker.RemoveJob(areaJob); SettlersLogger.Log(ChatColor.yellow, "Failed to MoveNext after while. Iterator position: {0}.", iterationType.CurrentPosition); return; } }
public void DoJob( IIterationType iterationType, IAreaJob areaJob, ConstructionJobInstance job, ref NPCBase.NPCState state) { if (iterationType == null) { AreaJobTracker.RemoveJob(areaJob); } else { Stockpile stockpile = areaJob.Owner.Stockpile; int num = 4096; while (num-- > 0) { Vector3Int currentPosition = iterationType.CurrentPosition; if (!currentPosition.IsValid) { state.SetIndicator(new IndicatorState(5f, BuiltinBlocks.Indices.erroridle, false, true), true); AreaJobTracker.RemoveJob(areaJob); return; } ushort val; if (World.TryGetTypeAt(currentPosition, out val)) { if (val == (ushort)0) { iterationType.MoveNext(); continue; } ItemTypes.ItemType type = ItemTypes.GetType(val); if (!type.IsDestructible) { iterationType.MoveNext(); continue; } if (type != this.digType) { bool flag = false; for (ItemTypes.ItemType parentItemType = type.ParentItemType; parentItemType != (ItemTypes.ItemType)null; parentItemType = parentItemType.ParentItemType) { if (parentItemType == this.digType) { flag = true; break; } } if (!flag) { iterationType.MoveNext(); continue; } } if (!stockpile.Contains(this.buildType.ItemIndex, 1)) { float num2 = Random.NextFloat(5f, 8f); job.Owner.Stats.RecordNPCIdleSeconds(job.NPCType, num2); state.SetIndicator(new IndicatorState(num2, this.buildType.ItemIndex, true, false), true); return; } if (ServerManager.TryChangeBlock(currentPosition, this.buildType, (BlockChangeRequestOrigin)areaJob.Owner, ESetBlockFlags.DefaultAudio) == EServerChangeBlockResult.Success) { stockpile.TryRemove(this.buildType.ItemIndex, 1, true); float cooldown = ReplacerSpecial.GetCooldown((float)type.DestructionTime * (1f / 1000f)); ReplacerSpecial.GatherResults.Clear(); List <ItemTypes.ItemTypeDrops> onRemoveItems = type.OnRemoveItems; for (int index = 0; index < onRemoveItems.Count; ++index) { ReplacerSpecial.GatherResults.Add(onRemoveItems[index]); } ModLoader.Callbacks.OnNPCGathered.Invoke((IJob)job, currentPosition, ReplacerSpecial.GatherResults); InventoryItem weightedRandom = ItemTypes.ItemTypeDrops.GetWeightedRandom(ReplacerSpecial.GatherResults); if (weightedRandom.Amount > 0) { state.SetIndicator(new IndicatorState(cooldown, weightedRandom.Type, false, true), true); } else { state.SetCooldown((double)cooldown); } state.Inventory.Add((IList <ItemTypes.ItemTypeDrops>)ReplacerSpecial.GatherResults); ++job.StoredItemCount; iterationType.MoveNext(); if (job.StoredItemCount < this.MaxGatheredPerRun) { return; } job.ShouldTakeItems = true; state.JobIsDone = true; return; } state.SetIndicator(new IndicatorState(5f, BuiltinBlocks.Indices.missingerror, true, false), true); return; } else { state.SetIndicator(new IndicatorState(5f, BuiltinBlocks.Indices.missingerror, true, false), true); return; } } state.SetCooldown(0.8, 1.2); } }
public static void PressButton(ButtonPressCallbackData data) { switch (data.ButtonIdentifier) { case GameLoader.NAMESPACE + ".SetScemanticName": NetworkMenu saveMenu = new NetworkMenu(); saveMenu.LocalStorage.SetAs("header", _localizationHelper.LocalizeOrDefault("SaveSchematic", data.Player)); saveMenu.Width = 600; saveMenu.Height = 300; saveMenu.ForceClosePopups = true; saveMenu.Items.Add(new Label(new LabelData(_localizationHelper.GetLocalizationKey("SaveInstructions"), UnityEngine.Color.black))); saveMenu.Items.Add(new InputField("Construction.SetArchitectArea")); saveMenu.Items.Add(new ButtonCallback(GameLoader.NAMESPACE + ".SetArchitectArea", new LabelData(_localizationHelper.GetLocalizationKey("Start"), UnityEngine.Color.black))); NetworkMenuManager.SendServerPopup(data.Player, saveMenu); break; case GameLoader.NAMESPACE + ".SetArchitectArea": NetworkMenuManager.CloseServerPopup(data.Player); if (data.Storage.TryGetAs("Construction.SetArchitectArea", out string schematicName)) { var colonySaves = GameLoader.Schematic_SAVE_LOC + $"\\{data.Player.ActiveColony.ColonyID}\\"; if (!Directory.Exists(colonySaves)) { Directory.CreateDirectory(colonySaves); } var schematicFile = Path.Combine(colonySaves, schematicName + ".schematic"); if (File.Exists(schematicFile)) { File.Delete(schematicFile); } var metaDataSave = Path.Combine(GameLoader.Schematic_SAVE_LOC, schematicName + ".schematic.metadata.json"); if (File.Exists(metaDataSave)) { File.Delete(metaDataSave); } AreaJobTracker.StartCommandToolSelection(data.Player, new GenericCommandToolSettings() { Key = "pipliz.constructionarea", TranslationKey = _localizationHelper.LocalizeOrDefault("Architect", data.Player), JSONData = new JSONNode().SetAs(ArchitectLoader.NAME + ".ArchitectSchematicName", schematicName).SetAs("constructionType", GameLoader.NAMESPACE + ".Architect"), OneAreaOnly = true, Maximum3DBlockCount = int.MaxValue, Maximum2DBlockCount = int.MaxValue, MaximumHeight = int.MaxValue, MinimumHeight = 1, Minimum2DBlockCount = 1, Minimum3DBlockCount = 1 }); } break; case GameLoader.NAMESPACE + ".ShowMainMenu": SendMainMenu(data.Player); break; case GameLoader.NAMESPACE + ".ShowBuildDetails": List <FileInfo> options = SchematicReader.GetSchematics(data.Player); var index = data.Storage.GetAs <int>(Selected_Schematic); if (options.Count > index) { var selectedSchematic = options[index]; if (SchematicReader.TryGetSchematicMetadata(selectedSchematic.Name, data.Player.ActiveColony.ColonyID, out SchematicMetadata schematicMetadata)) { if (schematicMetadata.Blocks.Count == 1 && schematicMetadata.Blocks.ContainsKey(ColonyBuiltIn.ItemTypes.AIR.Id)) { PandaChat.Send(data.Player, _localizationHelper, "invlaidSchematic", ChatColor.red); } { NetworkMenu menu = new NetworkMenu(); menu.Width = 800; menu.Height = 600; menu.LocalStorage.SetAs("header", selectedSchematic.Name.Replace(".schematic", "") + " " + _localizationHelper.LocalizeOrDefault("Details", data.Player)); menu.Items.Add(new Label(new LabelData(_localizationHelper.LocalizeOrDefault("Height", data.Player) + ": " + schematicMetadata.MaxY, UnityEngine.Color.black))); menu.Items.Add(new Label(new LabelData(_localizationHelper.LocalizeOrDefault("Width", data.Player) + ": " + schematicMetadata.MaxZ, UnityEngine.Color.black))); menu.Items.Add(new Label(new LabelData(_localizationHelper.LocalizeOrDefault("Length", data.Player) + ": " + schematicMetadata.MaxX, UnityEngine.Color.black))); menu.LocalStorage.SetAs(Selected_Schematic, selectedSchematic.Name); List <ValueTuple <IItem, int> > headerItems = new List <ValueTuple <IItem, int> >(); headerItems.Add(ValueTuple.Create <IItem, int>(new Label(new LabelData(" ", UnityEngine.Color.black)), 200)); headerItems.Add(ValueTuple.Create <IItem, int>(new Label(new LabelData(_localizationHelper.LocalizeOrDefault("Item", data.Player), UnityEngine.Color.black)), 200)); headerItems.Add(ValueTuple.Create <IItem, int>(new Label(new LabelData(_localizationHelper.LocalizeOrDefault("Required", data.Player), UnityEngine.Color.black)), 200)); headerItems.Add(ValueTuple.Create <IItem, int>(new Label(new LabelData(_localizationHelper.LocalizeOrDefault("InStockpile", data.Player), UnityEngine.Color.black)), 200)); menu.Items.Add(new HorizontalRow(headerItems)); foreach (var kvp in schematicMetadata.Blocks) { try { if (ItemTypes.TryGetType(kvp.Key, out ItemTypes.ItemType item)) { var stockpileCount = 0; data.Player.ActiveColony.Stockpile.Items.TryGetValue(item.ItemIndex, out stockpileCount); List <ValueTuple <IItem, int> > items = new List <ValueTuple <IItem, int> >(); items.Add(ValueTuple.Create <IItem, int>(new ItemIcon(kvp.Key), 200)); items.Add(ValueTuple.Create <IItem, int>(new Label(new LabelData(item.Name, UnityEngine.Color.black, UnityEngine.TextAnchor.MiddleLeft, 18, LabelData.ELocalizationType.Type)), 200)); items.Add(ValueTuple.Create <IItem, int>(new Label(new LabelData(" x " + kvp.Value.Count, UnityEngine.Color.black)), 200)); items.Add(ValueTuple.Create <IItem, int>(new Label(new LabelData(" x " + stockpileCount, UnityEngine.Color.black)), 200)); menu.Items.Add(new HorizontalRow(items)); } else { SettlersLogger.Log(ChatColor.orange, "Unknown item for schematic: {0}", kvp.Key); } } catch (Exception ex) { SettlersLogger.LogError(ex); } } menu.Items.Add(new DropDown(new LabelData(_localizationHelper.GetLocalizationKey("Rotation"), UnityEngine.Color.black), Selected_Schematic + ".Rotation", _rotation.Select(r => r.ToString()).ToList())); menu.Items.Add(new HorizontalSplit(new ButtonCallback(GameLoader.NAMESPACE + ".ShowMainMenu", new LabelData("Back", UnityEngine.Color.black, UnityEngine.TextAnchor.MiddleCenter)), new ButtonCallback(GameLoader.NAMESPACE + ".SetBuildArea", new LabelData("Build", UnityEngine.Color.black, UnityEngine.TextAnchor.MiddleCenter)))); menu.LocalStorage.SetAs(Selected_Schematic + ".Rotation", 0); NetworkMenuManager.SendServerPopup(data.Player, menu); } } } break; case GameLoader.NAMESPACE + ".SetBuildArea": var scem = data.Storage.GetAs <string>(Selected_Schematic); var rotation = data.Storage.GetAs <int>(Selected_Schematic + ".Rotation"); SettlersLogger.Log("Schematic: {0}", scem); if (SchematicReader.TryGetSchematicMetadata(scem, data.Player.ActiveColony.ColonyID, out SchematicMetadata metadata)) { if (metadata.Blocks.Count == 1 && metadata.Blocks.ContainsKey(ColonyBuiltIn.ItemTypes.AIR.Id)) { PandaChat.Send(data.Player, _localizationHelper, "invlaidSchematic", ChatColor.red); } { _awaitingClick[data.Player] = Tuple.Create(SchematicClickType.Build, scem, _rotation[rotation]); PandaChat.Send(data.Player, _localizationHelper, "instructions"); NetworkMenuManager.CloseServerPopup(data.Player); } } break; } }
public void DoJob(IIterationType iterationType, IAreaJob areaJob, ConstructionJobInstance job, ref NPC.NPCBase.NPCState state) { if (iterationType == null) { AreaJobTracker.RemoveJob(areaJob); return; } int iMax = 4096; while (iMax-- > 0) { Vector3Int jobPosition = iterationType.CurrentPosition; if (!jobPosition.IsValid) { // failed to find next position to do job at, self-destruct state.SetIndicator(new Shared.IndicatorState(5f, BuiltinBlocks.Indices.erroridle)); AreaJobTracker.RemoveJob(areaJob); return; } ushort foundTypeIndex; if (World.TryGetTypeAt(jobPosition, out foundTypeIndex)) { iterationType.MoveNext(); if (foundTypeIndex != 0) { ItemTypes.ItemType foundType = ItemTypes.GetType(foundTypeIndex); if (!foundType.IsDestructible) { continue; // skip this block, retry } if (ServerManager.TryChangeBlock(jobPosition, foundTypeIndex, 0, areaJob.Owner, ESetBlockFlags.DefaultAudio) == EServerChangeBlockResult.Success) { float blockDestructionTime = GetCooldown(foundType.DestructionTime * 0.001f); GatherResults.Clear(); var itemList = foundType.OnRemoveItems; for (int i = 0; i < itemList.Count; i++) { GatherResults.Add(itemList[i]); } ModLoader.Callbacks.OnNPCGathered.Invoke(job, jobPosition, GatherResults); InventoryItem toShow = ItemTypes.ItemTypeDrops.GetWeightedRandom(GatherResults); if (toShow.Amount > 0) { state.SetIndicator(new Shared.IndicatorState(blockDestructionTime, toShow.Type)); } else { state.SetCooldown(blockDestructionTime); } state.Inventory.Add(GatherResults); job.StoredItemCount++; if (job.StoredItemCount >= MaxGatheredPerRun) { job.ShouldTakeItems = true; state.JobIsDone = true; } } else { state.SetIndicator(new Shared.IndicatorState(5f, BuiltinBlocks.Indices.missingerror, true, false)); } return; // either changed a block or set indicator, job done } else { continue; // found air, try next loop } // unreachable } else { state.SetIndicator(new Shared.IndicatorState(5f, BuiltinBlocks.Indices.missingerror, true, false)); return; // end loop, wait for world to load } // unreachable } // reached loop count limit Assert.IsTrue(iMax <= 0); state.SetCooldown(1.0); }
public virtual void OnNPCAtJob(BlockJobInstance blockJobInstance, ref NPCState state) { ConstructionJobInstance instance = (ConstructionJobInstance)blockJobInstance; if (BlockTypes.ContainsByReference(instance.BlockType, out int index)) { Vector3 rotate = instance.NPC.Position.Vector; switch (index) { case 1: rotate.x -= 1f; break; case 2: rotate.x += 1f; break; case 3: rotate.z -= 1f; break; case 4: rotate.z += 1f; break; } instance.NPC.LookAt(rotate); } if (instance.ConstructionArea != null && !instance.ConstructionArea.IsValid) { instance.ConstructionArea = null; } if (instance.ConstructionArea == null) { if (AreaJobTracker.ExistingAreaAt(instance.Position.Add(-1, -1, -1), instance.Position.Add(1, 1, 1), out List <IAreaJob> jobs)) { for (int i = 0; i < jobs.Count; i++) { if (jobs[i] is ConstructionArea neighbourArea) { instance.ConstructionArea = neighbourArea; break; } } AreaJobTracker.AreaJobListPool.Return(jobs); } if (instance.ConstructionArea == null) { if (instance.DidAreaPresenceTest) { state.SetCooldown(0.5); ServerManager.TryChangeBlock(instance.Position, instance.BlockType, BuiltinBlocks.Types.air, instance.Owner); } else { state.SetIndicator(new Shared.IndicatorState(Random.NextFloat(3f, 5f), BuiltinBlocks.Indices.erroridle)); instance.DidAreaPresenceTest = true; } return; } } Assert.IsNotNull(instance.ConstructionArea); instance.ConstructionArea.DoJob(instance, ref state); }
public static async void RewindColonyBlocks(Colony colony) { foreach (var npc in colony.Followers.ToList()) { npc.health = 0; if (npc.Job is IAreaJob areaJob) { AreaJobTracker.RemoveJob(areaJob); } npc.ClearJob(); npc.OnDeath(); } RoamingJobManager.Objectives.Remove(colony); ServerManager.ColonyTracker.ColoniesLock.EnterWriteLock(); ServerManager.ColonyTracker.ColoniesByID.Remove(colony.ColonyID); Colony newcolony = new Colony(colony.ColonyID); newcolony.Stockpile.AddEnumerable(from unresolved in ServerManager.WorldSettingsReadOnly.InitialStockpile select new InventoryItem(unresolved.type, unresolved.amount)); ServerManager.ColonyTracker.ColoniesByID.Add(newcolony.ColonyID, newcolony); ServerManager.ColonyTracker.ColoniesLock.ExitWriteLock(); ServerManager.ColonyTracker.Save(); await Task.Run(() => { try { var colonyName = colony.Name; using (TrackedPositionContext db = new TrackedPositionContext()) { foreach (var trackedPos in db.Positions.Where(p => p.ColonyId == colonyName)) { var oldest = db.Positions.Where(o => o.X == trackedPos.X && o.Y == trackedPos.Y && o.Z == trackedPos.Z && o.TimeTracked < trackedPos.TimeTracked).OrderBy(tp => tp.TimeTracked).FirstOrDefault(); if (oldest == default(TrackedPosition)) { oldest = trackedPos; } if (!_queuedPositions.Any(pos => pos.Equals(oldest))) { lock (_queuedPositions) _queuedPositions.Add(oldest); ChunkQueue.QueuePlayerRequest(oldest.GetVector().ToChunk(), colony.Owners.FirstOrDefault()); } } if (_queuedPositions.Count <= 0) { return; } System.Threading.Thread.Sleep(10000); List <TrackedPosition> replaced = new List <TrackedPosition>(); foreach (var trackedPos in _queuedPositions) { if (ServerManager.TryChangeBlock(trackedPos.GetVector(), (ushort)trackedPos.BlockId) == EServerChangeBlockResult.Success) { replaced.Add(trackedPos); } } lock (_queuedPositions) { db.Positions.RemoveRange(_queuedPositions); foreach (var replace in replaced) { _queuedPositions.Remove(replace); } } db.SaveChanges(); } } catch (DbEntityValidationException e) { ProcessEntityException(e); } catch (Exception ex) { PandaLogger.LogError(ex); } }); }