/// <summary> /// Projected to run at a reasonable rate for gameplay (30-60fps) /// </summary> public static bool UpdateGameWorld() { if (updateGameWorldRateLimiter.GetSecondsToWaitBeforeNextEvent() > 0) { return(false); } updateGameWorldRateLimiter.RegisterEvent(); UpdateGameWorld5MinRM.RegisterEventStart(); UpdateGameWorld60MinRM.RegisterEventStart(); // update positions through physics engine var movedObjects = HandlePhysics(Timers.PortalYearTicks); // iterate through objects that have changed landblocks foreach (var movedObject in movedObjects) { // NOTE: The object's Location can now be null, if a player logs out, or an item is picked up if (movedObject.Location == null) { continue; } // assume adjacency move here? LandblockManager.RelocateObjectForPhysics(movedObject, true); } // Tick all of our Landblocks and WorldObjects var activeLandblocks = LandblockManager.GetActiveLandblocks(); foreach (var landblock in activeLandblocks) { landblock.Tick(Time.GetUnixTime()); } // clean up inactive landblocks LandblockManager.UnloadLandblocks(); UpdateGameWorld5MinRM.RegisterEventEnd(); UpdateGameWorld60MinRM.RegisterEventEnd(); if (UpdateGameWorld5MinRM.TotalSeconds > 300) { UpdateGameWorld5MinRM.ClearEventHistory(); UpdateGameWorld5MinLastReset = DateTime.UtcNow; } if (UpdateGameWorld60MinRM.TotalSeconds > 3600) { UpdateGameWorld60MinRM.ClearEventHistory(); UpdateGameWorld60MinLastReset = DateTime.UtcNow; } HouseManager.Tick(); return(true); }
public void TickPhysics(double portalYearTicks, ConcurrentBag <WorldObject> movedObjects) { Monitor5m.RegisterEventStart(); Monitor1h.RegisterEventStart(); monitorsRequireEventStart = false; foreach (WorldObject wo in GetWorldObjectsForPhysicsHandling()) { // set to TRUE if object changes landblock var landblockUpdate = false; // detect player movement // TODO: handle players the same as everything else if (wo is Player player) { wo.InUpdate = true; var newPosition = HandlePlayerPhysics(player); // update position through physics engine if (newPosition != null) { landblockUpdate = wo.UpdatePlayerPhysics(newPosition); } wo.InUpdate = false; } else { landblockUpdate = wo.UpdateObjectPhysics(); } if (landblockUpdate) { movedObjects.Add(wo); } } Monitor5m.PauseEvent(); Monitor1h.PauseEvent(); }
public void Tick(double currentUnixTime) { Monitor1h.RegisterEventStart(); ServerPerformanceMonitor.ResumeEvent(ServerPerformanceMonitor.MonitorType.Landblock_Tick_RunActions); actionQueue.RunActions(); ServerPerformanceMonitor.PauseEvent(ServerPerformanceMonitor.MonitorType.Landblock_Tick_RunActions); ProcessPendingWorldObjectAdditionsAndRemovals(); ServerPerformanceMonitor.ResumeEvent(ServerPerformanceMonitor.MonitorType.Landblock_Tick_Player_Tick); foreach (var player in players) { player.Player_Tick(currentUnixTime); } ServerPerformanceMonitor.PauseEvent(ServerPerformanceMonitor.MonitorType.Landblock_Tick_Player_Tick); // When a WorldObject Ticks, it can end up adding additional WorldObjects to this landblock if (!IsDormant) { ServerPerformanceMonitor.ResumeEvent(ServerPerformanceMonitor.MonitorType.Landblock_Tick_Monster_Tick); while (sortedCreaturesByNextTick.Count > 0) // Monster_Tick() { var first = sortedCreaturesByNextTick.First.Value; // If they wanted to run before or at now if (first.NextMonsterTickTime <= currentUnixTime) { sortedCreaturesByNextTick.RemoveFirst(); first.Monster_Tick(currentUnixTime); sortedCreaturesByNextTick.AddLast(first); // All creatures tick at a fixed interval } else { break; } } ServerPerformanceMonitor.PauseEvent(ServerPerformanceMonitor.MonitorType.Landblock_Tick_Monster_Tick); } ServerPerformanceMonitor.ResumeEvent(ServerPerformanceMonitor.MonitorType.Landblock_Tick_WorldObject_Heartbeat); while (sortedWorldObjectsByNextHeartbeat.Count > 0) // Heartbeat() { var first = sortedWorldObjectsByNextHeartbeat.First.Value; // If they wanted to run before or at now if (first.NextHeartbeatTime <= currentUnixTime) { sortedWorldObjectsByNextHeartbeat.RemoveFirst(); first.Heartbeat(currentUnixTime); InsertWorldObjectIntoSortedHeartbeatList(first); // WorldObjects can have heartbeats at different intervals } else { break; } } ServerPerformanceMonitor.PauseEvent(ServerPerformanceMonitor.MonitorType.Landblock_Tick_WorldObject_Heartbeat); ServerPerformanceMonitor.ResumeEvent(ServerPerformanceMonitor.MonitorType.Landblock_Tick_GeneratorUpdate); while (sortedGeneratorsByNextGeneratorUpdate.Count > 0) { var first = sortedGeneratorsByNextGeneratorUpdate.First.Value; // If they wanted to run before or at now if (first.NextGeneratorUpdateTime <= currentUnixTime) { sortedGeneratorsByNextGeneratorUpdate.RemoveFirst(); first.GeneratorUpdate(currentUnixTime); //InsertWorldObjectIntoSortedGeneratorUpdateList(first); sortedGeneratorsByNextGeneratorUpdate.AddLast(first); } else { break; } } ServerPerformanceMonitor.PauseEvent(ServerPerformanceMonitor.MonitorType.Landblock_Tick_GeneratorUpdate); ServerPerformanceMonitor.ResumeEvent(ServerPerformanceMonitor.MonitorType.Landblock_Tick_GeneratorRegeneration); while (sortedGeneratorsByNextRegeneration.Count > 0) // GeneratorRegeneration() { var first = sortedGeneratorsByNextRegeneration.First.Value; //Console.WriteLine($"{first.Name}.Landblock_Tick_GeneratorRegeneration({currentUnixTime})"); // If they wanted to run before or at now if (first.NextGeneratorRegenerationTime <= currentUnixTime) { sortedGeneratorsByNextRegeneration.RemoveFirst(); first.GeneratorRegeneration(currentUnixTime); InsertWorldObjectIntoSortedGeneratorRegenerationList(first); // Generators can have regnerations at different intervals } else { break; } } ServerPerformanceMonitor.PauseEvent(ServerPerformanceMonitor.MonitorType.Landblock_Tick_GeneratorRegeneration); // Heartbeat ServerPerformanceMonitor.ResumeEvent(ServerPerformanceMonitor.MonitorType.Landblock_Tick_Heartbeat); if (lastHeartBeat + heartbeatInterval <= DateTime.UtcNow) { var thisHeartBeat = DateTime.UtcNow; ProcessPendingWorldObjectAdditionsAndRemovals(); // Decay world objects if (lastHeartBeat != DateTime.MinValue) { foreach (var wo in worldObjects.Values) { if (wo.IsDecayable()) { wo.Decay(thisHeartBeat - lastHeartBeat); } } } if (!Permaload) { if (lastActiveTime + dormantInterval < thisHeartBeat) { IsDormant = true; } if (lastActiveTime + unloadInterval < thisHeartBeat) { LandblockManager.AddToDestructionQueue(this); } } //log.Info($"Landblock {Id.ToString()}.Tick({currentUnixTime}).Landblock_Tick_Heartbeat: thisHeartBeat: {thisHeartBeat.ToString()} | lastHeartBeat: {lastHeartBeat.ToString()} | worldObjects.Count: {worldObjects.Count()}"); lastHeartBeat = thisHeartBeat; } ServerPerformanceMonitor.PauseEvent(ServerPerformanceMonitor.MonitorType.Landblock_Tick_Heartbeat); // Database Save ServerPerformanceMonitor.ResumeEvent(ServerPerformanceMonitor.MonitorType.Landblock_Tick_Database_Save); if (lastDatabaseSave + databaseSaveInterval <= DateTime.UtcNow) { ProcessPendingWorldObjectAdditionsAndRemovals(); SaveDB(); lastDatabaseSave = DateTime.UtcNow; } ServerPerformanceMonitor.PauseEvent(ServerPerformanceMonitor.MonitorType.Landblock_Tick_Database_Save); Monitor1h.RegisterEventEnd(); if (DateTime.UtcNow - last1hClear >= last1hClearInteval) { Monitor1h.ClearEventHistory(); last1hClear = DateTime.UtcNow; } }