// Applies pending updates and sends them to players (if applicable). internal void ProcessUpdates() { if (World == null) { throw new InvalidOperationException("Map must be assigned to a world to process updates."); } if (World.IsLocked) { if (World.IsPendingMapUnload) { World.UnloadMap(true); } return; } int packetsSent = 0; bool canFlush = false; int maxPacketsPerUpdate = Server.CalculateMaxPacketsPerUpdate(World); while (packetsSent < maxPacketsPerUpdate) { BlockUpdate update; if (!updates.TryDequeue(out update)) { if (World.IsFlushing) { canFlush = true; } break; } if (!InBounds(update.X, update.Y, update.Z)) { continue; } int blockIndex = Index(update.X, update.Y, update.Z); Blocks[blockIndex] = (byte)update.BlockType; if (!World.IsFlushing) { //non classicube players get fallbacks instead of the real blocks Packet packet = PacketWriter.MakeSetBlock(update.X, update.Y, update.Z, update.BlockType); Packet fallback = PacketWriter.MakeSetBlock(update.X, update.Y, update.Z, Map.GetFallbackBlock(update.BlockType)); // Not using World.Players.Where(x => usesCpe) here to avoid memory allocations Player[] players = World.Players; for (int i = 0; i < players.Length; i++) { Player p = players[i]; if (p.UsesCustomBlocks) { p.SendLowPriority(packet); } else { p.SendLowPriority(fallback); } } } packetsSent++; } if (drawOps.Count > 0) { lock ( drawOpLock ) { if (drawOps.Count > 0) { packetsSent += ProcessDrawOps(maxPacketsPerUpdate - packetsSent); } } } else if (canFlush) { World.EndFlushMapBuffer(); } if (packetsSent == 0 && World.IsPendingMapUnload) { World.UnloadMap(true); } }