/// <summary> /// main game loop /// </summary> public void UseTime() { while (running) { // here we'd move server objects in motion (subject to landscape) and do physics collision detection List <WorldObject> allworldobj = null; List <Player> allplayers = null; List <Creature> allcreatures = null; List <WorldObject> movedObjects = null; List <WorldObject> despawnObjects = null; List <Creature> deadCreatures = null; lock (objectCacheLocker) { allworldobj = worldObjects.Values.ToList(); } // all players on this land block allplayers = allworldobj.OfType <Player>().ToList(); allcreatures = allworldobj.OfType <Creature>().ToList(); despawnObjects = allworldobj.ToList(); despawnObjects = despawnObjects.Where(x => x.DespawnTime > -1).ToList(); deadCreatures = allworldobj.OfType <Creature>().ToList(); deadCreatures = deadCreatures.Where(x => x.IsAlive == false).ToList(); // flag them as updated now in order to reduce chance of missing an update // this is only for moving objects across landblocks. movedObjects = allworldobj.ToList(); movedObjects = movedObjects.Where(p => p.LastUpdatedTicks >= p.LastMovementBroadcastTicks).ToList(); movedObjects.ForEach(m => m.LastMovementBroadcastTicks = WorldManager.PortalYearTicks); if (id.MapScope == Enum.MapScope.Outdoors) { // check to see if a player or other mutable object "roamed" to an adjacent landblock var objectsToRelocate = movedObjects.Where(m => m.Location.LandblockId.IsAdjacentTo(id) && m.Location.LandblockId != id).ToList(); // so, these objects moved to an adjacent block. they could have recalled to that block, died and bounced to a lifestone on that block, or // just simply walked accross the border line. in any case, we won't delete them, we'll just transfer them. the trick, though, is to // figure out how to treat it in adjacent landblocks. if the player walks across the southern border, the north adjacency needs to remove // them, but the south is actually getting them. we need to avoid sending Delete+Create to clients that already know about it, though. objectsToRelocate.ForEach(o => Log($"attempting to relocate object {o.Name} ({o.Guid.Full.ToString("X")})")); // RelocateObject will put them in the right landblock objectsToRelocate.ForEach(o => LandblockManager.RelocateObject(o)); // Remove has logic to make sure it doesn't double up the delete+create when "true" is passed. objectsToRelocate.ForEach(o => RemoveWorldObject(o.Guid, true)); } // for all players on landblock. Parallel.ForEach(allplayers, player => { // Process Action Queue for player. QueuedGameAction action = player.ActionQueuePop(); if (action != null) { HandleGameAction(action, player); } // Process Examination Queue for player QueuedGameAction examination = player.ExaminationQueuePop(); if (examination != null) { HandleGameAction(examination, player); } }); UpdateStatus(allplayers.Count); double tickTime = WorldManager.PortalYearTicks; // per-creature update on landblock. Parallel.ForEach(allworldobj, wo => { // Process the creatures wo.Tick(tickTime); }); // broadcast moving objects to the world.. // players and creatures can move. Parallel.ForEach(movedObjects, mo => { // detect all world objects in ghost range List <WorldObject> woproxghost = new List <WorldObject>(); woproxghost.AddRange(GetWorldObjectsInRange(mo, maxobjectGhostRange, true)); // for all objects in rang of this moving object or in ghost range of moving object update them. Parallel.ForEach(woproxghost, wo => { if (mo.Guid.IsPlayer()) { // if world object is in active zone then. if (wo.Location.SquaredDistanceTo(mo.Location) <= maxobjectRange) { // if world object is in active zone. if (!(mo as Player).GetTrackedObjectGuids().Contains(wo.Guid)) { (mo as Player).TrackObject(wo); } } // if world object is in ghost zone and outside of active zone else if ((mo as Player).GetTrackedObjectGuids().Contains(wo.Guid)) { (mo as Player).StopTrackingObject(wo, true); } } }); if (mo.Location.LandblockId == id) { // update if it's still here Broadcast(BroadcastEventArgs.CreateAction(BroadcastAction.AddOrUpdate, mo), true, Quadrant.All); } else { // remove and readd if it's not RemoveWorldObject(mo.Guid, false); LandblockManager.AddObject(mo); } }); // despawn objects despawnObjects.ForEach(deo => { if (deo.DespawnTime < WorldManager.PortalYearTicks) { RemoveWorldObject(deo.Guid, false); } }); // respawn creatures deadCreatures.ForEach(dc => { if (dc.RespawnTime < WorldManager.PortalYearTicks) { dc.IsAlive = true; // HandleParticleEffectEvent(dc, PlayScript.Create); AddWorldObject(dc); } }); Thread.Sleep(1); } // TODO: release resources }
/// <summary> /// main game loop /// </summary> public void UseTime() { while (running) { // here we'd move server objects in motion (subject to landscape) and do physics collision detection // for now, we'll move players around List <WorldObject> movedObjects = null; List <Player> players = null; lock (objectCacheLocker) { movedObjects = this.worldObjects.Values.OfType <WorldObject>().ToList(); players = this.worldObjects.Values.OfType <Player>().ToList(); } movedObjects = movedObjects.Where(p => p.LastUpdatedTicks >= p.LastMovementBroadcastTicks).ToList(); // flag them as updated now in order to reduce chance of missing an update movedObjects.ForEach(m => m.LastMovementBroadcastTicks = WorldManager.PortalYearTicks); if (this.id.MapScope == Enum.MapScope.Outdoors) { // check to see if a player or other mutable object "roamed" to an adjacent landblock var objectsToRelocate = movedObjects.Where(m => m.Location.LandblockId.IsAdjacentTo(this.id) && m.Location.LandblockId != this.id).ToList(); // so, these objects moved to an adjacent block. they could have recalled to that block, died and bounced to a lifestone on that block, or // just simply walked accross the border line. in any case, we won't delete them, we'll just transfer them. the trick, though, is to // figure out how to treat it in adjacent landblocks. if the player walks across the southern border, the north adjacency needs to remove // them, but the south is actually getting them. we need to avoid sending Delete+Create to clients that already know about it, though. objectsToRelocate.ForEach(o => Log($"attempting to relocate object {o.Name} ({o.Guid.Full.ToString("X")})")); // RelocateObject will put them in the right landblock objectsToRelocate.ForEach(o => LandblockManager.RelocateObject(o)); // Remove has logic to make sure it doesn't double up the delete+create when "true" is passed. objectsToRelocate.ForEach(o => RemoveWorldObject(o.Guid, true)); } // broadcast Parallel.ForEach(movedObjects, mo => { if (mo.Location.LandblockId == this.id) { // update if it's still here Broadcast(BroadcastEventArgs.CreateAction(BroadcastAction.AddOrUpdate, mo), true, Quadrant.All); } else { // remove and readd if it's not this.RemoveWorldObject(mo.Guid, false); LandblockManager.AddObject(mo); } }); // TODO: figure out if this landblock can be unloaded // process player action queues foreach (Player p in players) { QueuedGameAction action = p.ActionQueuePop(); if (action != null) { HandleGameAction(action, p); } } Thread.Sleep(1); } // TODO: release resources }