Skip to content

Commit 2b76e21

Browse files
authored
Merge branch 'GeyserMC:master' into main
2 parents 3fb818b + 7ae91a4 commit 2b76e21

20 files changed

+198
-233
lines changed

connector/pom.xml

+3-3
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
<properties>
1414
<adventure.version>4.8.0</adventure.version>
1515
<fastutil.version>8.5.2</fastutil.version>
16-
<jackson.version>2.10.2</jackson.version>
17-
<netty.version>4.1.59.Final</netty.version>
16+
<jackson.version>2.12.4</jackson.version>
17+
<netty.version>4.1.66.Final</netty.version>
1818
</properties>
1919

2020
<dependencies>
@@ -167,7 +167,7 @@
167167
<dependency>
168168
<groupId>com.github.GeyserMC</groupId>
169169
<artifactId>PacketLib</artifactId>
170-
<version>25eb4c4</version>
170+
<version>86c9c38</version>
171171
<scope>compile</scope>
172172
<exclusions>
173173
<exclusion>

connector/src/main/java/org/geysermc/connector/network/ConnectorServerEventHandler.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@
3030
import com.nukkitx.protocol.bedrock.BedrockServerSession;
3131
import io.netty.buffer.ByteBuf;
3232
import io.netty.channel.ChannelHandlerContext;
33+
import io.netty.channel.DefaultEventLoopGroup;
3334
import io.netty.channel.socket.DatagramPacket;
35+
import io.netty.util.concurrent.DefaultThreadFactory;
3436
import org.geysermc.connector.GeyserConnector;
3537
import org.geysermc.connector.common.ping.GeyserPingInfo;
3638
import org.geysermc.connector.configuration.GeyserConfiguration;
@@ -56,6 +58,7 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler {
5658
private static final int MAGIC_RAKNET_LENGTH = 338;
5759

5860
private final GeyserConnector connector;
61+
private final DefaultEventLoopGroup eventLoopGroup = new DefaultEventLoopGroup(new DefaultThreadFactory("Geyser player thread"));
5962

6063
public ConnectorServerEventHandler(GeyserConnector connector) {
6164
this.connector = connector;
@@ -162,7 +165,7 @@ public BedrockPong onQuery(InetSocketAddress inetSocketAddress) {
162165
public void onSessionCreation(BedrockServerSession bedrockServerSession) {
163166
bedrockServerSession.setLogging(true);
164167
bedrockServerSession.setCompressionLevel(connector.getConfig().getBedrock().getCompressionLevel());
165-
bedrockServerSession.setPacketHandler(new UpstreamPacketHandler(connector, new GeyserSession(connector, bedrockServerSession)));
168+
bedrockServerSession.setPacketHandler(new UpstreamPacketHandler(connector, new GeyserSession(connector, bedrockServerSession, eventLoopGroup.next())));
166169
// Set the packet codec to default just in case we need to send disconnect packets.
167170
bedrockServerSession.setPacketCodec(BedrockProtocol.DEFAULT_BEDROCK_CODEC);
168171
}

connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ private boolean translateAndDefault(BedrockPacket packet) {
5252
return PacketTranslatorRegistry.BEDROCK_TRANSLATOR.translate(packet.getClass(), packet, session);
5353
}
5454

55+
@Override
56+
boolean defaultHandler(BedrockPacket packet) {
57+
return translateAndDefault(packet);
58+
}
59+
5560
@Override
5661
public boolean handle(LoginPacket loginPacket) {
5762
BedrockPacketCodec packetCodec = BedrockProtocol.getBedrockCodec(loginPacket.getProtocolVersion());
@@ -156,7 +161,7 @@ public boolean handle(ResourcePackClientResponsePacket packet) {
156161

157162
@Override
158163
public boolean handle(ModalFormResponsePacket packet) {
159-
session.getFormCache().handleResponse(packet);
164+
session.getEventLoop().execute(() -> session.getFormCache().handleResponse(packet));
160165
return true;
161166
}
162167

@@ -209,11 +214,6 @@ public boolean handle(MovePlayerPacket packet) {
209214
return translateAndDefault(packet);
210215
}
211216

212-
@Override
213-
boolean defaultHandler(BedrockPacket packet) {
214-
return translateAndDefault(packet);
215-
}
216-
217217
@Override
218218
public boolean handle(ResourcePackChunkRequestPacket packet) {
219219
ResourcePackChunkDataPacket data = new ResourcePackChunkDataPacket();

connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java

+26-46
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@
5757
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
5858
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
5959
import com.nukkitx.protocol.bedrock.packet.*;
60+
import io.netty.channel.EventLoop;
6061
import it.unimi.dsi.fastutil.ints.*;
6162
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
62-
import it.unimi.dsi.fastutil.longs.Long2ObjectMaps;
6363
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
6464
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
6565
import it.unimi.dsi.fastutil.objects.ObjectIterator;
@@ -102,14 +102,21 @@
102102
import java.net.InetSocketAddress;
103103
import java.nio.charset.StandardCharsets;
104104
import java.util.*;
105-
import java.util.concurrent.*;
105+
import java.util.concurrent.CompletableFuture;
106+
import java.util.concurrent.CompletionException;
107+
import java.util.concurrent.ScheduledFuture;
108+
import java.util.concurrent.TimeUnit;
106109
import java.util.concurrent.atomic.AtomicInteger;
107110

108111
@Getter
109112
public class GeyserSession implements CommandSender {
110113

111114
private final GeyserConnector connector;
112115
private final UpstreamSession upstream;
116+
/**
117+
* The loop where all packets and ticking is processed to prevent concurrency issues.
118+
*/
119+
private final EventLoop eventLoop;
113120
private TcpClientSession downstream;
114121
@Setter
115122
private AuthData authData;
@@ -158,11 +165,6 @@ public class GeyserSession implements CommandSender {
158165
@Getter(AccessLevel.NONE)
159166
private final AtomicInteger itemNetId = new AtomicInteger(2);
160167

161-
@Getter(AccessLevel.NONE)
162-
private final Object inventoryLock = new Object();
163-
@Getter(AccessLevel.NONE)
164-
private CompletableFuture<Void> inventoryFuture;
165-
166168
@Setter
167169
private ScheduledFuture<?> craftingGridFuture;
168170

@@ -183,8 +185,8 @@ public class GeyserSession implements CommandSender {
183185
@Setter
184186
private ItemMappings itemMappings;
185187

186-
private final Map<Vector3i, SkullPlayerEntity> skullCache = new ConcurrentHashMap<>();
187-
private final Long2ObjectMap<ClientboundMapItemDataPacket> storedMaps = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>());
188+
private final Map<Vector3i, SkullPlayerEntity> skullCache = new Object2ObjectOpenHashMap<>();
189+
private final Long2ObjectMap<ClientboundMapItemDataPacket> storedMaps = new Long2ObjectOpenHashMap<>();
188190

189191
/**
190192
* Stores the map between Java and Bedrock biome network IDs.
@@ -426,9 +428,10 @@ public class GeyserSession implements CommandSender {
426428

427429
private MinecraftProtocol protocol;
428430

429-
public GeyserSession(GeyserConnector connector, BedrockServerSession bedrockServerSession) {
431+
public GeyserSession(GeyserConnector connector, BedrockServerSession bedrockServerSession, EventLoop eventLoop) {
430432
this.connector = connector;
431433
this.upstream = new UpstreamSession(bedrockServerSession);
434+
this.eventLoop = eventLoop;
432435

433436
this.advancementsCache = new AdvancementsCache(this);
434437
this.bookEditCache = new BookEditCache(this);
@@ -447,7 +450,6 @@ public GeyserSession(GeyserConnector connector, BedrockServerSession bedrockServ
447450

448451
this.playerInventory = new PlayerInventory();
449452
this.openInventory = null;
450-
this.inventoryFuture = CompletableFuture.completedFuture(null);
451453
this.craftingRecipes = new Int2ObjectOpenHashMap<>();
452454
this.unlockedRecipes = new ObjectOpenHashSet<>();
453455
this.lastRecipeNetId = new AtomicInteger(1);
@@ -664,7 +666,7 @@ private void connectDownstream() {
664666
boolean floodgate = this.remoteAuthType == AuthType.FLOODGATE;
665667

666668
// Start ticking
667-
tickThread = connector.getGeneralThreadPool().scheduleAtFixedRate(this::tick, 50, 50, TimeUnit.MILLISECONDS);
669+
tickThread = eventLoop.scheduleAtFixedRate(this::tick, 50, 50, TimeUnit.MILLISECONDS);
668670

669671
downstream = new TcpClientSession(this.remoteAddress, this.remotePort, protocol);
670672
disableSrvResolving();
@@ -1095,39 +1097,6 @@ private void startGame() {
10951097
upstream.sendPacket(startGamePacket);
10961098
}
10971099

1098-
/**
1099-
* Adds a new inventory task.
1100-
* Inventory tasks are executed one at a time, in order.
1101-
*
1102-
* @param task the task to run
1103-
*/
1104-
public void addInventoryTask(Runnable task) {
1105-
synchronized (inventoryLock) {
1106-
inventoryFuture = inventoryFuture.thenRun(task).exceptionally(throwable -> {
1107-
GeyserConnector.getInstance().getLogger().error("Error processing inventory task", throwable.getCause());
1108-
return null;
1109-
});
1110-
}
1111-
}
1112-
1113-
/**
1114-
* Adds a new inventory task with a delay.
1115-
* The delay is achieved by scheduling with the Geyser general thread pool.
1116-
* Inventory tasks are executed one at a time, in order.
1117-
*
1118-
* @param task the delayed task to run
1119-
* @param delayMillis delay in milliseconds
1120-
*/
1121-
public void addInventoryTask(Runnable task, long delayMillis) {
1122-
synchronized (inventoryLock) {
1123-
Executor delayedExecutor = command -> GeyserConnector.getInstance().getGeneralThreadPool().schedule(command, delayMillis, TimeUnit.MILLISECONDS);
1124-
inventoryFuture = inventoryFuture.thenRunAsync(task, delayedExecutor).exceptionally(throwable -> {
1125-
GeyserConnector.getInstance().getLogger().error("Error processing inventory task", throwable.getCause());
1126-
return null;
1127-
});
1128-
}
1129-
}
1130-
11311100
/**
11321101
* @return the next Bedrock item network ID to use for a new item
11331102
*/
@@ -1229,7 +1198,18 @@ public void sendUpstreamPacketImmediately(BedrockPacket packet) {
12291198
* @param packet the java edition packet from MCProtocolLib
12301199
*/
12311200
public void sendDownstreamPacket(Packet packet) {
1232-
if (downstream != null && (protocol.getSubProtocol().equals(SubProtocol.GAME) || packet.getClass() == LoginPluginResponsePacket.class)) {
1201+
if (!closed && this.downstream != null) {
1202+
EventLoop eventLoop = this.downstream.getChannel().eventLoop();
1203+
if (eventLoop.inEventLoop()) {
1204+
sendDownstreamPacket0(packet);
1205+
} else {
1206+
eventLoop.execute(() -> sendDownstreamPacket0(packet));
1207+
}
1208+
}
1209+
}
1210+
1211+
private void sendDownstreamPacket0(Packet packet) {
1212+
if (protocol.getSubProtocol().equals(SubProtocol.GAME) || packet.getClass() == LoginPluginResponsePacket.class) {
12331213
downstream.send(packet);
12341214
} else {
12351215
connector.getLogger().debug("Tried to send downstream packet " + packet.getClass().getSimpleName() + " before connected to the server");

connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java

+8-13
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
package org.geysermc.connector.network.session.cache;
2727

2828
import it.unimi.dsi.fastutil.longs.*;
29+
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
30+
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
2931
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
3032
import lombok.Getter;
3133
import org.geysermc.connector.entity.Tickable;
@@ -44,15 +46,15 @@ public class EntityCache {
4446
private final GeyserSession session;
4547

4648
@Getter
47-
private Long2ObjectMap<Entity> entities = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>());
49+
private final Long2ObjectMap<Entity> entities = new Long2ObjectOpenHashMap<>();
4850
/**
4951
* A list of all entities that must be ticked.
5052
*/
51-
private final List<Tickable> tickableEntities = Collections.synchronizedList(new ArrayList<>());
52-
private Long2LongMap entityIdTranslations = Long2LongMaps.synchronize(new Long2LongOpenHashMap());
53-
private Map<UUID, PlayerEntity> playerEntities = Collections.synchronizedMap(new HashMap<>());
54-
private Map<UUID, BossBar> bossBars = Collections.synchronizedMap(new HashMap<>());
55-
private final Long2LongMap cachedPlayerEntityLinks = Long2LongMaps.synchronize(new Long2LongOpenHashMap());
53+
private final List<Tickable> tickableEntities = new ObjectArrayList<>();
54+
private final Long2LongMap entityIdTranslations = new Long2LongOpenHashMap();
55+
private final Map<UUID, PlayerEntity> playerEntities = new Object2ObjectOpenHashMap<>();
56+
private final Map<UUID, BossBar> bossBars = new Object2ObjectOpenHashMap<>();
57+
private final Long2LongMap cachedPlayerEntityLinks = new Long2LongOpenHashMap();
5658

5759
@Getter
5860
private final AtomicLong nextEntityId = new AtomicLong(2L);
@@ -156,13 +158,6 @@ public void updateBossBars() {
156158
bossBars.values().forEach(BossBar::updateBossBar);
157159
}
158160

159-
public void clear() {
160-
entities = null;
161-
entityIdTranslations = null;
162-
playerEntities = null;
163-
bossBars = null;
164-
}
165-
166161
public long getCachedPlayerEntityLink(long playerId) {
167162
return cachedPlayerEntityLinks.remove(playerId);
168163
}

connector/src/main/java/org/geysermc/connector/network/translators/PacketTranslatorRegistry.java

+7-1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUpdateLightPacket;
3030
import com.github.steveice10.packetlib.packet.Packet;
3131
import com.nukkitx.protocol.bedrock.BedrockPacket;
32+
import io.netty.channel.EventLoop;
3233
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
3334
import org.geysermc.common.PlatformType;
3435
import org.geysermc.connector.GeyserConnector;
@@ -89,7 +90,12 @@ public <P extends T> boolean translate(Class<? extends P> clazz, P packet, Geyse
8990
try {
9091
PacketTranslator<P> translator = (PacketTranslator<P>) translators.get(clazz);
9192
if (translator != null) {
92-
translator.translate(packet, session);
93+
EventLoop eventLoop = session.getEventLoop();
94+
if (eventLoop.inEventLoop()) {
95+
translator.translate(packet, session);
96+
} else {
97+
eventLoop.execute(() -> translator.translate(packet, session));
98+
}
9399
return true;
94100
} else {
95101
if ((GeyserConnector.getInstance().getPlatformType() != PlatformType.STANDALONE || !(packet instanceof BedrockPacket)) && !IGNORED_PACKETS.contains(clazz)) {

connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockAnimateTranslator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public void translate(AnimatePacket packet, GeyserSession session) {
4848
switch (packet.getAction()) {
4949
case SWING_ARM:
5050
// Delay so entity damage can be processed first
51-
session.getConnector().getGeneralThreadPool().schedule(() ->
51+
session.getEventLoop().schedule(() ->
5252
session.sendDownstreamPacket(new ClientPlayerSwingArmPacket(Hand.MAIN_HAND)),
5353
25,
5454
TimeUnit.MILLISECONDS

connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java

+18-20
Original file line numberDiff line numberDiff line change
@@ -39,29 +39,27 @@ public class BedrockContainerCloseTranslator extends PacketTranslator<ContainerC
3939

4040
@Override
4141
public void translate(ContainerClosePacket packet, GeyserSession session) {
42-
session.addInventoryTask(() -> {
43-
byte windowId = packet.getId();
42+
byte windowId = packet.getId();
4443

45-
//Client wants close confirmation
46-
session.sendUpstreamPacket(packet);
47-
session.setClosingInventory(false);
44+
//Client wants close confirmation
45+
session.sendUpstreamPacket(packet);
46+
session.setClosingInventory(false);
4847

49-
if (windowId == -1 && session.getOpenInventory() instanceof MerchantContainer) {
50-
// 1.16.200 - window ID is always -1 sent from Bedrock
51-
windowId = (byte) session.getOpenInventory().getId();
52-
}
48+
if (windowId == -1 && session.getOpenInventory() instanceof MerchantContainer) {
49+
// 1.16.200 - window ID is always -1 sent from Bedrock
50+
windowId = (byte) session.getOpenInventory().getId();
51+
}
5352

54-
Inventory openInventory = session.getOpenInventory();
55-
if (openInventory != null) {
56-
if (windowId == openInventory.getId()) {
57-
ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(windowId);
58-
session.sendDownstreamPacket(closeWindowPacket);
59-
InventoryUtils.closeInventory(session, windowId, false);
60-
} else if (openInventory.isPending()) {
61-
InventoryUtils.displayInventory(session, openInventory);
62-
openInventory.setPending(false);
63-
}
53+
Inventory openInventory = session.getOpenInventory();
54+
if (openInventory != null) {
55+
if (windowId == openInventory.getId()) {
56+
ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(windowId);
57+
session.sendDownstreamPacket(closeWindowPacket);
58+
InventoryUtils.closeInventory(session, windowId, false);
59+
} else if (openInventory.isPending()) {
60+
InventoryUtils.displayInventory(session, openInventory);
61+
openInventory.setPending(false);
6462
}
65-
});
63+
}
6664
}
6765
}

0 commit comments

Comments
 (0)