public static void Tick(double portalYearTicks) { // update positions through physics engine ServerPerformanceMonitor.RestartEvent(ServerPerformanceMonitor.MonitorType.LandblockManager_TickPhysics); TickPhysics(portalYearTicks); ServerPerformanceMonitor.RegisterEventEnd(ServerPerformanceMonitor.MonitorType.LandblockManager_TickPhysics); // Tick all of our Landblocks and WorldObjects ServerPerformanceMonitor.RestartEvent(ServerPerformanceMonitor.MonitorType.LandblockManager_Tick); Tick(); ServerPerformanceMonitor.RegisterEventEnd(ServerPerformanceMonitor.MonitorType.LandblockManager_Tick); // clean up inactive landblocks UnloadLandblocks(); }
public static void Tick(double portalYearTicks) { // update positions through physics engine ServerPerformanceMonitor.RestartEvent(ServerPerformanceMonitor.MonitorType.LandblockManager_TickPhysics); TickPhysics(portalYearTicks); ServerPerformanceMonitor.RegisterEventEnd(ServerPerformanceMonitor.MonitorType.LandblockManager_TickPhysics); // Tick all of our Landblocks and WorldObjects (Work that can be multi-threaded) ServerPerformanceMonitor.RestartEvent(ServerPerformanceMonitor.MonitorType.LandblockManager_TickMultiThreadedWork); TickMultiThreadedWork(); ServerPerformanceMonitor.RegisterEventEnd(ServerPerformanceMonitor.MonitorType.LandblockManager_TickMultiThreadedWork); // Tick all of our Landblocks and WorldObjects (Work that must be single threaded) ServerPerformanceMonitor.RestartEvent(ServerPerformanceMonitor.MonitorType.LandblockManager_TickSingleThreadedWork); TickSingleThreadedWork(); ServerPerformanceMonitor.RegisterEventEnd(ServerPerformanceMonitor.MonitorType.LandblockManager_TickSingleThreadedWork); // clean up inactive landblocks UnloadLandblocks(); }
/// <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(); ServerPerformanceMonitor.RestartCumulativeEvents(); ServerPerformanceMonitor.RestartEvent(ServerPerformanceMonitor.MonitorType.UpdateGameWorld_Entire); LandblockManager.Tick(Timers.PortalYearTicks); HouseManager.Tick(); ServerPerformanceMonitor.RegisterEventEnd(ServerPerformanceMonitor.MonitorType.UpdateGameWorld_Entire); ServerPerformanceMonitor.RegisterCumulativeEvents(); return(true); }
/// <summary> /// Manages updating all entities on the world. /// - Server-side command-line commands are handled in their own thread. /// - Database I/O is handled in its own thread. /// - Network commands come from their own listener threads, and are queued for each sessions which are then processed here. /// - This thread does the rest of the work! /// </summary> private static void UpdateWorld() { log.DebugFormat("Starting UpdateWorld thread"); WorldActive = true; var worldTickTimer = new Stopwatch(); while (!pendingWorldStop) { /* * When it comes to thread safety for Landblocks and WorldObjects, ACE makes the following assumptions: * * Inbound ClientMessages and GameActions are handled on the main UpdateWorld thread. * - These actions may load Landblocks and modify other WorldObjects safely. * * PlayerEnterWorld queue is run on the main UpdateWorld thread. * - These actions may load Landblocks and modify other WorldObjects safely. * * Landblock Groups (calculated by LandblockManager) can be processed in parallel. * * Adjacent Landblocks will always be run on the same thread. * * Non-adjacent landblocks might be run on different threads. * - If two non-adjacent landblocks both touch the same landblock, and that landblock is active, they will be run on the same thread. * * Database results are returned from a task spawned in SerializedShardDatabase (via callback). * - Minimal processing should be done from the callback. Return as quickly as possible to let the database thread do database work. * - The processing of these results should be queued to an ActionQueue * * The only cases where it's acceptable for to create a new Task, Thread or Parallel loop are the following: * - Every scenario must be one where you don't care about breaking ACE * - DeveloperCommand Handlers */ worldTickTimer.Restart(); ServerPerformanceMonitor.RestartEvent(ServerPerformanceMonitor.MonitorType.PlayerManager_Tick); PlayerManager.Tick(); ServerPerformanceMonitor.RegisterEventEnd(ServerPerformanceMonitor.MonitorType.PlayerManager_Tick); ServerPerformanceMonitor.RestartEvent(ServerPerformanceMonitor.MonitorType.NetworkManager_InboundClientMessageQueueRun); NetworkManager.InboundMessageQueue.RunActions(); ServerPerformanceMonitor.RegisterEventEnd(ServerPerformanceMonitor.MonitorType.NetworkManager_InboundClientMessageQueueRun); // This will consist of PlayerEnterWorld actions, as well as other game world actions that require thread safety ServerPerformanceMonitor.RestartEvent(ServerPerformanceMonitor.MonitorType.actionQueue_RunActions); ActionQueue.RunActions(); ServerPerformanceMonitor.RegisterEventEnd(ServerPerformanceMonitor.MonitorType.actionQueue_RunActions); ServerPerformanceMonitor.RestartEvent(ServerPerformanceMonitor.MonitorType.DelayManager_RunActions); DelayManager.RunActions(); ServerPerformanceMonitor.RegisterEventEnd(ServerPerformanceMonitor.MonitorType.DelayManager_RunActions); ServerPerformanceMonitor.RestartEvent(ServerPerformanceMonitor.MonitorType.UpdateGameWorld); var gameWorldUpdated = UpdateGameWorld(); ServerPerformanceMonitor.RegisterEventEnd(ServerPerformanceMonitor.MonitorType.UpdateGameWorld); ServerPerformanceMonitor.RestartEvent(ServerPerformanceMonitor.MonitorType.NetworkManager_DoSessionWork); int sessionCount = NetworkManager.DoSessionWork(); ServerPerformanceMonitor.RegisterEventEnd(ServerPerformanceMonitor.MonitorType.NetworkManager_DoSessionWork); ServerPerformanceMonitor.Tick(); // We only relax the CPU if our game world is able to update at the target rate. // We do not sleep if our game world just updated. This is to prevent the scenario where our game world can't keep up. We don't want to add further delays. // If our game world is able to keep up, it will not be updated on most ticks. It's on those ticks (between updates) that we will relax the CPU. if (!gameWorldUpdated) { Thread.Sleep(sessionCount == 0 ? 10 : 1); // Relax the CPU more if no sessions are connected } Timers.PortalYearTicks += worldTickTimer.Elapsed.TotalSeconds; } // World has finished operations and concedes the thread to garbage collection WorldActive = false; }