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:
Ursprung
59e6fc0285
Commit
393c2b0f91
@ -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();
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,8 +68,6 @@ public interface GeyserConfiguration {
|
|||||||
|
|
||||||
boolean isDebugMode();
|
boolean isDebugMode();
|
||||||
|
|
||||||
int getGeneralThreadPool();
|
|
||||||
|
|
||||||
boolean isAllowThirdPartyCapes();
|
boolean isAllowThirdPartyCapes();
|
||||||
|
|
||||||
boolean isAllowThirdPartyEars();
|
boolean isAllowThirdPartyEars();
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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!
|
||||||
|
@ -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()) {
|
||||||
|
@ -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));
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren