Added back the tablist dimension indicator

This commit is contained in:
2025-03-25 21:17:12 +01:00
parent 7d4dca66f0
commit 83cc3a38e9
11 changed files with 73 additions and 155 deletions

View File

@ -8,6 +8,7 @@ As a challenge I'm trying to make it as user-friendly as possible. (It ain't the
- Custom join message - Custom join message
- Custom quit message - Custom quit message
- Custom chat message - Custom chat message
- Tablist dimension indicator
### Commands ### Commands
- /spectator | Essentially server-side freecam, you get put in spectator and are able to fly around, once you use the command again you get put back to where you were. - /spectator | Essentially server-side freecam, you get put in spectator and are able to fly around, once you use the command again you get put back to where you were.

View File

@ -9,7 +9,7 @@ yarn_mappings=1.21.4+build.8
loader_version=0.16.10 loader_version=0.16.10
# Mod Properties # Mod Properties
mod_version=1.1.1 mod_version=1.1.2
maven_group=wtf.hak.survivalfabric maven_group=wtf.hak.survivalfabric
archives_base_name=survivalfabric archives_base_name=survivalfabric

View File

@ -8,7 +8,7 @@ import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ServerWorld;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.world.GameMode; import net.minecraft.world.GameMode;
import wtf.hak.survivalfabric.utils.DimensionTeams; import wtf.hak.survivalfabric.utils.Utils;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -20,23 +20,23 @@ public class SpectatorCommand {
public static void register(CommandDispatcher<ServerCommandSource> dispatcher, String... aliases) { public static void register(CommandDispatcher<ServerCommandSource> dispatcher, String... aliases) {
for (String str : aliases) for (String str : aliases)
dispatcher.register(CommandManager.literal(str) // Ensure correct method name dispatcher.register(CommandManager.literal(str)
.executes(SpectatorCommand::execute)); .executes(SpectatorCommand::execute));
} }
private static int execute(CommandContext<ServerCommandSource> context) { private static int execute(CommandContext<ServerCommandSource> context) {
ServerCommandSource source = context.getSource(); ServerCommandSource source = context.getSource();
if (source.getEntity() == null) { // Ensure correct method name if (source.getEntity() == null) {
source.sendMessage(Text.literal("Console cannot go into spectator mode!")); source.sendMessage(Text.literal("Console cannot go into spectator mode!"));
return 0; return 0;
} }
ServerPlayerEntity player = (ServerPlayerEntity) source.getEntity(); // Ensure correct method name ServerPlayerEntity player = (ServerPlayerEntity) source.getEntity();
if (spectating.containsKey(player)) { if (spectating.containsKey(player)) {
LocationData data = spectating.get(player); LocationData data = spectating.get(player);
player.teleport(data.world, data.x, data.y, data.z, Set.of(), data.yaw, data.pitch, false); player.teleport(data.world, data.x, data.y, data.z, Set.of(), data.yaw, data.pitch, false);
player.changeGameMode(GameMode.SURVIVAL); player.changeGameMode(GameMode.SURVIVAL);
spectating.remove(player); spectating.remove(player);
//DimensionTeams.assignCorrectTeam(player, data.world.getRegistryKey().getValue().toTranslationKey()); Utils.updateListNames(player);
} else { } else {
spectating.put(player, new LocationData(player spectating.put(player, new LocationData(player
@ -47,7 +47,7 @@ public class SpectatorCommand {
.getPitch(), player .getPitch(), player
.getServerWorld())); .getServerWorld()));
player.changeGameMode(GameMode.SPECTATOR); player.changeGameMode(GameMode.SPECTATOR);
//DimensionTeams.assignCorrectTeam(player, ""); Utils.updateListNames(player);
} }
return 1; return 1;
} }

View File

@ -3,14 +3,10 @@ package wtf.hak.survivalfabric.mixin;
import net.minecraft.network.ClientConnection; import net.minecraft.network.ClientConnection;
import net.minecraft.network.message.MessageType; import net.minecraft.network.message.MessageType;
import net.minecraft.network.message.SignedMessage; import net.minecraft.network.message.SignedMessage;
import net.minecraft.network.packet.s2c.play.PlayerListS2CPacket;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.PlayerManager; import net.minecraft.server.PlayerManager;
import net.minecraft.server.network.ConnectedClientData; import net.minecraft.server.network.ConnectedClientData;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.MutableText;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.text.TextContent;
import net.minecraft.world.GameMode; import net.minecraft.world.GameMode;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
@ -18,9 +14,9 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyArg; import org.spongepowered.asm.mixin.injection.ModifyArg;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import wtf.hak.survivalfabric.commands.SpectatorCommand; import wtf.hak.survivalfabric.commands.SpectatorCommand;
import wtf.hak.survivalfabric.utils.DimensionTeams;
import wtf.hak.survivalfabric.utils.Messages; import wtf.hak.survivalfabric.utils.Messages;
import java.util.Objects;
import java.util.Set; import java.util.Set;
@Mixin(PlayerManager.class) @Mixin(PlayerManager.class)
@ -32,11 +28,6 @@ public abstract class PlayerManagerMixin {
player.sendMessage(text, false); player.sendMessage(text, false);
} }
@Inject(method = {"onPlayerConnect"}, at = {@At(value = "HEAD")})
public void onPlayerConnectHead(ClientConnection connection, ServerPlayerEntity player, ConnectedClientData clientData, CallbackInfo ci) {
//DimensionTeams.assignCorrectTeam(player, player.getServerWorld().getRegistryKey().getValue().toTranslationKey());
}
@ModifyArg(method = {"onPlayerConnect"}, at = @At(value = "INVOKE", target = "Lnet/minecraft/server/PlayerManager;broadcast(Lnet/minecraft/text/Text;Z)V")) @ModifyArg(method = {"onPlayerConnect"}, at = @At(value = "INVOKE", target = "Lnet/minecraft/server/PlayerManager;broadcast(Lnet/minecraft/text/Text;Z)V"))
private Text onPlayerConnect(Text text) { private Text onPlayerConnect(Text text) {
String name = text.getString().split(" ")[0]; String name = text.getString().split(" ")[0];
@ -56,7 +47,7 @@ public abstract class PlayerManagerMixin {
private void onBroadcast(SignedMessage message, ServerPlayerEntity sender, MessageType.Parameters parameters, CallbackInfo ci) { private void onBroadcast(SignedMessage message, ServerPlayerEntity sender, MessageType.Parameters parameters, CallbackInfo ci) {
if(sender != null) { if(sender != null) {
Text text = Text.literal(String.format(Messages.CHAT_FORMAT, sender.getName().getString(), message.getContent().getString())); Text text = Text.literal(String.format(Messages.CHAT_FORMAT, sender.getName().getString(), message.getContent().getString()));
sender.getServer().getPlayerManager().broadcast(text, false); Objects.requireNonNull(sender.getServer()).getPlayerManager().broadcast(text, false);
ci.cancel(); ci.cancel();
} }
} }

View File

@ -15,4 +15,5 @@ public abstract class ServerPlayNetworkHandlerMixin {
String name = text.getString().split(" ")[0]; String name = text.getString().split(" ")[0];
return Text.literal(String.format(Messages.QUIT_MESSAGE, name)); return Text.literal(String.format(Messages.QUIT_MESSAGE, name));
} }
} }

View File

@ -0,0 +1,34 @@
package wtf.hak.survivalfabric.mixin;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import wtf.hak.survivalfabric.commands.SpectatorCommand;
import wtf.hak.survivalfabric.utils.Messages;
@Mixin(ServerPlayerEntity.class)
public abstract class ServerPlayerEntityMixin {
@Inject(method = "getPlayerListName", at = @At("HEAD"), cancellable = true)
private void changePlayerListName(CallbackInfoReturnable<Text> cir) {
ServerPlayerEntity p = (ServerPlayerEntity) (Object) this;
String world = p.getServerWorld().getRegistryKey().getValue().toTranslationKey();
String finalName;
if(!SpectatorCommand.spectating.containsKey(p)) {
finalName = switch (world) {
case "minecraft.overworld" -> Messages.OVERWORLD_PREFIX;
case "minecraft.the_nether" -> Messages.NETHER_PREFIX;
case "minecraft.the_end" -> Messages.END_PREFIX;
default -> Messages.UNKNOWN_PREFIX;
};
} else
finalName = Messages.SPECTATOR_PREFIX;
finalName += "§7" + p.getName().getString();
cir.setReturnValue(Text.of(finalName));
}
}

View File

@ -3,13 +3,11 @@ package wtf.hak.survivalfabric.mixin;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ServerWorld;
import net.minecraft.text.Text;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import wtf.hak.survivalfabric.utils.DimensionTeams; import wtf.hak.survivalfabric.utils.Utils;
import wtf.hak.survivalfabric.utils.Messages;
@Mixin(ServerWorld.class) @Mixin(ServerWorld.class)
public class ServerWorldMixin { public class ServerWorldMixin {
@ -17,10 +15,7 @@ public class ServerWorldMixin {
@Inject(method = "onDimensionChanged", at = {@At("HEAD")}) @Inject(method = "onDimensionChanged", at = {@At("HEAD")})
public void onDimensionChange(Entity entity, CallbackInfo ci) { public void onDimensionChange(Entity entity, CallbackInfo ci) {
if(entity instanceof ServerPlayerEntity) { if(entity instanceof ServerPlayerEntity) {
ServerPlayerEntity player = (ServerPlayerEntity)entity; Utils.updateListNames((ServerPlayerEntity)entity);
String dimension = Messages.getDimensionFormatted(player.getServerWorld().getRegistryKey().getValue().toTranslationKey());
//player.sendMessage(Text.literal(dimension), false);
//DimensionTeams.assignCorrectTeam(player, player.getServerWorld().getRegistryKey().getValue().toTranslationKey());
} }
} }
} }

View File

@ -1,108 +0,0 @@
package wtf.hak.survivalfabric.utils;
import net.minecraft.scoreboard.ServerScoreboard;
import net.minecraft.scoreboard.Team;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import wtf.hak.survivalfabric.commands.SpectatorCommand;
public class DimensionTeams {
public static DimensionTeams INSTANCE;
public Team overworldTeam;
public Team netherTeam;
public Team endTeam;
public Team spectatorTeam;
public Team unknownTeam;
public DimensionTeams(ServerPlayerEntity player) {
ServerScoreboard scoreboard = player.getServer().getScoreboard();
for(Team team : scoreboard.getTeams()) {
if(team.getName().equals("survivalfabric_overworld")) {
player.getServer().getPlayerManager().broadcast(Text.literal("found old"), false);
overworldTeam = team;
} else if(team.getName().equals("survivalfabric_nether")) {
player.getServer().getPlayerManager().broadcast(Text.literal("found old"), false);
netherTeam = team;
} else if(team.getName().equals("survivalfabric_end")) {
player.getServer().getPlayerManager().broadcast(Text.literal("found old"), false);
endTeam = team;
} else if(team.getName().equals("survivalfabric_spectator")) {
player.getServer().getPlayerManager().broadcast(Text.literal("found old"), false);
spectatorTeam = team;
} else if(team.getName().equals("survivalfabric_unknown")) {
player.getServer().getPlayerManager().broadcast(Text.literal("found old"), false);
unknownTeam = team;
}
}
if(overworldTeam == null) {
overworldTeam = scoreboard.addTeam("survivalfabric_overworld");
player.getServer().getPlayerManager().broadcast(Text.literal("added new"), false);
} else if (netherTeam == null) {
netherTeam = scoreboard.addTeam("survivalfabric_nether");
player.getServer().getPlayerManager().broadcast(Text.literal("added new"), false);
} else if (endTeam == null) {
endTeam = scoreboard.addTeam("survivalfabric_end");
player.getServer().getPlayerManager().broadcast(Text.literal("added new"), false);
} else if (spectatorTeam == null) {
spectatorTeam = scoreboard.addTeam("survivalfabric_spectator");
player.getServer().getPlayerManager().broadcast(Text.literal("added new"), false);
} else if (unknownTeam == null) {
unknownTeam = scoreboard.addTeam("survivalfabric_unknown");
player.getServer().getPlayerManager().broadcast(Text.literal("added new"), false);
}
overworldTeam.setPrefix(Text.literal(Messages.OVERWORLD_PREFIX));
overworldTeam.setColor(Formatting.GRAY);
netherTeam.setPrefix(Text.literal(Messages.NETHER_PREFIX));
netherTeam.setColor(Formatting.GRAY);
endTeam.setPrefix(Text.literal(Messages.END_PREFIX));
endTeam.setColor(Formatting.GRAY);
spectatorTeam.setPrefix(Text.literal(Messages.SPECTATOR_PREFIX));
spectatorTeam.setColor(Formatting.GRAY);
unknownTeam.setPrefix(Text.literal(Messages.UNKNOWN_PREFIX));
unknownTeam.setColor(Formatting.GRAY);
}
public static Team assignCorrectTeam(ServerPlayerEntity player, String translationKey) {
if (INSTANCE == null) {
INSTANCE = new DimensionTeams(player);
}
ServerScoreboard scoreboard = player.getServer().getScoreboard();
String name = player.getNameForScoreboard();
for(Team team : player.getServer().getScoreboard().getTeams()) {
if(team.getName().startsWith("survivalfabric")) {
if(team.getPlayerList().contains(name))
scoreboard.removeScoreHolderFromTeam(name, team);
}
}
if(!SpectatorCommand.spectating.containsKey(player)) {
switch (translationKey) {
case "minecraft.overworld":
scoreboard.addScoreHolderToTeam(name, INSTANCE.overworldTeam);
return INSTANCE.overworldTeam;
case "minecraft.the_nether":
scoreboard.addScoreHolderToTeam(name, INSTANCE.netherTeam);
return INSTANCE.netherTeam;
case "minecraft.the_end":
scoreboard.addScoreHolderToTeam(name, INSTANCE.endTeam);
return INSTANCE.endTeam;
default:
scoreboard.addScoreHolderToTeam(name, INSTANCE.unknownTeam);
return INSTANCE.unknownTeam;
}
} else {
scoreboard.addScoreHolderToTeam(name, INSTANCE.spectatorTeam);
return INSTANCE.spectatorTeam;
}
}
}

View File

@ -13,16 +13,4 @@ public class Messages {
public static final String SPECTATOR_PREFIX = "§8[§eSpectator§8] "; public static final String SPECTATOR_PREFIX = "§8[§eSpectator§8] ";
public static final String UNKNOWN_PREFIX = "§8[§7Unknown§8] "; public static final String UNKNOWN_PREFIX = "§8[§7Unknown§8] ";
public static String getDimensionFormatted(String translationKey) {
switch(translationKey) {
case "minecraft.overworld":
return "Overworld";
case "minecraft.the_nether":
return "Nether";
case "minecraft.the_end":
return "End";
default:
return "Unknown";
}
}
} }

View File

@ -0,0 +1,15 @@
package wtf.hak.survivalfabric.utils;
import net.minecraft.network.packet.s2c.play.PlayerListS2CPacket;
import net.minecraft.server.network.ServerPlayerEntity;
import java.util.Objects;
public class Utils {
public static void updateListNames(ServerPlayerEntity p) {
for(ServerPlayerEntity sp : Objects.requireNonNull(p.getServer()).getPlayerManager().getPlayerList()) {
sp.networkHandler.sendPacket(new PlayerListS2CPacket(PlayerListS2CPacket.Action.UPDATE_DISPLAY_NAME, p));
}
}
}

View File

@ -1,13 +1,14 @@
{ {
"required": true, "required": true,
"package": "wtf.hak.survivalfabric.mixin", "package": "wtf.hak.survivalfabric.mixin",
"compatibilityLevel": "JAVA_21", "compatibilityLevel": "JAVA_21",
"mixins": [ "mixins": [
"PlayerManagerMixin", "PlayerManagerMixin",
"ServerPlayNetworkHandlerMixin", "ServerPlayerEntityMixin",
"ServerWorldMixin" "ServerPlayNetworkHandlerMixin",
], "ServerWorldMixin"
"injectors": { ],
"defaultRequire": 1 "injectors": {
"defaultRequire": 1
} }
} }