Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
Shanwer committed Oct 11, 2024
2 parents 424dbff + 50de9d6 commit 7281412
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
Expand Down Expand Up @@ -101,7 +102,7 @@ public void initChannel(@NonNull LocalChannelWithRemoteAddress channel) {

ChannelPipeline pipeline = channel.pipeline();

initializeHAProxySupport(channel);
addHAProxySupport(pipeline);

pipeline.addLast("read-timeout", new ReadTimeoutHandler(getFlag(BuiltinFlags.READ_TIMEOUT, 30)));
pipeline.addLast("write-timeout", new WriteTimeoutHandler(getFlag(BuiltinFlags.WRITE_TIMEOUT, 0)));
Expand Down Expand Up @@ -142,21 +143,33 @@ public MinecraftCodecHelper getCodecHelper() {
return (MinecraftCodecHelper) this.codecHelper;
}

private void initializeHAProxySupport(Channel channel) {
// TODO duplicate code
private void addHAProxySupport(ChannelPipeline pipeline) {
InetSocketAddress clientAddress = getFlag(BuiltinFlags.CLIENT_PROXIED_ADDRESS);
if (clientAddress == null) {
return;
if (clientAddress != null) {
pipeline.addFirst("proxy-protocol-packet-sender", new ChannelInboundHandlerAdapter() {
@Override
public void channelActive(@NonNull ChannelHandlerContext ctx) throws Exception {
HAProxyProxiedProtocol proxiedProtocol = clientAddress.getAddress() instanceof Inet4Address ? HAProxyProxiedProtocol.TCP4 : HAProxyProxiedProtocol.TCP6;
InetSocketAddress remoteAddress;
if (ctx.channel().remoteAddress() instanceof InetSocketAddress) {
remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress();
} else {
remoteAddress = new InetSocketAddress(host, port);
}
ctx.channel().writeAndFlush(new HAProxyMessage(
HAProxyProtocolVersion.V2, HAProxyCommand.PROXY, proxiedProtocol,
clientAddress.getAddress().getHostAddress(), remoteAddress.getAddress().getHostAddress(),
clientAddress.getPort(), remoteAddress.getPort()
));
ctx.pipeline().remove(this);
ctx.pipeline().remove("proxy-protocol-encoder");
super.channelActive(ctx);
}
});
pipeline.addFirst("proxy-protocol-encoder", HAProxyMessageEncoder.INSTANCE);
}
}

channel.pipeline().addLast("proxy-protocol-encoder", HAProxyMessageEncoder.INSTANCE);
HAProxyProxiedProtocol proxiedProtocol = clientAddress.getAddress() instanceof Inet4Address ? HAProxyProxiedProtocol.TCP4 : HAProxyProxiedProtocol.TCP6;
InetSocketAddress remoteAddress = (InetSocketAddress) channel.remoteAddress();
channel.writeAndFlush(new HAProxyMessage(
HAProxyProtocolVersion.V2, HAProxyCommand.PROXY, proxiedProtocol,
clientAddress.getAddress().getHostAddress(), remoteAddress.getAddress().getHostAddress(),
clientAddress.getPort(), remoteAddress.getPort()
)).addListener(future -> channel.pipeline().remove("proxy-protocol-encoder"));
}

/**
* Should only be called when direct ByteBufs should be preferred. At this moment, this should only be called on BungeeCord.
Expand Down
15 changes: 11 additions & 4 deletions core/src/main/java/org/geysermc/geyser/util/EntityUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@

import java.util.Locale;
import net.kyori.adventure.key.Key;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.GameType;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
Expand Down Expand Up @@ -292,22 +294,27 @@ public static GameType toBedrockGamemode(GameMode gamemode) {
};
}

private static String translatedEntityName(String namespace, String name, GeyserSession session) {
// MinecraftLocale would otherwise invoke getBootstrap (which doesn't exist) and create some folders
private static String translatedEntityName(@NonNull String namespace, @NonNull String name, @NonNull GeyserSession session) {
// MinecraftLocale would otherwise invoke getBootstrap (which doesn't exist) and create some folders,
// so use the default fallback value as used in Minecraft Java
if (EnvironmentUtils.isUnitTesting) {
return "entity." + namespace + "." + name;
}
return MinecraftLocale.getLocaleString("entity." + namespace + "." + name, session.locale());
}

public static String translatedEntityName(Key type, GeyserSession session) {
public static String translatedEntityName(@NonNull Key type, @NonNull GeyserSession session) {
return translatedEntityName(type.namespace(), type.value(), session);
}

public static String translatedEntityName(EntityType type, GeyserSession session) {
public static String translatedEntityName(@Nullable EntityType type, @NonNull GeyserSession session) {
if (type == EntityType.PLAYER) {
return "Player"; // the player's name is always shown instead
}
// default fallback value as used in Minecraft Java
if (type == null) {
return "entity.unregistered_sadface";
}
// this works at least with all 1.20.5 entities, except the killer bunny since that's not an entity type.
String typeName = type.name().toLowerCase(Locale.ROOT);
return translatedEntityName("minecraft", typeName, session);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,25 @@
import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNextPacketType;
import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.mockContextScoreboard;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;

import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket;
import org.cloudburstmc.protocol.bedrock.packet.RemoveEntityPacket;
import org.geysermc.geyser.entity.type.living.monster.EnderDragonPartEntity;
import org.geysermc.geyser.session.cache.EntityCache;
import org.geysermc.geyser.translator.protocol.java.entity.JavaRemoveEntitiesTranslator;
import org.geysermc.geyser.translator.protocol.java.entity.spawn.JavaAddExperienceOrbTranslator;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundRemoveEntitiesPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddExperienceOrbPacket;
import org.junit.jupiter.api.Test;

public class TeamIdentifierTest {
/**
* Tests that don't fit in a larger system (e.g. sidebar objective) that were reported on GitHub
*/
public class ScoreboardIssueTests {
/**
* Test for <a href="https://github.com/GeyserMC/Geyser/issues/5075">#5075</a>
*/
@Test
void entityWithoutUuid() {
// experience orbs are the only known entities without an uuid, see Entity#teamIdentifier for more info
Expand All @@ -50,6 +59,10 @@ void entityWithoutUuid() {
// because the entity would be registered and deregistered to the scoreboard.
assertDoesNotThrow(() -> {
context.translate(addExperienceOrbTranslator, new ClientboundAddExperienceOrbPacket(2, 0, 0, 0, 1));

String displayName = context.mockOrSpy(EntityCache.class).getEntityByJavaId(2).getDisplayName();
assertEquals("entity.minecraft.experience_orb", displayName);

context.translate(removeEntitiesTranslator, new ClientboundRemoveEntitiesPacket(new int[] { 2 }));
});

Expand All @@ -58,4 +71,23 @@ void entityWithoutUuid() {
assertNextPacketType(context, RemoveEntityPacket.class);
});
}

/**
* Test for <a href="https://github.com/GeyserMC/Geyser/issues/5078">#5078</a>
*/
@Test
void entityWithoutType() {
// dragon entity parts are an entity in Geyser, but do not have an entity type
mockContextScoreboard(context -> {
// EntityUtils#translatedEntityName used to not take null EntityType's into account,
// so it used to throw an exception
assertDoesNotThrow(() -> {
// dragon entity parts are not spawned using a packet, so we manually create an instance
var dragonHeadPart = new EnderDragonPartEntity(context.session(), 2, 2, 1, 1);

String displayName = dragonHeadPart.getDisplayName();
assertEquals("entity.unregistered_sadface", displayName);
});
});
}
}
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ protocol-codec = "3.0.0.Beta5-20240916.181041-6"
raknet = "1.0.0.CR3-20240416.144209-1"
mcauthlib = "e5b0bcc"
minecraftauth = "4.1.1"
mcprotocollib = "1.21-20241008.134549-23"
mcprotocollib = "1.21-20241010.155958-24"
adventure = "4.14.0"
adventure-platform = "4.3.0"
junit = "5.9.2"
Expand Down

0 comments on commit 7281412

Please sign in to comment.