3
0
Mirror von https://github.com/GeyserMC/Geyser.git synchronisiert 2024-11-20 06:50:09 +01:00

Handle chunks on the player thread

Dieser Commit ist enthalten in:
Camotoy 2021-11-13 11:03:55 -05:00
Ursprung 59e6fc0285
Commit 393c2b0f91
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: 7EEFB66FE798081F
28 geänderte Dateien mit 219 neuen und 239 gelöschten Zeilen

Datei anzeigen

@ -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();

Datei anzeigen

@ -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);
} }
} }

Datei anzeigen

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

Datei anzeigen

@ -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;

Datei anzeigen

@ -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

Datei anzeigen

@ -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 updateBlock(session);
session.getConnector().getGeneralThreadPool().schedule(() -> { session.getConnector().getLogger().debug("Spawned item frame at location " + bedrockPosition + " with java id " + entityId);
updateBlock(session);
session.getConnector().getLogger().debug("Spawned item frame at location " + bedrockPosition + " with java id " + entityId);
}, 500, TimeUnit.MILLISECONDS);
valid = true; valid = true;
} }

Datei anzeigen

@ -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--;
}
} }

Datei anzeigen

@ -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 {

Datei anzeigen

@ -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!

Datei anzeigen

@ -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:
session.connect(); 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();
}
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()) {

Datei anzeigen

@ -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;
} }
try { CompletableFuture.supplyAsync(() -> {
msaAuthenticationService.login(); try {
GameProfile profile = msaAuthenticationService.getSelectedProfile(); msaAuthenticationService.login();
if (profile == null) { GameProfile profile = msaAuthenticationService.getSelectedProfile();
// Java account is offline if (profile == null) {
disconnect(LanguageUtils.getPlayerLocaleString("geyser.network.remote.invalid_account", clientData.getLanguageCode())); // Java account is offline
disconnect(LanguageUtils.getPlayerLocaleString("geyser.network.remote.invalid_account", clientData.getLanguageCode()));
return null;
}
return new MinecraftProtocol(profile, msaAuthenticationService.getAccessToken());
} catch (RequestException e) {
throw new CompletionException(e);
}
}).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 {
// Wait one second before trying again
connector.getScheduledThread().schedule(() -> attemptCodeAuthentication(msaAuthenticationService), 1, TimeUnit.SECONDS);
}
return; return;
} }
if (!closed) {
protocol = new MinecraftProtocol(profile, msaAuthenticationService.getAccessToken()); this.protocol = response;
connectDownstream();
connectDownstream();
} catch (RequestException e) {
if (!(e instanceof AuthPendingException)) {
connector.getLogger().error("Failed to log in with Microsoft code!", e);
disconnect(e.toString());
} else {
// Wait one second before trying again
connector.getGeneralThreadPool().schedule(() -> attemptCodeAuthentication(msaAuthenticationService), 1, TimeUnit.SECONDS);
} }
} });
} }
/** /**
@ -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));

Datei anzeigen

@ -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);
} }

Datei anzeigen

@ -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);
} }
} }

Datei anzeigen

@ -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);
} }

Datei anzeigen

@ -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);
} }
} }

Datei anzeigen

@ -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);

Datei anzeigen

@ -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);
});
} }
} }
} }

Datei anzeigen

@ -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); SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket();
// session.sendPacket(playStatus); playerGameTypePacket.setGamemode(packet.getGameMode().ordinal());
session.sendUpstreamPacket(playerGameTypePacket);
SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket(); }
playerGameTypePacket.setGamemode(packet.getGameMode().ordinal());
session.sendUpstreamPacket(playerGameTypePacket);
session.setGameMode(packet.getGameMode());
SetEntityDataPacket entityDataPacket = new SetEntityDataPacket(); SetEntityDataPacket entityDataPacket = new SetEntityDataPacket();
entityDataPacket.setRuntimeEntityId(entity.getGeyserId()); entityDataPacket.setRuntimeEntityId(entity.getGeyserId());

Datei anzeigen

@ -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);
} }
} }

Datei anzeigen

@ -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,85 +63,79 @@ 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(() -> { ChunkUtils.ChunkData chunkData = ChunkUtils.translateToBedrock(session, column, yOffset);
try { ChunkSection[] sections = chunkData.sections();
if (session.isClosed()) {
return;
}
ChunkUtils.ChunkData chunkData = ChunkUtils.translateToBedrock(session, column, yOffset);
ChunkSection[] sections = chunkData.sections();
// Find highest section // Find highest section
int sectionCount = sections.length - 1; int sectionCount = sections.length - 1;
while (sectionCount >= 0 && sections[sectionCount] == null) { while (sectionCount >= 0 && sections[sectionCount] == null) {
sectionCount--; sectionCount--;
} }
sectionCount++; sectionCount++;
// Estimate chunk size // Estimate chunk size
int size = 0; int size = 0;
for (int i = 0; i < sectionCount; i++) { for (int i = 0; i < sectionCount; i++) {
ChunkSection section = sections[i]; ChunkSection section = sections[i];
size += (section != null ? section : session.getBlockMappings().getEmptyChunkSection()).estimateNetworkSize(); size += (section != null ? section : session.getBlockMappings().getEmptyChunkSection()).estimateNetworkSize();
} }
size += ChunkUtils.EMPTY_CHUNK_DATA.length; // Consists only of biome data size += ChunkUtils.EMPTY_CHUNK_DATA.length; // Consists only of biome data
size += 1; // Border blocks size += 1; // Border blocks
size += 1; // Extra data length (always 0) size += 1; // Extra data length (always 0)
size += chunkData.blockEntities().length * 64; // Conservative estimate of 64 bytes per tile entity size += chunkData.blockEntities().length * 64; // Conservative estimate of 64 bytes per tile entity
// Allocate output buffer // Allocate output buffer
ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer(size); ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer(size);
byte[] payload; byte[] payload;
try { try {
for (int i = 0; i < sectionCount; i++) { for (int i = 0; i < sectionCount; i++) {
ChunkSection section = sections[i]; ChunkSection section = sections[i];
(section != null ? section : session.getBlockMappings().getEmptyChunkSection()).writeToNetwork(byteBuf); (section != null ? section : session.getBlockMappings().getEmptyChunkSection()).writeToNetwork(byteBuf);
}
// At this point we're dealing with Bedrock chunk sections
boolean overworld = session.getChunkCache().isExtendedHeight();
int dimensionOffset = (overworld ? MINIMUM_ACCEPTED_HEIGHT_OVERWORLD : MINIMUM_ACCEPTED_HEIGHT) >> 4;
for (int i = 0; i < sectionCount; i++) {
int biomeYOffset = dimensionOffset + i;
if (biomeYOffset < yOffset) {
// Ignore this biome section since it goes below the height of the Java world
byteBuf.writeBytes(ChunkUtils.EMPTY_BIOME_DATA);
continue;
}
BiomeTranslator.toNewBedrockBiome(session, column.getBiomeData(), i + (dimensionOffset - yOffset)).writeToNetwork(byteBuf);
}
// As of 1.17.10, Bedrock hardcodes to always read 32 biome sections
int remainingEmptyBiomes = 32 - sectionCount;
for (int i = 0; i < remainingEmptyBiomes; i++) {
byteBuf.writeBytes(ChunkUtils.EMPTY_BIOME_DATA);
}
byteBuf.writeByte(0); // Border blocks - Edu edition only
VarInts.writeUnsignedInt(byteBuf, 0); // extra data length, 0 for now
// Encode tile entities into buffer
NBTOutputStream nbtStream = NbtUtils.createNetworkWriter(new ByteBufOutputStream(byteBuf));
for (NbtMap blockEntity : chunkData.blockEntities()) {
nbtStream.writeTag(blockEntity);
}
// Copy data into byte[], because the protocol lib really likes things that are s l o w
byteBuf.readBytes(payload = new byte[byteBuf.readableBytes()]);
} finally {
byteBuf.release(); // Release buffer to allow buffer pooling to be useful
}
LevelChunkPacket levelChunkPacket = new LevelChunkPacket();
levelChunkPacket.setSubChunksLength(sectionCount);
levelChunkPacket.setCachingEnabled(false);
levelChunkPacket.setChunkX(column.getX());
levelChunkPacket.setChunkZ(column.getZ());
levelChunkPacket.setData(payload);
session.sendUpstreamPacket(levelChunkPacket);
} catch (Exception ex) {
ex.printStackTrace();
} }
});
// At this point we're dealing with Bedrock chunk sections
boolean overworld = session.getChunkCache().isExtendedHeight();
int dimensionOffset = (overworld ? MINIMUM_ACCEPTED_HEIGHT_OVERWORLD : MINIMUM_ACCEPTED_HEIGHT) >> 4;
for (int i = 0; i < sectionCount; i++) {
int biomeYOffset = dimensionOffset + i;
if (biomeYOffset < yOffset) {
// Ignore this biome section since it goes below the height of the Java world
byteBuf.writeBytes(ChunkUtils.EMPTY_BIOME_DATA);
continue;
}
BiomeTranslator.toNewBedrockBiome(session, column.getBiomeData(), i + (dimensionOffset - yOffset)).writeToNetwork(byteBuf);
}
// As of 1.17.10, Bedrock hardcodes to always read 32 biome sections
int remainingEmptyBiomes = 32 - sectionCount;
for (int i = 0; i < remainingEmptyBiomes; i++) {
byteBuf.writeBytes(ChunkUtils.EMPTY_BIOME_DATA);
}
byteBuf.writeByte(0); // Border blocks - Edu edition only
VarInts.writeUnsignedInt(byteBuf, 0); // extra data length, 0 for now
// Encode tile entities into buffer
NBTOutputStream nbtStream = NbtUtils.createNetworkWriter(new ByteBufOutputStream(byteBuf));
for (NbtMap blockEntity : chunkData.blockEntities()) {
nbtStream.writeTag(blockEntity);
}
// Copy data into byte[], because the protocol lib really likes things that are s l o w
byteBuf.readBytes(payload = new byte[byteBuf.readableBytes()]);
} catch (IOException e) {
session.getConnector().getLogger().error("IO error while encoding chunk", e);
return;
} finally {
byteBuf.release(); // Release buffer to allow buffer pooling to be useful
}
LevelChunkPacket levelChunkPacket = new LevelChunkPacket();
levelChunkPacket.setSubChunksLength(sectionCount);
levelChunkPacket.setCachingEnabled(false);
levelChunkPacket.setChunkX(column.getX());
levelChunkPacket.setChunkZ(column.getZ());
levelChunkPacket.setData(payload);
session.sendUpstreamPacket(levelChunkPacket);
} }
} }

Datei anzeigen

@ -141,15 +141,12 @@ 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. player.spawnEntity(session);
if (session.getUpstream().isInitialized()) {
player.spawnEntity(session);
SkullSkinManager.requestAndHandleSkin(player, session, (skin -> session.scheduleInEventLoop(() -> { SkullSkinManager.requestAndHandleSkin(player, session, (skin -> session.scheduleInEventLoop(() -> {
// Delay to minimize split-second "player" pop-in // Delay to minimize split-second "player" pop-in
player.getMetadata().getFlags().setFlag(EntityFlag.INVISIBLE, false); player.getMetadata().getFlags().setFlag(EntityFlag.INVISIBLE, false);
player.updateBedrockMetadata(session); player.updateBedrockMetadata(session);
}, 250, TimeUnit.MILLISECONDS))); }, 250, TimeUnit.MILLISECONDS)));
}
} }
} }

Datei anzeigen

@ -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;

Datei anzeigen

@ -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);
} }

Datei anzeigen

@ -167,31 +167,29 @@ public class SkinManager {
} }
} }
if (session.getUpstream().isInitialized()) { PlayerListPacket.Entry updatedEntry = buildEntryManually(
PlayerListPacket.Entry updatedEntry = buildEntryManually( session,
session, entity.getUuid(),
entity.getUuid(), entity.getUsername(),
entity.getUsername(), entity.getGeyserId(),
entity.getGeyserId(), skin.getTextureUrl(),
skin.getTextureUrl(), skin.getSkinData(),
skin.getSkinData(), cape.getCapeId(),
cape.getCapeId(), cape.getCapeData(),
cape.getCapeData(), geometry
geometry );
);
PlayerListPacket playerAddPacket = new PlayerListPacket(); PlayerListPacket playerAddPacket = new PlayerListPacket();
playerAddPacket.setAction(PlayerListPacket.Action.ADD); playerAddPacket.setAction(PlayerListPacket.Action.ADD);
playerAddPacket.getEntries().add(updatedEntry); playerAddPacket.getEntries().add(updatedEntry);
session.sendUpstreamPacket(playerAddPacket); session.sendUpstreamPacket(playerAddPacket);
if (!entity.isPlayerList()) { if (!entity.isPlayerList()) {
PlayerListPacket playerRemovePacket = new PlayerListPacket(); PlayerListPacket playerRemovePacket = new PlayerListPacket();
playerRemovePacket.setAction(PlayerListPacket.Action.REMOVE); playerRemovePacket.setAction(PlayerListPacket.Action.REMOVE);
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);

Datei anzeigen

@ -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;

Datei anzeigen

@ -55,15 +55,13 @@ 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(""); packet.setNewSkinName(skin.getTextureUrl());
packet.setNewSkinName(skin.getTextureUrl()); 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);
} }

Datei anzeigen

@ -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) {

Datei anzeigen

@ -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