Search code examples
javaminecraftminecraft-fabric

Overriding Minecraft Respawn Behavior


I want to create a mod that overrides the default respawn mechanics. I want each player to start 100,000 blocks from spawn in a different direction and have that be their default respawn position. I tried overriding the ServerPlayerEntity with this behavior and it seemed like it might have worked but I couldn't find a way to have the server replace the default ServerPlayerEntity with my subclass.

This is what I was trying to do:

public class Server100KMPlayerEntity extends ServerPlayerEntity {
    public Server100KMPlayerEntity(MinecraftServer server, ServerWorld world, GameProfile profile) {
        super(server, world, profile);
    }

    @Override
    public void setSpawnPoint(RegistryKey<World> dimension, @Nullable BlockPos pos, float angle, boolean forced, boolean sendMessage) {
        if (pos != null) {
            super.setSpawnPoint(dimension, pos, angle, forced, sendMessage);
        } else {
            BlockPos newPos = PlayerPositions.valueOf(getEntityName()).getPosition(getServer().getWorld(World.OVERWORLD));
            super.setSpawnPoint(World.OVERWORLD, newPos, 0f, false, sendMessage);
        }
    }

    enum PlayerPositions {
        Player1(-70711, -70711),
        Player2(70711, -70711),
        Player3(-70711, 70711),
        Player4(70711, 70711);

        private final int x, z;

        PlayerPositions(int x, int z) {
            this.x = x;
            this.z = z;
        }

        public BlockPos getPosition(World world) {
            for (int d = world.getTopY(); d > world.getBottomY(); --d) {
                if (!world.isSpaceEmpty(new Box(new BlockPos(x, d, z)))) {
                    return new BlockPos(x, d - 1, z);
                }
            }
            return null;
        }
    }
}

I also looked into S2C and C2S events but didn't see anything there that looked helpful. Any advice would be greatly appreciated.


Solution

  • You can inject a Mixin into the respawnPlayer method within the PlayerManager class, where you set the player's spawn point every time before they spawn.

    Here's an example:

    @Mixin(PlayerManager.class)
    public class ServerPlayerEntityMixin {
        @Inject(method = "respawnPlayer", at = @At("HEAD"))
        public void respawnPlayer(ServerPlayerEntity player, boolean alive, CallbackInfoReturnable<ServerPlayerEntity> cir) {
            BlockPos yourPos = new BlockPos(0, 200, 0); // Whatever position you'd like (you can match the player's display name to a value or something)
            RegistryKey<World> dimension = World.OVERWORLD; // I'm assuming you'd like this to be in the overworld
            player.setSpawnPoint(dimension, yourPos, 0, true, false);
        }
    }
    

    One thing to note: The Y axis matters when you're passing it to setSpawnPoint, if there are blocks present where the player would spawn, it will just default back to the world spawn point. Positions above ground and even in the air should work just fine however.