From 706b3f2116fd9cb491809b0f02d1b12690818f15 Mon Sep 17 00:00:00 2001 From: Sotr Date: Wed, 27 Mar 2019 19:16:07 +0800 Subject: [PATCH] Send mass packets async --- .../destroystokyo/paper/PaperWorldMap.java | 5 ++-- .../server/core/AkarinAsyncScheduler.java | 24 +++++++++++++++++++ .../java/net/minecraft/server/Entity.java | 2 ++ .../net/minecraft/server/MinecraftServer.java | 14 ++++++++--- .../java/net/minecraft/server/PlayerList.java | 18 +++++++++----- src/main/java/net/minecraft/server/World.java | 2 +- .../net/minecraft/server/WorldManager.java | 10 +++++--- 7 files changed, 60 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldMap.java b/src/main/java/com/destroystokyo/paper/PaperWorldMap.java index af9e4455c..449f620a3 100644 --- a/src/main/java/com/destroystokyo/paper/PaperWorldMap.java +++ b/src/main/java/com/destroystokyo/paper/PaperWorldMap.java @@ -12,10 +12,11 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; public class PaperWorldMap extends HashMap { - private final List worlds = new ArrayList<>(); - private final List worldsIterable = new ArrayList() { + private final List worlds = new CopyOnWriteArrayList<>(); // Akarin + private final List worldsIterable = new CopyOnWriteArrayList() { // Akarin @Override public Iterator iterator() { Iterator iterator = super.iterator(); diff --git a/src/main/java/io/akarin/server/core/AkarinAsyncScheduler.java b/src/main/java/io/akarin/server/core/AkarinAsyncScheduler.java index a4cb8752f..e8f5756a8 100644 --- a/src/main/java/io/akarin/server/core/AkarinAsyncScheduler.java +++ b/src/main/java/io/akarin/server/core/AkarinAsyncScheduler.java @@ -5,8 +5,12 @@ import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import net.minecraft.server.EntityHuman; +import net.minecraft.server.EntityPlayer; import net.minecraft.server.MinecraftServer; import net.minecraft.server.NetworkManager; +import net.minecraft.server.PacketPlayOutUpdateTime; +import net.minecraft.server.WorldServer; public class AkarinAsyncScheduler extends Thread { private final static Logger LOGGER = LogManager.getLogger("Akarin"); @@ -43,6 +47,26 @@ public class AkarinAsyncScheduler extends Thread { } } + // Send time updates to everyone, it will get the right time from the world the player is in. + // Paper start - optimize time updates + for (final WorldServer world : server.getWorlds()) { + final boolean doDaylight = world.getGameRules().getBoolean("doDaylightCycle"); + final long dayTime = world.getDayTime(); + long worldTime = world.getTime(); + final PacketPlayOutUpdateTime worldPacket = new PacketPlayOutUpdateTime(worldTime, dayTime, doDaylight); + for (EntityHuman entityhuman : world.players) { + if (!(entityhuman instanceof EntityPlayer) || (server.currentTick() + entityhuman.getId()) % 20 != 0) { + continue; + } + EntityPlayer entityplayer = (EntityPlayer) entityhuman; + long playerTime = entityplayer.getPlayerTime(); + PacketPlayOutUpdateTime packet = (playerTime == dayTime) ? worldPacket : + new PacketPlayOutUpdateTime(worldTime, playerTime, doDaylight); + entityplayer.playerConnection.sendPacket(packet); // Add support for per player time + } + } + // Paper end + try { long sleepFixed = STD_TICK_TIME - (System.currentTimeMillis() - currentLoop); Thread.sleep(sleepFixed); diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java index fbe4cf0d7..97f5f26ff 100644 --- a/src/main/java/net/minecraft/server/Entity.java +++ b/src/main/java/net/minecraft/server/Entity.java @@ -30,6 +30,8 @@ import org.bukkit.entity.Player; import org.bukkit.entity.Vehicle; import co.aikar.timings.MinecraftTimings; // Paper import co.aikar.timings.Timing; // Paper +import io.akarin.server.core.AkarinAsyncExecutor; + import org.bukkit.event.entity.EntityCombustByEntityEvent; import org.bukkit.event.hanging.HangingBreakByEntityEvent; import org.bukkit.event.vehicle.VehicleBlockCollisionEvent; diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index 528e4b371..bcd145494 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -89,7 +89,7 @@ public abstract class MinecraftServer implements IAsyncTaskHandler, IMojangStati private boolean isRunning = true; private boolean isRestarting = false; // Paper - flag to signify we're attempting to restart private boolean isStopped; - private int ticks; + private int ticks; public int currentTick() { return this.ticks; } // Akarin - OBFHELPER protected final Proxy c; private IChatBaseComponent w; private int x; @@ -1035,7 +1035,9 @@ public abstract class MinecraftServer implements IAsyncTaskHandler, IMojangStati org.bukkit.craftbukkit.chunkio.ChunkIOExecutor.tick(); MinecraftTimings.chunkIOTickTimer.stopTimingUnsafe(); // Spigot // Akarin - MinecraftTimings.timeUpdateTimer.startTimingUnsafe(); // Spigot // Akarin + // Akarin start + /* + MinecraftTimings.timeUpdateTimer.startTimingUnsafe(); // Spigot // Send time updates to everyone, it will get the right time from the world the player is in. // Paper start - optimize time updates for (final WorldServer world : this.getWorlds()) { @@ -1055,7 +1057,9 @@ public abstract class MinecraftServer implements IAsyncTaskHandler, IMojangStati } } // Paper end - MinecraftTimings.timeUpdateTimer.stopTimingUnsafe(); // Spigot // Akarin + MinecraftTimings.timeUpdateTimer.stopTimingUnsafe(); // Spigot + */ + // Akarin end // WorldServer worldserver; // CraftBukkit - dropped down long i; @@ -1068,9 +1072,13 @@ public abstract class MinecraftServer implements IAsyncTaskHandler, IMojangStati TileEntityHopper.skipHopperEvents = worldserver.paperConfig.disableHopperMoveEvents || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper i = SystemUtils.getMonotonicNanos(); if (true || worldserver.worldProvider.getDimensionManager() == DimensionManager.OVERWORLD || this.getAllowNether()) { // CraftBukkit + // Akarin start + /* this.methodProfiler.a(() -> { return "dim-" + worldserver.worldProvider.getDimensionManager().getDimensionID(); }); + */ + // Akarin end /* Drop global time updates if (this.ticks % 20 == 0) { //this.methodProfiler.enter(* // Akarin - remove caller diff --git a/src/main/java/net/minecraft/server/PlayerList.java b/src/main/java/net/minecraft/server/PlayerList.java index 6c44064b7..2ae6d2fe3 100644 --- a/src/main/java/net/minecraft/server/PlayerList.java +++ b/src/main/java/net/minecraft/server/PlayerList.java @@ -5,6 +5,8 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.mojang.authlib.GameProfile; + +import io.akarin.server.core.AkarinAsyncExecutor; import io.netty.buffer.Unpooled; import java.io.File; import java.net.SocketAddress; @@ -1057,14 +1059,15 @@ public abstract class PlayerList { } public void sendAll(Packet packet) { - for (int i = 0; i < this.players.size(); ++i) { - ((EntityPlayer) this.players.get(i)).playerConnection.sendPacket(packet); + for (EntityHuman player : this.players) { // Akarin - iterate safety + ((EntityPlayer) player).playerConnection.sendPacket(packet); // Akarin } } // CraftBukkit start - add a world/entity limited version public void sendAll(Packet packet, EntityHuman entityhuman) { + AkarinAsyncExecutor.scheduleAsyncTask(() -> { // Akarin for (int i = 0; i < this.players.size(); ++i) { EntityPlayer entityplayer = this.players.get(i); if (entityhuman != null && entityhuman instanceof EntityPlayer && !entityplayer.getBukkitEntity().canSee(((EntityPlayer) entityhuman).getBukkitEntity())) { @@ -1072,12 +1075,15 @@ public abstract class PlayerList { } ((EntityPlayer) this.players.get(i)).playerConnection.sendPacket(packet); } + }); // Akarin } public void sendAll(Packet packet, World world) { - for (int i = 0; i < world.players.size(); ++i) { - ((EntityPlayer) world.players.get(i)).playerConnection.sendPacket(packet); + AkarinAsyncExecutor.scheduleAsyncTask(() -> { // Akarin + for (EntityHuman player : world.players) { // Akarin - iterate safety + ((EntityPlayer) player).playerConnection.sendPacket(packet); // Akarin } + }); // Akarin } // CraftBukkit end @@ -1230,8 +1236,8 @@ public abstract class PlayerList { } List players1 = world == null ? players : world.players; - for (int j = 0; j < players1.size(); ++j) { - EntityHuman entity = players1.get(j); + for (EntityHuman entity : players1) { // Akarin - iterate safety + //EntityHuman entity = players1.get(j); // Akarin if (!(entity instanceof EntityPlayer)) continue; EntityPlayer entityplayer = (EntityPlayer) entity; // Paper end diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java index 46662ab08..59a77409a 100644 --- a/src/main/java/net/minecraft/server/World.java +++ b/src/main/java/net/minecraft/server/World.java @@ -85,7 +85,7 @@ public abstract class World implements IEntityAccess, GeneratorAccess, IIBlockAc public final List tileEntityListTick = Lists.newArrayList(); private final List c = Lists.newArrayList(); private final Set tileEntityListUnload = HashObjSets.newMutableSet(); // Paper // Akarin - public final List players = Lists.newArrayList(); + public final List players = Lists.newCopyOnWriteArrayList(); // Akarin - iterate safety public final Map playersByName = HashObjObjMaps.newMutableMap(); // Paper - World EntityHuman Lookup Optimizations // Akarin public final List k = Lists.newArrayList(); protected final IntHashMap entitiesById = new IntHashMap<>(); diff --git a/src/main/java/net/minecraft/server/WorldManager.java b/src/main/java/net/minecraft/server/WorldManager.java index 0ba0eb661..0319e4ea7 100644 --- a/src/main/java/net/minecraft/server/WorldManager.java +++ b/src/main/java/net/minecraft/server/WorldManager.java @@ -3,6 +3,8 @@ package net.minecraft.server; import java.util.Iterator; import javax.annotation.Nullable; +import io.akarin.server.core.AkarinAsyncExecutor; + public class WorldManager implements IWorldAccess { private final MinecraftServer a; @@ -36,7 +38,7 @@ public class WorldManager implements IWorldAccess { public void a(@Nullable EntityHuman entityhuman, SoundEffect soundeffect, SoundCategory soundcategory, double d0, double d1, double d2, float f, float f1) { // CraftBukkit - this.world.dimension, // Paper - this.world.dimension -> this.world - this.a.getPlayerList().sendPacketNearby(entityhuman, d0, d1, d2, f > 1.0F ? (double) (16.0F * f) : 16.0D, this.world, new PacketPlayOutNamedSoundEffect(soundeffect, soundcategory, d0, d1, d2, f, f1)); + AkarinAsyncExecutor.scheduleAsyncTask(() -> this.a.getPlayerList().sendPacketNearby(entityhuman, d0, d1, d2, f > 1.0F ? (double) (16.0F * f) : 16.0D, this.world, new PacketPlayOutNamedSoundEffect(soundeffect, soundcategory, d0, d1, d2, f, f1))); // Akarin; } public void a(int i, int j, int k, int l, int i1, int j1) {} @@ -51,15 +53,16 @@ public class WorldManager implements IWorldAccess { public void a(EntityHuman entityhuman, int i, BlockPosition blockposition, int j) { // CraftBukkit - this.world.dimension - this.a.getPlayerList().sendPacketNearby(entityhuman, (double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ(), 64.0D, this.world, new PacketPlayOutWorldEvent(i, blockposition, j, false)); + AkarinAsyncExecutor.scheduleAsyncTask(() -> this.a.getPlayerList().sendPacketNearby(entityhuman, (double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ(), 64.0D, this.world, new PacketPlayOutWorldEvent(i, blockposition, j, false))); // Akarin; } public void a(int i, BlockPosition blockposition, int j) { - this.a.getPlayerList().sendAll(new PacketPlayOutWorldEvent(i, blockposition, j, true)); + AkarinAsyncExecutor.scheduleAsyncTask(() -> this.a.getPlayerList().sendAll(new PacketPlayOutWorldEvent(i, blockposition, j, true))); // Akarin } public void b(int i, BlockPosition blockposition, int j) { // Iterator iterator = this.a.getPlayerList().v().iterator(); // Paper + AkarinAsyncExecutor.scheduleAsyncTask(() -> { // Akarin // CraftBukkit start EntityHuman entityhuman = null; @@ -92,6 +95,7 @@ public class WorldManager implements IWorldAccess { } } } + }); // Akarin } }