private void OnTick() { var now = DateTime.Now; if (nextStatsTime < now) { nextStatsTime = now.AddMilliseconds(statsInterval); lastStats = currentStats; currentStats = new Stats(); } // Never use more than half the available tick time // but always process at least one queued block. var maxTime = (1000 / ConVar.Server.tickrate) / 2; var n = 0; while (stabilityQueue.Count > 0 && (n == 0 || (DateTime.Now - now).TotalMilliseconds < maxTime)) { var block = stabilityQueue[0]; stabilityQueue.RemoveAt(0); if (!BuildingBlockHelpers.IsValidBlock(block)) { continue; } UpdateStability(block); ++n; } // Always delay queued updates until the next tick. // This also gives us a nice bottom up effect. while (stabilityQueueDelayed.Count > 0) { stabilityQueue.Add(stabilityQueueDelayed[0]); stabilityQueueDelayed.RemoveAt(0); } }
private void OnEntityBuilt(Planner planner, GameObject obj) { if (obj == null) { return; } var block = obj.GetComponent <BuildingBlock>(); if (!BuildingBlockHelpers.IsValidBlock(block)) { return; } #if DEBUG Log("Placing block " + block.blockDefinition.hierachyName); #endif ++currentStats.blocksBuilt; try { var defaultGrade = block.blockDefinition.defaultGrade; if (!UpdateStability(block, false)) { ++currentStats.blocksFailedBuilding; // If this isn't stable, refund. var player = planner.ownerPlayer; foreach (var cost in defaultGrade.costToBuild) { var item = ItemManager.CreateByItemID(cost.itemid, (int)cost.amount, false); player.GiveItem(item, BaseEntity.GiveItemReason.Generic); } player.ChatMessage(_(buildingFailedMessages[rng.Next(0, buildingFailedMessages.Length)])); return; } } catch (Exception ex) { Error("OnEntityBuilt failed", ex); } }
private void OnBuildingBlockDemolish(BuildingBlock block, BasePlayer player) { if (!BuildingBlockHelpers.IsValidBlock(block)) { return; } OnDemolish(block); }
private void OnEntityDeath(BaseCombatEntity entity, HitInfo info) { var block = entity as BuildingBlock; if (!BuildingBlockHelpers.IsValidBlock(block)) { return; } OnDemolish(block); }
// Enqueues a stability update for the next tick private void EnqueueUpdate(BuildingBlock block) { ++currentStats.blocksEnqueued; if (!stabilityQueueDelayed.Contains(block)) { ++currentStats.blocksEnqueuedUnique; #if DEBUG Log("Enqueued " + BuildingBlockHelpers.Name(block)); #endif stabilityQueueDelayed.Add(block); } }
// Updates the stability of a block and returns false if the block has just been destroyed private bool UpdateStability(BuildingBlock block, bool propagate = true) { ++currentStats.blocksUpdated; if (block.isDestroyed) { #if DEBUG Log("Skipped " + BuildingBlockHelpers.Name(block) + ": Already destroyed"); #endif return(true); } // Log("Updating stability on " + block.Name()); // Exclude foundations from stability updates. if (BuildingBlockHelpers.IsFoundation(block)) { #if DEBUG Log("Skipped " + BuildingBlockHelpers.Name(block) + ": Is foundation"); #endif return(true); } List <BuildingBlock> supports; List <BuildingBlock> supported; BuildingBlockHelpers.GetAdjacentBlocks(block, out supports, out supported); if (supports.Count > 0) { #if DEBUG Log("Skipped " + BuildingBlockHelpers.Name(block) + ": Still has " + supports.Count + " supports"); #endif return(true); } // If this block has no more supports, destroy it. #if DEBUG Log(BuildingBlockHelpers.Name(block) + " has no (more) supports, killing (supported " + supported.Count + ")" + (propagate ? " - propagating" : " - not propagating")); #endif DemolishBlock(block); var deployables = BuildingBlockHelpers.GetOrphanedDeployables(block); foreach (var deployable in deployables) { if (!deployable.isDestroyed) { DemolishDeployable(deployable); } } if (propagate) { foreach (var supportedBlock in supported) { EnqueueUpdate(supportedBlock); } } return(false); }
void cmdConsoleUpdateAll(ConsoleSystem.Arg arg) { if (arg.connection != null && arg.connection.authLevel < 2) { return; } var allBlocks = UnityEngine.Object.FindObjectsOfType <BuildingBlock>(); foreach (var block in allBlocks) { if (!BuildingBlockHelpers.IsValidBlock(block)) { continue; } UpdateStability(block, true); } SendReply(arg, "Updating stability on ALL " + allBlocks.Length + " blocks in the background now, this will take a while."); }
private void OnServerInitialized() { LoadConfig(); var customMessages = (Dictionary <string, object>)Config["messages"]; if (customMessages != null) { foreach (var pair in customMessages) { messages[pair.Key] = Convert.ToString(pair.Value); } Log("Loaded " + customMessages.Count + " translation strings"); } // Initialize helpers BuildingBlockHelpers.Initialize(); // Force an update on all blocks when first started var fs = Interface.GetMod().DataFileSystem; var data = fs.GetDatafile("BetterStability"); bool firstStart = false; if (data["firststart"] == null) { Log("Starting the first time, forcing update on ALL blocks"); firstStart = true; data["firststart"] = false; fs.SaveDatafile("BetterStability"); } // Schedule stability updates for all blocks that support anything var allBlocks = UnityEngine.Object.FindObjectsOfType <BuildingBlock>(); int n = 0; foreach (var block in allBlocks) { if (firstStart || (!BuildingBlockHelpers.IsFoundation(block) && BuildingBlockHelpers.IsSupportForAnything(block))) { EnqueueUpdate(block); ++n; } } Log("Queued " + n + " blocks for stability updates"); }
// Updates supported blocks once a block has been demolished private void OnDemolish(BuildingBlock block) { ++currentStats.blocksDemolished; List <BuildingBlock> supports; List <BuildingBlock> supported; BuildingBlockHelpers.GetAdjacentBlocks(block, out supports, out supported); #if DEBUG Log("OnDemolish called for " + BuildingBlockHelpers.Name(block) + " (support for " + supported.Count + " blocks)"); #endif foreach (var supportedBlock in supported) { EnqueueUpdate(supportedBlock); // Must be queued as this block is still alive } var deployables = BuildingBlockHelpers.GetOrphanedDeployables(block); foreach (var entity in deployables) { DemolishDeployable(entity); } }