fix: use og server host for transfer

This commit is contained in:
iceBear67 committed 2026-09-02 00:23:43 +08:00
1 parent bf38f8b2b2
commit 08be6bc3ae
8 files changed
+123 -6

No files matched your search

@@ -1,8 +1,8 @@
§d§lSFCraft 已更新到 2.2.1。
§d§lSFCraft 已更新到 2.3。
§a主要改动:
- 修复了非被斩首怪物掉落头颅的问题
- 修复了 4K 图片无法下载到服务器中的问题。现在高分辨率图片会被降采样
- 修复了鞘翅撞进地狱门需要有空隙的问题
具体信息请查阅我们的更新日志:
§bhttps://sfclub.cc/~sfcraft/changelog/2026-08-08/
§bhttps://sfclub.cc/~sfcraft/changelog/2026-08-24/
@@ -0,0 +1,26 @@
package io.ib67.sfcraft.mixin.common;
import io.ib67.sfcraft.network.HandshakeAddress;
import net.minecraft.network.Connection;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
/**
* Connection 从握手一路存活到 play 阶段,拿来记玩家自报的进服地址。
*/
@Mixin(Connection.class)
public class ConnectionMixin implements HandshakeAddress.Holder {
@Unique
private HandshakeAddress sfcraft$handshakeAddress;
@Override
public @Nullable HandshakeAddress sfcraft$handshakeAddress() {
return sfcraft$handshakeAddress;
}
@Override
public void sfcraft$setHandshakeAddress(@Nullable HandshakeAddress address) {
this.sfcraft$handshakeAddress = address;
}
}
@@ -0,0 +1,12 @@
package io.ib67.sfcraft.mixin.common.bridge;
import net.minecraft.network.Connection;
import net.minecraft.server.network.ServerCommonPacketListenerImpl;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(ServerCommonPacketListenerImpl.class)
public interface ServerCommonNetworkHandlerBridge {
@Accessor("connection")
Connection sfcraft$getConnection();
}
@@ -2,7 +2,9 @@ package io.ib67.sfcraft.mixin.server;
import io.ib67.sfcraft.SFCraft;
import io.ib67.sfcraft.callback.SFCallbacks;
import io.ib67.sfcraft.network.HandshakeAddress;
import net.minecraft.network.Connection;
import net.minecraft.network.protocol.handshake.ClientIntentionPacket;
import net.minecraft.network.protocol.status.ServerStatus;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerHandshakePacketListenerImpl;
@@ -11,7 +13,9 @@ import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ServerHandshakePacketListenerImpl.class)
public abstract class ServerHandshakeNetworkHandlerMixin {
@@ -19,6 +23,15 @@ public abstract class ServerHandshakeNetworkHandlerMixin {
@Final
private Connection connection;
/**
* 记下玩家实际用来进服的地址,房间 transfer 时把他送回同一个入口。
*/
@Inject(method = "handleIntention", at = @At("HEAD"))
private void sf$captureAddress(ClientIntentionPacket packet, CallbackInfo ci) {
((HandshakeAddress.Holder) connection)
.sfcraft$setHandshakeAddress(HandshakeAddress.sanitize(packet.hostName(), packet.port()));
}
@Redirect(method = "handleIntention", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;getStatus()Lnet/minecraft/network/protocol/status/ServerStatus;"))
public ServerStatus getMetadata(MinecraftServer instance) {
var result = SFCallbacks.MOTD.invoker().onMotd(instance,connection);
@@ -10,6 +10,7 @@ import io.ib67.kiwi.tuple.Tuple2;
import io.ib67.sfcraft.ServerModule;
import io.ib67.sfcraft.config.SFConfig;
import io.ib67.sfcraft.inject.MinecraftServerSupplier;
import io.ib67.sfcraft.network.HandshakeAddress;
import io.ib67.sfcraft.registry.RoomRegistry;
import lombok.extern.log4j.Log4j2;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
@@ -20,7 +21,6 @@ import net.minecraft.core.BlockPos;
import net.minecraft.network.PacketSendListener;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.common.ClientboundStoreCookiePacket;
import net.minecraft.network.protocol.common.ClientboundTransferPacket;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.Identifier;
import net.minecraft.server.level.TicketType;
@@ -83,8 +83,9 @@ public class RoomModule extends ServerModule {
return 0;
}
var networkHandler = player.connection;
var transfer = HandshakeAddress.transferPacketFor(player, config);
networkHandler.send(new ClientboundStoreCookiePacket(ROOM_COOKIE, EMPTY), PacketSendListener.thenRun(() -> {
networkHandler.send(new ClientboundTransferPacket(config.domain, config.port));
networkHandler.send(transfer);
}));
return 1;
}
@@ -0,0 +1,61 @@
package io.ib67.sfcraft.network;
import io.ib67.sfcraft.config.SFConfig;
import io.ib67.sfcraft.mixin.common.bridge.ServerCommonNetworkHandlerBridge;
import net.minecraft.network.protocol.common.ClientboundTransferPacket;
import net.minecraft.server.level.ServerPlayer;
import org.jetbrains.annotations.Nullable;
/**
* 玩家在握手包里自报的服务器地址,也就是他实际用来进服的那个地址。
* 由 {@code ServerHandshakeNetworkHandlerMixin} 记到 {@link net.minecraft.network.Connection} 上,
* transfer 时原样回显,让玩家重连回原本的入口而不是配置里写死的那个。
*/
public record HandshakeAddress(String host, int port) {
/**
* 代理(BungeeCord/Velocity legacy forwarding、FML)会把转发数据拼在 hostName 后面,以 '\0' 分隔。
*/
private static final char FORWARDING_SEPARATOR = '\0';
/**
* 挂在 {@link net.minecraft.network.Connection} 上的握手地址,由 ConnectionMixin 实现。
*/
public interface Holder {
@Nullable
HandshakeAddress sfcraft$handshakeAddress();
void sfcraft$setHandshakeAddress(@Nullable HandshakeAddress address);
}
/**
* 清洗握手包里的 hostName / port,不可用时返回 null。
*/
public static @Nullable HandshakeAddress sanitize(String hostName, int port) {
if (hostName == null || port <= 0 || port > 65535) return null;
var host = hostName;
var separator = host.indexOf(FORWARDING_SEPARATOR);
if (separator >= 0) host = host.substring(0, separator);
// SRV 解析出来的 FQDN 可能带尾点
while (host.endsWith(".")) host = host.substring(0, host.length() - 1);
host = host.trim();
return host.isEmpty() ? null : new HandshakeAddress(host, port);
}
/**
* 读玩家当前连接上记的握手地址,拿不到返回 null。
*/
public static @Nullable HandshakeAddress of(ServerPlayer player) {
var connection = ((ServerCommonNetworkHandlerBridge) player.connection).sfcraft$getConnection();
return connection instanceof Holder holder ? holder.sfcraft$handshakeAddress() : null;
}
/**
* 优先把玩家送回他自己用的地址,拿不到才回退配置里的 domain / port。
*/
public static ClientboundTransferPacket transferPacketFor(ServerPlayer player, SFConfig fallback) {
var address = of(player);
return address == null
? new ClientboundTransferPacket(fallback.domain, fallback.port)
: new ClientboundTransferPacket(address.host(), address.port());
}
}
@@ -6,13 +6,13 @@ import io.ib67.sfcraft.config.SFConfig;
import io.ib67.sfcraft.inject.MinecraftServerSupplier;
import io.ib67.sfcraft.module.RoomModule;
import io.ib67.sfcraft.module.SignatureService;
import io.ib67.sfcraft.network.HandshakeAddress;
import io.ib67.sfcraft.registry.RoomRegistry;
import io.ib67.sfcraft.subserver.Room;
import io.netty.buffer.Unpooled;
import net.minecraft.network.PacketSendListener;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.common.ClientboundStoreCookiePacket;
import net.minecraft.network.protocol.common.ClientboundTransferPacket;
import net.minecraft.resources.Identifier;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.CommonColors;
@@ -44,6 +44,8 @@ public class RoomTeleporter {
throw new IllegalStateException("world isn't exist");
}
var networkHandler = player.connection;
// 趁连接还在 play 阶段先取好目标地址
var transfer = HandshakeAddress.transferPacketFor(player, config);
networkHandler.switchToConfig();
var request = new RequestedRoom(room.getServerIdentifier(), name, finalUuid);
var requestBuf = Unpooled.buffer();
@@ -58,7 +60,7 @@ public class RoomTeleporter {
)
);
networkHandler.send(new ClientboundStoreCookiePacket(ROOM_COOKIE, cookie), PacketSendListener.thenRun(() -> {
networkHandler.send(new ClientboundTransferPacket(config.domain, config.port));
networkHandler.send(transfer);
}));
}
}
+2
View File
@@ -9,11 +9,13 @@
"client": [
],
"server": [
"common.ConnectionMixin",
"common.EntityMixin",
"common.MobEntityMixin",
"common.PlayerEntityMixin",
"common.bridge.EntityBridge",
"common.bridge.ServerChunkManagerBridge",
"common.bridge.ServerCommonNetworkHandlerBridge",
"common.bridge.ServerPlayerBridge",
"common.bridge.ServerWorldBridge",
"common.fixes.EndermanEntityMixin",