Handle chunks on the player thread

This commit is contained in:
Camotoy 2021-11-13 11:03:55 -05:00
parent 59e6fc0285
commit 393c2b0f91
No known key found for this signature in database
GPG key ID: 7EEFB66FE798081F
28 changed files with 219 additions and 239 deletions

View file

@ -36,6 +36,7 @@ import com.nukkitx.protocol.bedrock.BedrockServer;
import io.netty.channel.epoll.Epoll; import io.netty.channel.epoll.Epoll;
import io.netty.channel.kqueue.KQueue; import io.netty.channel.kqueue.KQueue;
import io.netty.util.NettyRuntime; import io.netty.util.NettyRuntime;
import io.netty.util.concurrent.DefaultThreadFactory;
import io.netty.util.internal.SystemPropertyUtil; import io.netty.util.internal.SystemPropertyUtil;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
@ -118,7 +119,7 @@ public class GeyserConnector {
private volatile boolean shuttingDown = false; private volatile boolean shuttingDown = false;
private final ScheduledExecutorService generalThreadPool; private final ScheduledExecutorService scheduledThread;
private final BedrockServer bedrockServer; private final BedrockServer bedrockServer;
private final PlatformType platformType; private final PlatformType platformType;
@ -144,7 +145,7 @@ public class GeyserConnector {
logger.info(""); logger.info("");
logger.info("******************************************"); logger.info("******************************************");
this.generalThreadPool = Executors.newScheduledThreadPool(config.getGeneralThreadPool()); this.scheduledThread = Executors.newSingleThreadScheduledExecutor(new DefaultThreadFactory("Geyser Scheduled Thread"));
logger.setDebug(config.isDebugMode()); logger.setDebug(config.isDebugMode());
@ -404,7 +405,7 @@ public class GeyserConnector {
bootstrap.getGeyserLogger().info(LanguageUtils.getLocaleStringLog("geyser.core.shutdown.kick.done")); bootstrap.getGeyserLogger().info(LanguageUtils.getLocaleStringLog("geyser.core.shutdown.kick.done"));
} }
generalThreadPool.shutdown(); scheduledThread.shutdown();
bedrockServer.close(); bedrockServer.close();
if (timeSyncer != null) { if (timeSyncer != null) {
timeSyncer.shutdown(); timeSyncer.shutdown();

View file

@ -97,7 +97,7 @@ public final class LocalSession extends TcpSession {
exceptionCaught(null, future.cause()); exceptionCaught(null, future.cause());
} }
}); });
} catch(Throwable t) { } catch (Throwable t) {
exceptionCaught(null, t); exceptionCaught(null, t);
} }
} }

View file

@ -68,8 +68,6 @@ public interface GeyserConfiguration {
boolean isDebugMode(); boolean isDebugMode();
int getGeneralThreadPool();
boolean isAllowThirdPartyCapes(); boolean isAllowThirdPartyCapes();
boolean isAllowThirdPartyEars(); boolean isAllowThirdPartyEars();

View file

@ -96,9 +96,6 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
@JsonProperty("debug-mode") @JsonProperty("debug-mode")
private boolean debugMode = false; private boolean debugMode = false;
@JsonProperty("general-thread-pool")
private int generalThreadPool = 32;
@JsonProperty("allow-third-party-capes") @JsonProperty("allow-third-party-capes")
private boolean allowThirdPartyCapes = true; private boolean allowThirdPartyCapes = true;

View file

@ -133,9 +133,7 @@ public class BoatEntity extends Entity {
// Get the entity by the first stored passenger and convey motion in this manner // Get the entity by the first stored passenger and convey motion in this manner
Entity entity = session.getEntityCache().getEntityByJavaId(this.passengers.iterator().nextLong()); Entity entity = session.getEntityCache().getEntityByJavaId(this.passengers.iterator().nextLong());
if (entity != null) { if (entity != null) {
session.getConnector().getGeneralThreadPool().execute(() -> updateLeftPaddle(session, entity);
updateLeftPaddle(session, entity)
);
} }
} }
} else { } else {
@ -150,9 +148,7 @@ public class BoatEntity extends Entity {
if (!this.passengers.isEmpty()) { if (!this.passengers.isEmpty()) {
Entity entity = session.getEntityCache().getEntityByJavaId(this.passengers.iterator().nextLong()); Entity entity = session.getEntityCache().getEntityByJavaId(this.passengers.iterator().nextLong());
if (entity != null) { if (entity != null) {
session.getConnector().getGeneralThreadPool().execute(() -> updateRightPaddle(session, entity);
updateRightPaddle(session, entity)
);
} }
} }
} else { } else {
@ -180,7 +176,7 @@ public class BoatEntity extends Entity {
paddleTimeLeft += ROWING_SPEED; paddleTimeLeft += ROWING_SPEED;
sendAnimationPacket(session, rower, AnimatePacket.Action.ROW_LEFT, paddleTimeLeft); sendAnimationPacket(session, rower, AnimatePacket.Action.ROW_LEFT, paddleTimeLeft);
session.getConnector().getGeneralThreadPool().schedule(() -> session.scheduleInEventLoop(() ->
updateLeftPaddle(session, rower), updateLeftPaddle(session, rower),
100, 100,
TimeUnit.MILLISECONDS TimeUnit.MILLISECONDS
@ -193,7 +189,7 @@ public class BoatEntity extends Entity {
paddleTimeRight += ROWING_SPEED; paddleTimeRight += ROWING_SPEED;
sendAnimationPacket(session, rower, AnimatePacket.Action.ROW_RIGHT, paddleTimeRight); sendAnimationPacket(session, rower, AnimatePacket.Action.ROW_RIGHT, paddleTimeRight);
session.getConnector().getGeneralThreadPool().schedule(() -> session.scheduleInEventLoop(() ->
updateRightPaddle(session, rower), updateRightPaddle(session, rower),
100, 100,
TimeUnit.MILLISECONDS TimeUnit.MILLISECONDS

View file

@ -42,8 +42,6 @@ import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.item.ItemTranslator; import org.geysermc.connector.network.translators.item.ItemTranslator;
import org.geysermc.connector.registry.type.ItemMapping; import org.geysermc.connector.registry.type.ItemMapping;
import java.util.concurrent.TimeUnit;
/** /**
* Item frames are an entity in Java but a block entity in Bedrock. * Item frames are an entity in Java but a block entity in Bedrock.
*/ */
@ -99,11 +97,8 @@ public class ItemFrameEntity extends Entity {
session.getItemFrameCache().put(bedrockPosition, this); session.getItemFrameCache().put(bedrockPosition, this);
// Delay is required, or else loading in frames on chunk load is sketchy at best
session.getConnector().getGeneralThreadPool().schedule(() -> {
updateBlock(session); updateBlock(session);
session.getConnector().getLogger().debug("Spawned item frame at location " + bedrockPosition + " with java id " + entityId); session.getConnector().getLogger().debug("Spawned item frame at location " + bedrockPosition + " with java id " + entityId);
}, 500, TimeUnit.MILLISECONDS);
valid = true; valid = true;
} }

View file

@ -29,13 +29,11 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadat
import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityData;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket;
import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.entity.type.EntityType;
import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.session.GeyserSession;
import java.util.concurrent.ScheduledFuture; public class TNTEntity extends Entity implements Tickable {
import java.util.concurrent.TimeUnit;
public class TNTEntity extends Entity {
private int currentTick; private int currentTick;
@ -49,16 +47,26 @@ public class TNTEntity extends Entity {
currentTick = (int) entityMetadata.getValue(); currentTick = (int) entityMetadata.getValue();
metadata.getFlags().setFlag(EntityFlag.IGNITED, true); metadata.getFlags().setFlag(EntityFlag.IGNITED, true);
metadata.put(EntityData.FUSE_LENGTH, currentTick); metadata.put(EntityData.FUSE_LENGTH, currentTick);
ScheduledFuture<?> future = session.getConnector().getGeneralThreadPool().scheduleAtFixedRate(() -> {
if (currentTick % 5 == 0) {
metadata.put(EntityData.FUSE_LENGTH, currentTick);
}
currentTick--;
super.updateBedrockMetadata(entityMetadata, session);
}, 50, 50, TimeUnit.MILLISECONDS); // 5 ticks
session.getConnector().getGeneralThreadPool().schedule(() -> future.cancel(true), (int) entityMetadata.getValue() / 20, TimeUnit.SECONDS);
} }
super.updateBedrockMetadata(entityMetadata, session); super.updateBedrockMetadata(entityMetadata, session);
} }
@Override
public void tick(GeyserSession session) {
if (currentTick == 0) {
// No need to update the fuse when there is none
return;
}
if (currentTick % 5 == 0) {
metadata.put(EntityData.FUSE_LENGTH, currentTick);
SetEntityDataPacket packet = new SetEntityDataPacket();
packet.setRuntimeEntityId(geyserId);
packet.getMetadata().put(EntityData.FUSE_LENGTH, currentTick);
session.sendUpstreamPacket(packet);
}
currentTick--;
}
} }

View file

@ -129,7 +129,7 @@ public class PlayerEntity extends LivingEntity {
if (session.getEntityCache().getPlayerEntity(uuid) == null) if (session.getEntityCache().getPlayerEntity(uuid) == null)
return; return;
if (session.getUpstream().isInitialized() && session.getEntityCache().getEntityByGeyserId(geyserId) == null) { if (session.getEntityCache().getEntityByGeyserId(geyserId) == null) {
session.getEntityCache().spawnEntity(this); session.getEntityCache().spawnEntity(this);
} else { } else {
spawnEntity(session); spawnEntity(session);
@ -288,7 +288,7 @@ public class PlayerEntity extends LivingEntity {
linkPacket.setEntityLink(new EntityLinkData(geyserId, parrot.getGeyserId(), type, false, false)); linkPacket.setEntityLink(new EntityLinkData(geyserId, parrot.getGeyserId(), type, false, false));
// Delay, or else spawned-in players won't get the link // Delay, or else spawned-in players won't get the link
// TODO: Find a better solution. This problem also exists with item frames // TODO: Find a better solution. This problem also exists with item frames
session.getConnector().getGeneralThreadPool().schedule(() -> session.sendUpstreamPacket(linkPacket), 500, TimeUnit.MILLISECONDS); session.scheduleInEventLoop(() -> session.sendUpstreamPacket(linkPacket), 500, TimeUnit.MILLISECONDS);
if (isLeft) { if (isLeft) {
leftParrot = parrot; leftParrot = parrot;
} else { } else {

View file

@ -114,7 +114,7 @@ public class Metrics {
* Starts the Scheduler which submits our data every 30 minutes. * Starts the Scheduler which submits our data every 30 minutes.
*/ */
private void startSubmitting() { private void startSubmitting() {
connector.getGeneralThreadPool().scheduleAtFixedRate(this::submitData, 1, 30, TimeUnit.MINUTES); connector.getScheduledThread().scheduleAtFixedRate(this::submitData, 1, 30, TimeUnit.MINUTES);
// Submit the data every 30 minutes, first time after 1 minutes to give other plugins enough time to start // Submit the data every 30 minutes, first time after 1 minutes to give other plugins enough time to start
// WARNING: Changing the frequency has no effect but your plugin WILL be blocked/deleted! // WARNING: Changing the frequency has no effect but your plugin WILL be blocked/deleted!
// WARNING: Just don't do it! // WARNING: Just don't do it!

View file

@ -104,6 +104,8 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
} }
resourcePacksInfo.setForcedToAccept(GeyserConnector.getInstance().getConfig().isForceResourcePacks()); resourcePacksInfo.setForcedToAccept(GeyserConnector.getInstance().getConfig().isForceResourcePacks());
session.sendUpstreamPacket(resourcePacksInfo); session.sendUpstreamPacket(resourcePacksInfo);
LanguageUtils.loadGeyserLocale(session.getLocale());
return true; return true;
} }
@ -111,7 +113,12 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
public boolean handle(ResourcePackClientResponsePacket packet) { public boolean handle(ResourcePackClientResponsePacket packet) {
switch (packet.getStatus()) { switch (packet.getStatus()) {
case COMPLETED: case COMPLETED:
if (connector.getConfig().getRemote().getAuthType() != AuthType.ONLINE) {
session.authenticate(session.getAuthData().getName());
} else if (!couldLoginUserByName(session.getAuthData().getName())) {
// We must spawn the white world
session.connect(); session.connect();
}
connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.network.connect", session.getAuthData().getName())); connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.network.connect", session.getAuthData().getName()));
break; break;
@ -182,9 +189,6 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.auth.stored_credentials", session.getAuthData().getName())); connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.auth.stored_credentials", session.getAuthData().getName()));
session.setMicrosoftAccount(info.isMicrosoftAccount()); session.setMicrosoftAccount(info.isMicrosoftAccount());
session.authenticate(info.getEmail(), info.getPassword()); session.authenticate(info.getEmail(), info.getPassword());
// TODO send a message to bedrock user telling them they are connected (if nothing like a motd
// somes from the Java server w/in a few seconds)
return true; return true;
} }
} }
@ -192,20 +196,6 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
return false; return false;
} }
@Override
public boolean handle(SetLocalPlayerAsInitializedPacket packet) {
LanguageUtils.loadGeyserLocale(session.getLocale());
if (!session.isLoggedIn() && !session.isLoggingIn() && session.getRemoteAuthType() == AuthType.ONLINE) {
// TODO it is safer to key authentication on something that won't change (UUID, not username)
if (!couldLoginUserByName(session.getAuthData().getName())) {
LoginEncryptionUtils.buildAndShowLoginWindow(session);
}
// else we were able to log the user in
}
return translateAndDefault(packet);
}
@Override @Override
public boolean handle(MovePlayerPacket packet) { public boolean handle(MovePlayerPacket packet) {
if (session.isLoggingIn()) { if (session.isLoggingIn()) {

View file

@ -229,6 +229,8 @@ public class GeyserSession implements CommandSender {
private Vector2i lastChunkPosition = null; private Vector2i lastChunkPosition = null;
private int renderDistance; private int renderDistance;
private boolean sentSpawnPacket;
private boolean loggedIn; private boolean loggedIn;
private boolean loggingIn; private boolean loggingIn;
@ -501,6 +503,10 @@ public class GeyserSession implements CommandSender {
disconnect(disconnectReason.name()); disconnect(disconnectReason.name());
connector.getSessionManager().removeSession(this); connector.getSessionManager().removeSession(this);
}); });
this.remoteAddress = connector.getConfig().getRemote().getAddress();
this.remotePort = connector.getConfig().getRemote().getPort();
this.remoteAuthType = connector.getConfig().getRemote().getAuthType();
} }
/** /**
@ -508,9 +514,7 @@ public class GeyserSession implements CommandSender {
*/ */
public void connect() { public void connect() {
startGame(); startGame();
this.remoteAddress = connector.getConfig().getRemote().getAddress(); sentSpawnPacket = true;
this.remotePort = connector.getConfig().getRemote().getPort();
this.remoteAuthType = connector.getConfig().getRemote().getAuthType();
// Set the hardcoded shield ID to the ID we just defined in StartGamePacket // Set the hardcoded shield ID to the ID we just defined in StartGamePacket
upstream.getSession().getHardcodedBlockingId().set(this.itemMappings.getStoredItems().shield().getBedrockId()); upstream.getSession().getHardcodedBlockingId().set(this.itemMappings.getStoredItems().shield().getBedrockId());
@ -685,27 +689,36 @@ public class GeyserSession implements CommandSender {
if (loggedIn || closed) { if (loggedIn || closed) {
return; return;
} }
CompletableFuture.supplyAsync(() -> {
try { try {
msaAuthenticationService.login(); msaAuthenticationService.login();
GameProfile profile = msaAuthenticationService.getSelectedProfile(); GameProfile profile = msaAuthenticationService.getSelectedProfile();
if (profile == null) { if (profile == null) {
// Java account is offline // Java account is offline
disconnect(LanguageUtils.getPlayerLocaleString("geyser.network.remote.invalid_account", clientData.getLanguageCode())); disconnect(LanguageUtils.getPlayerLocaleString("geyser.network.remote.invalid_account", clientData.getLanguageCode()));
return; return null;
} }
protocol = new MinecraftProtocol(profile, msaAuthenticationService.getAccessToken()); return new MinecraftProtocol(profile, msaAuthenticationService.getAccessToken());
connectDownstream();
} catch (RequestException e) { } catch (RequestException e) {
if (!(e instanceof AuthPendingException)) { throw new CompletionException(e);
connector.getLogger().error("Failed to log in with Microsoft code!", e); }
disconnect(e.toString()); }).whenComplete((response, ex) -> {
if (ex != null) {
if (!(ex instanceof CompletionException completionException) || !(completionException.getCause() instanceof AuthPendingException)) {
connector.getLogger().error("Failed to log in with Microsoft code!", ex);
disconnect(ex.toString());
} else { } else {
// Wait one second before trying again // Wait one second before trying again
connector.getGeneralThreadPool().schedule(() -> attemptCodeAuthentication(msaAuthenticationService), 1, TimeUnit.SECONDS); connector.getScheduledThread().schedule(() -> attemptCodeAuthentication(msaAuthenticationService), 1, TimeUnit.SECONDS);
} }
return;
} }
if (!closed) {
this.protocol = response;
connectDownstream();
}
});
} }
/** /**
@ -725,6 +738,7 @@ public class GeyserSession implements CommandSender {
downstream = new TcpClientSession(this.remoteAddress, this.remotePort, this.protocol); downstream = new TcpClientSession(this.remoteAddress, this.remotePort, this.protocol);
disableSrvResolving(); disableSrvResolving();
} }
if (connector.getConfig().getRemote().isUseProxyProtocol()) { if (connector.getConfig().getRemote().isUseProxyProtocol()) {
downstream.setFlag(BuiltinFlags.ENABLE_CLIENT_PROXY_PROTOCOL, true); downstream.setFlag(BuiltinFlags.ENABLE_CLIENT_PROXY_PROTOCOL, true);
downstream.setFlag(BuiltinFlags.CLIENT_PROXIED_ADDRESS, upstream.getAddress()); downstream.setFlag(BuiltinFlags.CLIENT_PROXIED_ADDRESS, upstream.getAddress());
@ -1133,7 +1147,11 @@ public class GeyserSession implements CommandSender {
StartGamePacket startGamePacket = new StartGamePacket(); StartGamePacket startGamePacket = new StartGamePacket();
startGamePacket.setUniqueEntityId(playerEntity.getGeyserId()); startGamePacket.setUniqueEntityId(playerEntity.getGeyserId());
startGamePacket.setRuntimeEntityId(playerEntity.getGeyserId()); startGamePacket.setRuntimeEntityId(playerEntity.getGeyserId());
startGamePacket.setPlayerGameType(GameType.SURVIVAL); startGamePacket.setPlayerGameType(switch (gameMode) {
case CREATIVE -> GameType.CREATIVE;
case ADVENTURE -> GameType.ADVENTURE;
default -> GameType.SURVIVAL;
});
startGamePacket.setPlayerPosition(Vector3f.from(0, 69, 0)); startGamePacket.setPlayerPosition(Vector3f.from(0, 69, 0));
startGamePacket.setRotation(Vector2f.from(1, 1)); startGamePacket.setRotation(Vector2f.from(1, 1));

View file

@ -65,8 +65,7 @@ public class FormCache {
NetworkStackLatencyPacket latencyPacket = new NetworkStackLatencyPacket(); NetworkStackLatencyPacket latencyPacket = new NetworkStackLatencyPacket();
latencyPacket.setFromServer(true); latencyPacket.setFromServer(true);
latencyPacket.setTimestamp(-System.currentTimeMillis()); latencyPacket.setTimestamp(-System.currentTimeMillis());
session.getConnector().getGeneralThreadPool().schedule( session.scheduleInEventLoop(() -> session.sendUpstreamPacket(latencyPacket),
() -> session.sendUpstreamPacket(latencyPacket),
500, TimeUnit.MILLISECONDS); 500, TimeUnit.MILLISECONDS);
} }

View file

@ -27,7 +27,6 @@ package org.geysermc.connector.network.translators.bedrock;
import com.nukkitx.protocol.bedrock.packet.ClientboundMapItemDataPacket; import com.nukkitx.protocol.bedrock.packet.ClientboundMapItemDataPacket;
import com.nukkitx.protocol.bedrock.packet.MapInfoRequestPacket; import com.nukkitx.protocol.bedrock.packet.MapInfoRequestPacket;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator; import org.geysermc.connector.network.translators.Translator;
@ -44,7 +43,7 @@ public class BedrockMapInfoRequestTranslator extends PacketTranslator<MapInfoReq
ClientboundMapItemDataPacket mapPacket = session.getStoredMaps().remove(mapId); ClientboundMapItemDataPacket mapPacket = session.getStoredMaps().remove(mapId);
if (mapPacket != null) { if (mapPacket != null) {
// Delay the packet 100ms to prevent the client from ignoring the packet // Delay the packet 100ms to prevent the client from ignoring the packet
GeyserConnector.getInstance().getGeneralThreadPool().schedule(() -> session.sendUpstreamPacket(mapPacket), session.scheduleInEventLoop(() -> session.sendUpstreamPacket(mapPacket),
100, TimeUnit.MILLISECONDS); 100, TimeUnit.MILLISECONDS);
} }
} }

View file

@ -61,7 +61,7 @@ public class BedrockMobEquipmentTranslator extends PacketTranslator<MobEquipment
// Activate shield since we are already sneaking // Activate shield since we are already sneaking
// (No need to send a release item packet - Java doesn't do this when swapping items) // (No need to send a release item packet - Java doesn't do this when swapping items)
// Required to do it a tick later or else it doesn't register // Required to do it a tick later or else it doesn't register
session.getConnector().getGeneralThreadPool().schedule(() -> session.sendDownstreamPacket(new ServerboundUseItemPacket(Hand.MAIN_HAND)), session.scheduleInEventLoop(() -> session.sendDownstreamPacket(new ServerboundUseItemPacket(Hand.MAIN_HAND)),
50, TimeUnit.MILLISECONDS); 50, TimeUnit.MILLISECONDS);
} }

View file

@ -76,8 +76,7 @@ public class BedrockNetworkStackLatencyTranslator extends PacketTranslator<Netwo
attributesPacket.setAttributes(Collections.singletonList(GeyserAttributeType.EXPERIENCE_LEVEL.getAttribute(0))); attributesPacket.setAttributes(Collections.singletonList(GeyserAttributeType.EXPERIENCE_LEVEL.getAttribute(0)));
} }
session.getConnector().getGeneralThreadPool().schedule( session.scheduleInEventLoop(() -> session.sendUpstreamPacket(attributesPacket),
() -> session.sendUpstreamPacket(attributesPacket),
500, TimeUnit.MILLISECONDS); 500, TimeUnit.MILLISECONDS);
} }
} }

View file

@ -43,7 +43,7 @@ public class BedrockServerSettingsRequestTranslator extends PacketTranslator<Ser
int windowId = session.getFormCache().addForm(window); int windowId = session.getFormCache().addForm(window);
// Fixes https://bugs.mojang.com/browse/MCPE-94012 because of the delay // Fixes https://bugs.mojang.com/browse/MCPE-94012 because of the delay
session.getConnector().getGeneralThreadPool().schedule(() -> { session.scheduleInEventLoop(() -> {
ServerSettingsResponsePacket serverSettingsResponsePacket = new ServerSettingsResponsePacket(); ServerSettingsResponsePacket serverSettingsResponsePacket = new ServerSettingsResponsePacket();
serverSettingsResponsePacket.setFormData(window.getJsonData()); serverSettingsResponsePacket.setFormData(window.getJsonData());
serverSettingsResponsePacket.setFormId(windowId); serverSettingsResponsePacket.setFormId(windowId);

View file

@ -25,14 +25,12 @@
package org.geysermc.connector.network.translators.bedrock; package org.geysermc.connector.network.translators.bedrock;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
import com.nukkitx.protocol.bedrock.packet.SetLocalPlayerAsInitializedPacket; import com.nukkitx.protocol.bedrock.packet.SetLocalPlayerAsInitializedPacket;
import org.geysermc.connector.entity.player.PlayerEntity; import org.geysermc.connector.common.AuthType;
import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator; import org.geysermc.connector.network.translators.Translator;
import org.geysermc.connector.skin.SkinManager; import org.geysermc.connector.utils.LoginEncryptionUtils;
import org.geysermc.connector.skin.SkullSkinManager;
@Translator(packet = SetLocalPlayerAsInitializedPacket.class) @Translator(packet = SetLocalPlayerAsInitializedPacket.class)
public class BedrockSetLocalPlayerAsInitializedTranslator extends PacketTranslator<SetLocalPlayerAsInitializedPacket> { public class BedrockSetLocalPlayerAsInitializedTranslator extends PacketTranslator<SetLocalPlayerAsInitializedPacket> {
@ -41,23 +39,12 @@ public class BedrockSetLocalPlayerAsInitializedTranslator extends PacketTranslat
if (session.getPlayerEntity().getGeyserId() == packet.getRuntimeEntityId()) { if (session.getPlayerEntity().getGeyserId() == packet.getRuntimeEntityId()) {
if (!session.getUpstream().isInitialized()) { if (!session.getUpstream().isInitialized()) {
session.getUpstream().setInitialized(true); session.getUpstream().setInitialized(true);
session.login();
for (PlayerEntity entity : session.getEntityCache().getEntitiesByType(PlayerEntity.class)) { if (session.getRemoteAuthType() == AuthType.ONLINE) {
if (!entity.isValid()) { if (!session.isLoggedIn()) {
SkinManager.requestAndHandleSkinAndCape(entity, session, null); LoginEncryptionUtils.buildAndShowLoginWindow(session);
entity.sendPlayer(session);
} }
} // else we were able to log the user in
// Send Skulls
for (PlayerEntity entity : session.getSkullCache().values()) {
entity.spawnEntity(session);
SkullSkinManager.requestAndHandleSkin(entity, session, (skin) -> {
entity.getMetadata().getFlags().setFlag(EntityFlag.INVISIBLE, false);
entity.updateBedrockMetadata(session);
});
} }
} }
} }

View file

@ -70,19 +70,25 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket
BiomeTranslator.loadServerBiomes(session, packet.getDimensionCodec()); BiomeTranslator.loadServerBiomes(session, packet.getDimensionCodec());
session.getTagCache().clear(); session.getTagCache().clear();
session.setGameMode(packet.getGameMode());
boolean needsSpawnPacket = !session.isSentSpawnPacket();
if (needsSpawnPacket) {
// The player has yet to spawn so let's do that using some of the information in this Java packet
session.setDimension(newDimension);
session.connect();
}
AdventureSettingsPacket bedrockPacket = new AdventureSettingsPacket(); AdventureSettingsPacket bedrockPacket = new AdventureSettingsPacket();
bedrockPacket.setUniqueEntityId(session.getPlayerEntity().getGeyserId()); bedrockPacket.setUniqueEntityId(session.getPlayerEntity().getGeyserId());
bedrockPacket.setPlayerPermission(PlayerPermission.MEMBER); bedrockPacket.setPlayerPermission(PlayerPermission.MEMBER);
session.sendUpstreamPacket(bedrockPacket); session.sendUpstreamPacket(bedrockPacket);
PlayStatusPacket playStatus = new PlayStatusPacket(); if (!needsSpawnPacket) {
playStatus.setStatus(PlayStatusPacket.Status.LOGIN_SUCCESS);
// session.sendPacket(playStatus);
SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket(); SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket();
playerGameTypePacket.setGamemode(packet.getGameMode().ordinal()); playerGameTypePacket.setGamemode(packet.getGameMode().ordinal());
session.sendUpstreamPacket(playerGameTypePacket); session.sendUpstreamPacket(playerGameTypePacket);
session.setGameMode(packet.getGameMode()); }
SetEntityDataPacket entityDataPacket = new SetEntityDataPacket(); SetEntityDataPacket entityDataPacket = new SetEntityDataPacket();
entityDataPacket.setRuntimeEntityId(entity.getGeyserId()); entityDataPacket.setRuntimeEntityId(entity.getGeyserId());

View file

@ -109,7 +109,7 @@ public class JavaPlayerInfoTranslator extends PacketTranslator<ClientboundPlayer
} }
} }
if (!translate.getEntries().isEmpty() && (packet.getAction() == PlayerListEntryAction.REMOVE_PLAYER || session.getUpstream().isInitialized())) { if (!translate.getEntries().isEmpty()) {
session.sendUpstreamPacket(translate); session.sendUpstreamPacket(translate);
} }
} }

View file

@ -43,6 +43,8 @@ import org.geysermc.connector.network.translators.world.BiomeTranslator;
import org.geysermc.connector.network.translators.world.chunk.ChunkSection; import org.geysermc.connector.network.translators.world.chunk.ChunkSection;
import org.geysermc.connector.utils.ChunkUtils; import org.geysermc.connector.utils.ChunkUtils;
import java.io.IOException;
import static org.geysermc.connector.utils.ChunkUtils.MINIMUM_ACCEPTED_HEIGHT; import static org.geysermc.connector.utils.ChunkUtils.MINIMUM_ACCEPTED_HEIGHT;
import static org.geysermc.connector.utils.ChunkUtils.MINIMUM_ACCEPTED_HEIGHT_OVERWORLD; import static org.geysermc.connector.utils.ChunkUtils.MINIMUM_ACCEPTED_HEIGHT_OVERWORLD;
@ -61,11 +63,6 @@ public class JavaLevelChunkTranslator extends PacketTranslator<ClientboundLevelC
// Ensure that, if the player is using lower world heights, the position is not offset // Ensure that, if the player is using lower world heights, the position is not offset
int yOffset = session.getChunkCache().getChunkMinY(); int yOffset = session.getChunkCache().getChunkMinY();
GeyserConnector.getInstance().getGeneralThreadPool().execute(() -> {
try {
if (session.isClosed()) {
return;
}
ChunkUtils.ChunkData chunkData = ChunkUtils.translateToBedrock(session, column, yOffset); ChunkUtils.ChunkData chunkData = ChunkUtils.translateToBedrock(session, column, yOffset);
ChunkSection[] sections = chunkData.sections(); ChunkSection[] sections = chunkData.sections();
@ -126,6 +123,9 @@ public class JavaLevelChunkTranslator extends PacketTranslator<ClientboundLevelC
// Copy data into byte[], because the protocol lib really likes things that are s l o w // Copy data into byte[], because the protocol lib really likes things that are s l o w
byteBuf.readBytes(payload = new byte[byteBuf.readableBytes()]); byteBuf.readBytes(payload = new byte[byteBuf.readableBytes()]);
} catch (IOException e) {
session.getConnector().getLogger().error("IO error while encoding chunk", e);
return;
} finally { } finally {
byteBuf.release(); // Release buffer to allow buffer pooling to be useful byteBuf.release(); // Release buffer to allow buffer pooling to be useful
} }
@ -137,9 +137,5 @@ public class JavaLevelChunkTranslator extends PacketTranslator<ClientboundLevelC
levelChunkPacket.setChunkZ(column.getZ()); levelChunkPacket.setChunkZ(column.getZ());
levelChunkPacket.setData(payload); levelChunkPacket.setData(payload);
session.sendUpstreamPacket(levelChunkPacket); session.sendUpstreamPacket(levelChunkPacket);
} catch (Exception ex) {
ex.printStackTrace();
}
});
} }
} }

View file

@ -141,8 +141,6 @@ public class SkullBlockEntityTranslator extends BlockEntityTranslator implements
// Cache entity // Cache entity
session.getSkullCache().put(blockPosition, player); session.getSkullCache().put(blockPosition, player);
// Only send to session if we are initialized, otherwise it will happen then.
if (session.getUpstream().isInitialized()) {
player.spawnEntity(session); player.spawnEntity(session);
SkullSkinManager.requestAndHandleSkin(player, session, (skin -> session.scheduleInEventLoop(() -> { SkullSkinManager.requestAndHandleSkin(player, session, (skin -> session.scheduleInEventLoop(() -> {
@ -151,5 +149,4 @@ public class SkullBlockEntityTranslator extends BlockEntityTranslator implements
player.updateBedrockMetadata(session); player.updateBedrockMetadata(session);
}, 250, TimeUnit.MILLISECONDS))); }, 250, TimeUnit.MILLISECONDS)));
} }
}
} }

View file

@ -62,7 +62,7 @@ public class GeyserLegacyPingPassthrough implements IGeyserPingPassthrough, Runn
// Ensure delay is not zero // Ensure delay is not zero
int interval = (connector.getConfig().getPingPassthroughInterval() == 0) ? 1 : connector.getConfig().getPingPassthroughInterval(); int interval = (connector.getConfig().getPingPassthroughInterval() == 0) ? 1 : connector.getConfig().getPingPassthroughInterval();
connector.getLogger().debug("Scheduling ping passthrough at an interval of " + interval + " second(s)."); connector.getLogger().debug("Scheduling ping passthrough at an interval of " + interval + " second(s).");
connector.getGeneralThreadPool().scheduleAtFixedRate(pingPassthrough, 1, interval, TimeUnit.SECONDS); connector.getScheduledThread().scheduleAtFixedRate(pingPassthrough, 1, interval, TimeUnit.SECONDS);
return pingPassthrough; return pingPassthrough;
} }
return null; return null;

View file

@ -212,14 +212,14 @@ public final class FloodgateSkinUploader {
private void reconnectLater(GeyserConnector connector) { private void reconnectLater(GeyserConnector connector) {
// we ca only reconnect when the thread pool is open // we ca only reconnect when the thread pool is open
if (connector.getGeneralThreadPool().isShutdown() || closed) { if (connector.getScheduledThread().isShutdown() || closed) {
logger.info("The skin uploader has been closed"); logger.info("The skin uploader has been closed");
return; return;
} }
long additionalTime = ThreadLocalRandom.current().nextInt(7); long additionalTime = ThreadLocalRandom.current().nextInt(7);
// we don't have to check the result. onClose will handle that for us // we don't have to check the result. onClose will handle that for us
connector.getGeneralThreadPool() connector.getScheduledThread()
.schedule(client::reconnect, 8 + additionalTime, TimeUnit.SECONDS); .schedule(client::reconnect, 8 + additionalTime, TimeUnit.SECONDS);
} }

View file

@ -167,7 +167,6 @@ public class SkinManager {
} }
} }
if (session.getUpstream().isInitialized()) {
PlayerListPacket.Entry updatedEntry = buildEntryManually( PlayerListPacket.Entry updatedEntry = buildEntryManually(
session, session,
entity.getUuid(), entity.getUuid(),
@ -192,7 +191,6 @@ public class SkinManager {
playerRemovePacket.getEntries().add(updatedEntry); playerRemovePacket.getEntries().add(updatedEntry);
session.sendUpstreamPacket(playerRemovePacket); session.sendUpstreamPacket(playerRemovePacket);
} }
}
} catch (Exception e) { } catch (Exception e) {
GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.skin.fail", entity.getUuid()), e); GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.skin.fail", entity.getUuid()), e);
} }

View file

@ -101,7 +101,7 @@ public class SkinProvider {
// Schedule Daily Image Expiry if we are caching them // Schedule Daily Image Expiry if we are caching them
if (GeyserConnector.getInstance().getConfig().getCacheImages() > 0) { if (GeyserConnector.getInstance().getConfig().getCacheImages() > 0) {
GeyserConnector.getInstance().getGeneralThreadPool().scheduleAtFixedRate(() -> { GeyserConnector.getInstance().getScheduledThread().scheduleAtFixedRate(() -> {
File cacheFolder = GeyserConnector.getInstance().getBootstrap().getConfigFolder().resolve("cache").resolve("images").toFile(); File cacheFolder = GeyserConnector.getInstance().getBootstrap().getConfigFolder().resolve("cache").resolve("images").toFile();
if (!cacheFolder.exists()) { if (!cacheFolder.exists()) {
return; return;

View file

@ -55,7 +55,6 @@ public class SkullSkinManager extends SkinManager {
SkinProvider.requestSkin(entity.getUuid(), data.skinUrl(), true) SkinProvider.requestSkin(entity.getUuid(), data.skinUrl(), true)
.whenCompleteAsync((skin, throwable) -> { .whenCompleteAsync((skin, throwable) -> {
try { try {
if (session.getUpstream().isInitialized()) {
PlayerSkinPacket packet = new PlayerSkinPacket(); PlayerSkinPacket packet = new PlayerSkinPacket();
packet.setUuid(entity.getUuid()); packet.setUuid(entity.getUuid());
packet.setOldSkinName(""); packet.setOldSkinName("");
@ -63,7 +62,6 @@ public class SkullSkinManager extends SkinManager {
packet.setSkin(buildSkullEntryManually(skin.getTextureUrl(), skin.getSkinData())); packet.setSkin(buildSkullEntryManually(skin.getTextureUrl(), skin.getSkinData()));
packet.setTrustedSkin(true); packet.setTrustedSkin(true);
session.sendUpstreamPacket(packet); session.sendUpstreamPacket(packet);
}
} catch (Exception e) { } catch (Exception e) {
GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.skin.fail", entity.getUuid()), e); GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.skin.fail", entity.getUuid()), e);
} }

View file

@ -92,7 +92,8 @@ public class CooldownUtils {
titlePacket.setPlatformOnlineId(""); titlePacket.setPlatformOnlineId("");
session.sendUpstreamPacket(titlePacket); session.sendUpstreamPacket(titlePacket);
if (hasCooldown(session)) { if (hasCooldown(session)) {
session.getConnector().getGeneralThreadPool().schedule(() -> computeCooldown(session, sessionPreference, lastHitTime), 50, TimeUnit.MILLISECONDS); // Updated per tick. 1000 divided by 20 ticks equals 50 session.scheduleInEventLoop(() ->
computeCooldown(session, sessionPreference, lastHitTime), 50, TimeUnit.MILLISECONDS); // Updated per tick. 1000 divided by 20 ticks equals 50
} else { } else {
SetTitlePacket removeTitlePacket = new SetTitlePacket(); SetTitlePacket removeTitlePacket = new SetTitlePacket();
if (sessionPreference == CooldownType.ACTIONBAR) { if (sessionPreference == CooldownType.ACTIONBAR) {

View file

@ -110,9 +110,6 @@ max-players: 100
# If debug messages should be sent through console # If debug messages should be sent through console
debug-mode: false debug-mode: false
# Thread pool size
general-thread-pool: 32
# Allow third party capes to be visible. Currently allowing: # Allow third party capes to be visible. Currently allowing:
# OptiFine capes, LabyMod capes, 5Zig capes and MinecraftCapes # OptiFine capes, LabyMod capes, 5Zig capes and MinecraftCapes
allow-third-party-capes: true allow-third-party-capes: true