diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ac72c34..1af9e09 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/src/client/java/modchest/REServerModClient.java b/src/client/java/modchest/REServerModClient.java index 075f88b..7ed34a4 100644 --- a/src/client/java/modchest/REServerModClient.java +++ b/src/client/java/modchest/REServerModClient.java @@ -1,20 +1,18 @@ package modchest; +import modchest.networking.modNetworkingClient; import net.fabricmc.api.ClientModInitializer; -import net.minecraft.client.MinecraftClient; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.text.Text; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class REServerModClient implements ClientModInitializer { - @Override - public void onInitializeClient() { - // This entrypoint is suitable for setting up client-specific logic, such as rendering. - //EntitySleepEvents.START_SLEEPING.register(new entitySleepStartSleepingEventHandler()); - } + public static final Logger LOGGER = LoggerFactory.getLogger("modchest"); // Erster Error Logger + @Override + public void onInitializeClient() { + // This entrypoint is suitable for setting up client-specific logic, such as rendering. - public static void writeMessage(String text) { //holt den Spieler dieses Clients und sendet ihm eine Nachricht - PlayerEntity thisPlayer = MinecraftClient.getInstance().player; - assert thisPlayer != null; - thisPlayer.sendMessage(Text.literal(text)); - } + modNetworkingClient.registerC2SPackets(); //Identifier unter denen der Client zuhoert werden registriert + + LOGGER.info("Modchest successfully loaded!"); + } } \ No newline at end of file diff --git a/src/client/java/modchest/mixin/client/DeathScreen.java b/src/client/java/modchest/mixin/client/DeathScreen.java new file mode 100644 index 0000000..bb96ec9 --- /dev/null +++ b/src/client/java/modchest/mixin/client/DeathScreen.java @@ -0,0 +1,77 @@ +package modchest.mixin.client; + +import modchest.REServerModClient; +import modchest.networking.modNetworkingClient; +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; +import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.text.Text; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(net.minecraft.client.gui.screen.DeathScreen.class) +public class DeathScreen extends Screen { + protected DeathScreen(Text title) { + super(Text.of("useless")); + } //Da wir einen bereits bestehenden Screen erweitern, wird dieser Text nie angezeigt + + @Inject(method = "init", at = @At("TAIL")) //Dieser Code wird in den eigentlich bereits bestehenden Code der Klasse DeathScreen hinzugefügt + private void addMultiSleepButtons(CallbackInfo info) {; + int widthButton = 40; //Die generelle Breite der knoepfe wird definiert + int heightButton = 20; // " hoehe " + int yOffset = 5; //Wie gross der Abstand zwischen der oberen Kante un dem knop sein soll (der Nullpunkt (0|0) ist soswohl im Fenster als auch beim Knopf oben links die Ecke) + int xOffset = this.width / 2 - widthButton / 2; //Die Mitte wird ausgerechnet (Mitte vom fenster minus halbe Breite des knopfes um tatsächlich die Mitte zu haben, weil koordinaten und so + this.addDrawableChild( + new ButtonWidget(xOffset - 2 * (widthButton + 5), yOffset, widthButton, heightButton, Text.translatable("#1"), button -> { //Knopf wird erzeugt + REServerModClient.LOGGER.info("First Button for using spawn pressed!"); + PacketByteBuf buffer = PacketByteBufs.create(); //Neuer Buffer wird erstellt + buffer.writeInt(1); //Beschrieben, damit der Server weiss, welcher knopf gedrueckt wurde + sendPacket(buffer); //Und an den Server gesendet zum Speichern; Die gesamte logik passiert auf dem server, damit man keien fake koordinaten oder so eingeben kann + }) + ); + this.addDrawableChild( + new ButtonWidget(xOffset - (widthButton + 5), yOffset, widthButton, heightButton, Text.translatable("#2"), button -> { //Kommentare siehe knopf #1 + REServerModClient.LOGGER.info("Second Button for using spawn pressed!"); + PacketByteBuf buffer = PacketByteBufs.create(); + buffer.writeInt(2); + sendPacket(buffer); + }) + ); + this.addDrawableChild( + new ButtonWidget(xOffset, yOffset, widthButton, heightButton, Text.translatable("#3"), button -> { //Kommentare siehe knopf #1 + REServerModClient.LOGGER.info("Third Button for using spawn pressed!"); + PacketByteBuf buffer = PacketByteBufs.create(); + buffer.writeInt(3); + sendPacket(buffer); + }) + ); + this.addDrawableChild( + new ButtonWidget(xOffset + (widthButton + 5), yOffset, widthButton, heightButton, Text.translatable("#4"), button -> { //Kommentare siehe knopf #1 + REServerModClient.LOGGER.info("Fourth Button for using spawn pressed!"); + PacketByteBuf buffer = PacketByteBufs.create(); + buffer.writeInt(4); + sendPacket(buffer); + }) + ); + this.addDrawableChild( + new ButtonWidget(xOffset + 2 * (widthButton + 5), yOffset, widthButton, heightButton, Text.translatable("#5"), button -> { //Kommentare siehe knopf #1 + REServerModClient.LOGGER.info("Fifth Button for using spawn pressed!"); + PacketByteBuf buffer = PacketByteBufs.create(); + buffer.writeInt(5); + sendPacket(buffer); + }) + ); + } + + @Unique + private synchronized void sendPacket(PacketByteBuf buffer) { + try { + ClientPlayNetworking.send(modNetworkingClient.death_multi_respawn_buttons, buffer); + } catch (Exception e) {} + } +} diff --git a/src/client/java/modchest/mixin/client/ExampleClientMixin.java b/src/client/java/modchest/mixin/client/ExampleClientMixin.java deleted file mode 100644 index 0a7c93d..0000000 --- a/src/client/java/modchest/mixin/client/ExampleClientMixin.java +++ /dev/null @@ -1,15 +0,0 @@ -package modchest.mixin.client; - -import net.minecraft.client.MinecraftClient; -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.CallbackInfo; - -@Mixin(MinecraftClient.class) -public class ExampleClientMixin { - @Inject(at = @At("HEAD"), method = "run") - private void run(CallbackInfo info) { - // This code is injected into the start of MinecraftClient.run()V - } -} \ No newline at end of file diff --git a/src/client/java/modchest/mixin/client/SleepingChatScreen.java b/src/client/java/modchest/mixin/client/SleepingChatScreen.java new file mode 100644 index 0000000..1d68f8b --- /dev/null +++ b/src/client/java/modchest/mixin/client/SleepingChatScreen.java @@ -0,0 +1,77 @@ +package modchest.mixin.client; + +import modchest.REServerModClient; +import modchest.networking.modNetworkingClient; +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; +import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.text.Text; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(net.minecraft.client.gui.screen.SleepingChatScreen.class) +public class SleepingChatScreen extends Screen { //Sehr identisch zu Death Screen, siehe dort fuer Kommentare!! + protected SleepingChatScreen(Text title) { + super(Text.of("useless")); + } + + @Inject(method = "init", at = @At("TAIL")) + private void addMultiSleepButtons(CallbackInfo info) { + int widthButton = 40; + int heightButton = 20; + int yOffset = 5; + int xOffset = this.width / 2 - widthButton / 2; + this.addDrawableChild( + new ButtonWidget(xOffset - 2 * (widthButton + 5), yOffset, widthButton, heightButton, Text.translatable("#1"), button -> { + REServerModClient.LOGGER.info("First Button for saving spawn pressed!"); + PacketByteBuf buffer = PacketByteBufs.create(); + buffer.writeInt(1); + sendPacket(buffer); + }) + ); + this.addDrawableChild( + new ButtonWidget(xOffset - (widthButton + 5), yOffset, widthButton, heightButton, Text.translatable("#2"), button -> { + REServerModClient.LOGGER.info("Second Button for saving spawn pressed!"); + PacketByteBuf buffer = PacketByteBufs.create(); + buffer.writeInt(2); + sendPacket(buffer); + }) + ); + this.addDrawableChild( + new ButtonWidget(xOffset, yOffset, widthButton, heightButton, Text.translatable("#3"), button -> { + REServerModClient.LOGGER.info("Third Button for saving spawn pressed!"); + PacketByteBuf buffer = PacketByteBufs.create(); + buffer.writeInt(3); + sendPacket(buffer); + }) + ); + this.addDrawableChild( + new ButtonWidget(xOffset + (widthButton + 5), yOffset, widthButton, heightButton, Text.translatable("#4"), button -> { + REServerModClient.LOGGER.info("Fourth Button for saving spawn pressed!"); + PacketByteBuf buffer = PacketByteBufs.create(); + buffer.writeInt(4); + sendPacket(buffer); + }) + ); + this.addDrawableChild( + new ButtonWidget(xOffset + 2 * (widthButton + 5), yOffset, widthButton, heightButton, Text.translatable("#5"), button -> { + REServerModClient.LOGGER.info("Fifth Button for saving spawn pressed!"); + PacketByteBuf buffer = PacketByteBufs.create(); + buffer.writeInt(5); + sendPacket(buffer); + }) + ); + } + + @Unique + private synchronized void sendPacket(PacketByteBuf buffer) { + try { + ClientPlayNetworking.send(modNetworkingClient.start_sleeping_call_buttons, buffer); + } catch (Exception e) {} + } +} \ No newline at end of file diff --git a/src/client/java/modchest/networking/modNetworkingClient.java b/src/client/java/modchest/networking/modNetworkingClient.java new file mode 100644 index 0000000..b30a978 --- /dev/null +++ b/src/client/java/modchest/networking/modNetworkingClient.java @@ -0,0 +1,15 @@ +package modchest.networking; + +import modchest.REServerMod; +import modchest.networking.packet.respawnRequestS2CPacket; +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; +import net.minecraft.util.Identifier; + +public class modNetworkingClient { //Identifier werden eingeführt + public static final Identifier request_respawn = new Identifier(REServerMod.MOD_ID, "request_respawn"); //alle Identifier muessen leider IMMER auf Client und Server (doppelt) eingefuehrt werden + public static final Identifier start_sleeping_call_buttons = new Identifier(REServerMod.MOD_ID, "start_sleeping_call_buttons"); + public static final Identifier death_multi_respawn_buttons = new Identifier(REServerMod.MOD_ID, "death_call_respawn_buttons"); + public static void registerC2SPackets() { //Identifier fuer packets werden registriert (Identifier die der Server aufruft um beim CLient was auszufuehren) + ClientPlayNetworking.registerGlobalReceiver(request_respawn, respawnRequestS2CPacket::receive); //was der Client dann machen soll steht in der receive Methode + } +} diff --git a/src/client/java/modchest/networking/packet/respawnRequestS2CPacket.java b/src/client/java/modchest/networking/packet/respawnRequestS2CPacket.java new file mode 100644 index 0000000..12c10c9 --- /dev/null +++ b/src/client/java/modchest/networking/packet/respawnRequestS2CPacket.java @@ -0,0 +1,15 @@ +package modchest.networking.packet; + +import modchest.REServerModClient; +import net.fabricmc.fabric.api.networking.v1.PacketSender; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientPlayNetworkHandler; +import net.minecraft.network.PacketByteBuf; + +public class respawnRequestS2CPacket { + + public static void receive(MinecraftClient minecraftClient, ClientPlayNetworkHandler clientPlayNetworkHandler, PacketByteBuf packetByteBuf, PacketSender packetSender) { + REServerModClient.LOGGER.info("Server asked for respawn after pressing a saved respawn button!"); + minecraftClient.player.requestRespawn(); + } +} diff --git a/src/client/resources/reservermod.client.mixins.json b/src/client/resources/reservermod.client.mixins.json index efda068..583fc92 100644 --- a/src/client/resources/reservermod.client.mixins.json +++ b/src/client/resources/reservermod.client.mixins.json @@ -3,9 +3,12 @@ "package": "modchest.mixin.client", "compatibilityLevel": "JAVA_17", "client": [ - "ExampleClientMixin" + "DeathScreen", + "SleepingChatScreen" ], "injectors": { "defaultRequire": 1 - } + }, + "mixins": [ + ] } \ No newline at end of file diff --git a/src/main/java/modchest/REServerMod.java b/src/main/java/modchest/REServerMod.java index a082617..38b063e 100644 --- a/src/main/java/modchest/REServerMod.java +++ b/src/main/java/modchest/REServerMod.java @@ -5,6 +5,7 @@ import modchest.block.modBlocks; import modchest.event.entitySleepStartSleepingEventHandler; import modchest.item.modItemGroup; import modchest.item.modItems; +import modchest.networking.modNetworkingServer; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.entity.event.v1.EntitySleepEvents; import org.slf4j.Logger; @@ -23,7 +24,8 @@ public class REServerMod implements ModInitializer { modBlocks.setBlocks(); // Hier werden die Blöcke erstellt modBlockEntities.registerBlockEntities(); // Die Interaktionsmenüs für die Blöcke werden erstellt EntitySleepEvents.START_SLEEPING.register(new entitySleepStartSleepingEventHandler()); + modNetworkingServer.registerS2CPackets(); //Identifier unter denen der Server zuhoert werden registriert - LOGGER.info("Modchest erfolgreich geladen!"); + LOGGER.info("Modchest successfully loaded!"); } } \ No newline at end of file diff --git a/src/main/java/modchest/event/entitySleepStartSleepingEventHandler.java b/src/main/java/modchest/event/entitySleepStartSleepingEventHandler.java index 26b182a..0f939fc 100644 --- a/src/main/java/modchest/event/entitySleepStartSleepingEventHandler.java +++ b/src/main/java/modchest/event/entitySleepStartSleepingEventHandler.java @@ -1,12 +1,17 @@ package modchest.event; +import modchest.networking.modNetworkingServer; import net.fabricmc.fabric.api.entity.event.v1.EntitySleepEvents; +import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; +import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; import net.minecraft.util.math.BlockPos; public class entitySleepStartSleepingEventHandler implements EntitySleepEvents.StartSleeping { + @Override public void onStartSleeping(LivingEntity entity, BlockPos sleepingPos) { //Methode die aufgerufen wird, wenn sich ein entity Hinlegt if (entity instanceof PlayerEntity) { //ueberprueft ob das Entity ein Spieler ist diff --git a/src/main/java/modchest/mixin/ExampleMixin.java b/src/main/java/modchest/mixin/ExampleMixin.java deleted file mode 100644 index 4c11efa..0000000 --- a/src/main/java/modchest/mixin/ExampleMixin.java +++ /dev/null @@ -1,15 +0,0 @@ -package modchest.mixin; - -import net.minecraft.server.MinecraftServer; -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.CallbackInfo; - -@Mixin(MinecraftServer.class) -public class ExampleMixin { - @Inject(at = @At("HEAD"), method = "loadWorld") - private void init(CallbackInfo info) { - // This code is injected into the start of MinecraftServer.loadWorld()V - } -} \ No newline at end of file diff --git a/src/main/java/modchest/mixin/ServerPlayerEntityMixin.java b/src/main/java/modchest/mixin/ServerPlayerEntityMixin.java new file mode 100644 index 0000000..3555b3c --- /dev/null +++ b/src/main/java/modchest/mixin/ServerPlayerEntityMixin.java @@ -0,0 +1,48 @@ +package modchest.mixin; + +import modchest.util.ServerPlayerEntityInterface; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.server.network.ServerPlayerEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ServerPlayerEntity.class) +public abstract class ServerPlayerEntityMixin implements ServerPlayerEntityInterface { + @Unique + private int[] dataSaver = new int [1]; //Weil die nbt daten beim tod geloescht werden, muessen sie rueber kopiert werden; der neue nbtTag existiert aber noch nciht, daher muessen sie hier zwischengespeichert werden + + @Override + public int[] getDataSaver() { //Um errors zu vermeiden, sorgt er dafuer, dass es immer ein persistentData gibt + if (this.dataSaver == null) { + this.dataSaver = new int[1]; + } + return this.dataSaver; + } + + @Override + public void setDataSaver(int[] data) { //Um errors zu vermeiden, sorgt er dafuer, dass es immer ein persistentData gibt + this.dataSaver = data; + } + + @Inject(method = "writeCustomDataToNbt", at = @At("TAIL")) + public void writeCustomDataToNbt(NbtCompound nbt, CallbackInfo ci) { //Immer wenn eine andere Methode aufruft, dass Daten abgespeichert werden sollen, tun wir das jetzt auch + if (this.dataSaver.length == 15) { + nbt.putIntArray("REServerMod.sleep_data", this.dataSaver); + } + } + + @Inject(method = "readCustomDataFromNbt", at = @At("TAIL")) + public void readCustomDataFromNbt(NbtCompound nbt, CallbackInfo ci) { //gleiches beim einlesen. Werden NBT-Daten eingelesen, tun wird das auch + if (dataSaver.length == 15) { + dataSaver = nbt.getIntArray("REServerMod.sleep_data"); + } + } + + @Inject(method = "copyFrom", at = @At("TAIL")) + public void copyFrom(ServerPlayerEntity oldPlayer, boolean alive, CallbackInfo ci) { //Beim Tod des Spielers werden die NBT-Daten kopiert, damit die Spawnpunkte nicht verloren gehen, kopieren wir sie auch mit rueber + dataSaver = ((ServerPlayerEntityInterface) oldPlayer).getDataSaver(); + } +} diff --git a/src/main/java/modchest/networking/modNetworkingServer.java b/src/main/java/modchest/networking/modNetworkingServer.java new file mode 100644 index 0000000..64f771d --- /dev/null +++ b/src/main/java/modchest/networking/modNetworkingServer.java @@ -0,0 +1,19 @@ +package modchest.networking; + +import modchest.REServerMod; +import modchest.networking.packet.deathScreenMultiButtonsC2SPacket; +import modchest.networking.packet.setNewRespawnsC2SPacket; +import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; +import net.minecraft.util.Identifier; + +public class modNetworkingServer { //Identifier werden eingeführt + public static final Identifier request_respawn = new Identifier(REServerMod.MOD_ID, "request_respawn"); //alle Identifier muessen leider IMMER auf Client und Server (doppelt) eingefuehrt werden + public static final Identifier start_sleeping_call_buttons = new Identifier(REServerMod.MOD_ID, "start_sleeping_call_buttons"); + public static final Identifier death_multi_respawn_buttons = new Identifier(REServerMod.MOD_ID, "death_call_respawn_buttons"); + + public static void registerS2CPackets() { //Identifier fuer packets werden registriert (Identifier die der Client aufruft um beim Server was auszufuehren) + ServerPlayNetworking.registerGlobalReceiver(start_sleeping_call_buttons, setNewRespawnsC2SPacket::receive); //was der Server dann machen soll steht in der receive Methode + + ServerPlayNetworking.registerGlobalReceiver(death_multi_respawn_buttons, deathScreenMultiButtonsC2SPacket::receive); + } +} diff --git a/src/main/java/modchest/networking/packet/deathScreenMultiButtonsC2SPacket.java b/src/main/java/modchest/networking/packet/deathScreenMultiButtonsC2SPacket.java new file mode 100644 index 0000000..0292061 --- /dev/null +++ b/src/main/java/modchest/networking/packet/deathScreenMultiButtonsC2SPacket.java @@ -0,0 +1,51 @@ +package modchest.networking.packet; + +import modchest.REServerMod; +import modchest.networking.modNetworkingServer; +import modchest.util.setAndGetMultiButtonsSpawn; +import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; +import net.fabricmc.fabric.api.networking.v1.PacketSender; +import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayNetworkHandler; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.registry.RegistryKey; +import net.minecraft.world.World; + +import java.util.Arrays; + +public class deathScreenMultiButtonsC2SPacket { + public static void receive(MinecraftServer server, ServerPlayerEntity player, //Passiert auf dem Server!!! + ServerPlayNetworkHandler handler, PacketByteBuf buf, PacketSender responseSender) { + setAndGetMultiButtonsSpawn setAndGet = new setAndGetMultiButtonsSpawn(); //um die nicht-statischen Methoden aufzurufen, erzeugen wir ein Objekt. Wir speichern aber keine Daten in der Klasse, daher ist das OK + int num; //num steht fuer Number, und sagt, welcher der 5 Knoepfe gedrueckt wurde, da das Spiel abstuertzt wenn man buf.readInt() mehr als einmal ausfuehrt + try { + num = buf.readInt(); //Um Spielabstuertze definitiv zu verhindern in einem try block, hat aber nie Probleme gemacht, also eine reine absicherung + } catch (Exception e) { + REServerMod.LOGGER.info("Following Error when trying to get the number of pressed Button: " + e + "continuing bwith Button 1"); + num = 1; + } + BlockPos posAlt = player.getSpawnPointPosition(); //Spawnpunkt der Vanilla-respawn-funktion wird gespeichert + RegistryKey dimAlt = player.getSpawnPointDimension();//Dimension " + float angleAlt = player.getSpawnAngle(); //Blickrichtung " + int[] posXYZ = setAndGet.getMultiSpawn(player, num); //neue Koordinaten werden vom Server geholt + + if (posXYZ.length == 3 && posXYZ[0] < 77889900) { //Stellt sicher, dass die 3 spawnkoordinaten nicht null sind; Koordinaten 77889900 sind ausserhalb der Welt und werden daher von mir in setAndGetMultiSpawnButtonsSpawn als Errorcodes verwendet + try { + REServerMod.LOGGER.info("try Respawning from Multi-Sapwn"); + player.setSpawnPoint(World.OVERWORLD, new BlockPos(posXYZ[0], posXYZ[1], posXYZ[2]), 0, true, true); //neuer Spawn wird gesetzt + ServerPlayNetworking.send(player, modNetworkingServer.request_respawn, PacketByteBufs.create()); //Anfrage an den Client zum respawnen wird gesendet + player.sendMessage(Text.of("Respawn bei #" + num + "! ")); + REServerMod.LOGGER.info("Respawned Player: " + player.getDisplayName() + "at " + Arrays.toString(setAndGet.getMultiSpawn(player, num))); + } catch (Exception e) { + REServerMod.LOGGER.info("Sorry! Following error, trying to respawn player " + player.getDisplayName() + ": " + e); + } + } else { + player.sendMessage(Text.of("Oh! Scheint so als wäre der Spawnpunkt nicht gesetzt!")); + } + //player.setSpawnPoint(dimAlt, posAlt, angleAlt, true, false); //TODDO: wenn unkommentiert, setzt er schneller den neuen spawn, als der Spieler respawnt + } +} diff --git a/src/main/java/modchest/networking/packet/setNewRespawnsC2SPacket.java b/src/main/java/modchest/networking/packet/setNewRespawnsC2SPacket.java new file mode 100644 index 0000000..4cab0f3 --- /dev/null +++ b/src/main/java/modchest/networking/packet/setNewRespawnsC2SPacket.java @@ -0,0 +1,46 @@ +package modchest.networking.packet; + +import modchest.REServerMod; +import modchest.util.setAndGetMultiButtonsSpawn; +import net.fabricmc.fabric.api.networking.v1.PacketSender; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayNetworkHandler; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; + +import java.util.Arrays; + +public class setNewRespawnsC2SPacket { + public static void receive(MinecraftServer server, ServerPlayerEntity player, //Passiert auf dem Server!!! + ServerPlayNetworkHandler handler, PacketByteBuf buf, PacketSender responseSender) { + setAndGetMultiButtonsSpawn setAndGet = new setAndGetMultiButtonsSpawn(); + try { + switch (buf.readInt()) { //Wird nur einmal angefragt, daher muss buf.readInt() nicht als variable gesetzt werden + case 1: + setAndGet.setMultiSpawn(player, 1); //Spawnpunkt wird gespeichert + player.sendMessage(Text.of("Respawn #1 gesetzt! " + Arrays.toString(setAndGet.getMultiSpawn(player, 1)))); + break; + case 2: + setAndGet.setMultiSpawn(player, 2); + player.sendMessage(Text.of("Respawn #2 gesetzt! " + Arrays.toString(setAndGet.getMultiSpawn(player, 2)))); + break; + case 3: + setAndGet.setMultiSpawn(player, 3); + player.sendMessage(Text.of("Respawn #3 gesetzt! " + Arrays.toString(setAndGet.getMultiSpawn(player, 3)))); + break; + case 4: + setAndGet.setMultiSpawn(player, 4); + player.sendMessage(Text.of("Respawn #4 gesetzt! " + Arrays.toString(setAndGet.getMultiSpawn(player, 4)))); + break; + case 5: + setAndGet.setMultiSpawn(player, 5); + player.sendMessage(Text.of("Respawn #5 gesetzt! " + Arrays.toString(setAndGet.getMultiSpawn(player, 5)))); + break; + } + } catch (Exception e) { + player.sendMessage(Text.of("Uff! Error beim Speichern! Schaue in die Logs fuer mehr details")); + REServerMod.LOGGER.info("Following Error, when trying to save " + player.getDisplayName() + "'s Spawnpoint: " + e); + } + } +} diff --git a/src/main/java/modchest/util/ServerPlayerEntityInterface.java b/src/main/java/modchest/util/ServerPlayerEntityInterface.java new file mode 100644 index 0000000..6be28b3 --- /dev/null +++ b/src/main/java/modchest/util/ServerPlayerEntityInterface.java @@ -0,0 +1,10 @@ +package modchest.util; + +import net.minecraft.nbt.NbtCompound; +import net.minecraft.server.network.ServerPlayerEntity; +import org.spongepowered.asm.mixin.Unique; + +public interface ServerPlayerEntityInterface { + int[] getDataSaver(); + void setDataSaver(int[] data); +} diff --git a/src/main/java/modchest/util/setAndGetMultiButtonsSpawn.java b/src/main/java/modchest/util/setAndGetMultiButtonsSpawn.java new file mode 100644 index 0000000..10a79bf --- /dev/null +++ b/src/main/java/modchest/util/setAndGetMultiButtonsSpawn.java @@ -0,0 +1,63 @@ +package modchest.util; + +import modchest.REServerMod; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; + +public class setAndGetMultiButtonsSpawn { + + public synchronized void setMultiSpawn(ServerPlayerEntity player, int spawn) { +ServerPlayerEntityInterface castedPlayer = (ServerPlayerEntityInterface) player; + int[] fullArray = castedPlayer.getDataSaver(); //holt sich den ganzen Array, mit allen gespeicherten Spawnpunkten; struktur wird etwas weiter unten erklaert + spawn--; //weil der Array mit Slot 0 beginnt, rutscht alles eins auf + if (fullArray.length != 15) { //Wenn der array unbeschrieben ist (Laenge ungleich 15), wird ein neuer erstellt + fullArray = new int[15]; + for (int i = 0; i < 15; i++) { + fullArray[i] = 77889911; //Lueckenfueller; wird in deathScreenMultiButtonsC2SPacket uebrprueft und rausgefiltert + } + } + fullArray[spawn * 3 + 0] = (int) player.getX(); + fullArray[spawn * 3 + 1] = (int) player.getY(); + fullArray[spawn * 3 + 2] = (int) player.getZ(); + + try { + castedPlayer.setDataSaver(fullArray); +} catch (Exception e) { + REServerMod.LOGGER.info("Sorry! Error when saving Spawnpoint! Exception: " + e); + player.sendMessage(Text.of("Tut mir leid! Das hat nicht geklappt!" + e)); + } + } + + public synchronized int[] getMultiSpawn(ServerPlayerEntity player, int spawn) { + ServerPlayerEntityInterface castedPlayer = (ServerPlayerEntityInterface) player; + int[] fullArray = castedPlayer.getDataSaver(); + if (fullArray.length != 15) { + int[] tempArray = new int[15]; + for (int i = 0; i < 15; i++) { + tempArray[i] = 77889922; //Lueckenfueller; wird in deathScreenMultiButtonsC2SPacket uebrprueft und rausgefiltert + } + + try { + castedPlayer.setDataSaver(fullArray); + } catch (Exception e) { + REServerMod.LOGGER.info("Sorry! Error when loading Spawnpoint! Exception: " + e); + player.sendMessage(Text.of("Tut mir leid! Das hat nicht geklappt!" + e)); + } + } + + fullArray = castedPlayer.getDataSaver(); + spawn--; + int[] posXYZ = new int[3]; + try { + posXYZ[0] = fullArray[spawn * 3 + 0]; //der array ist 15 slots lang, davon gehoeren immer 3 zusammen; wir rutschen also um die anzahl an Spawns weiter und holen uns dann den nullten, ersten un zweiten + posXYZ[1] = fullArray[spawn * 3 + 1]; //Bsp.: angenommen wir wollen den 2. spawn, ueberspringen wir FullArray[0] (x-Koordinate fuer slot 1), FullArray[1] (y-Koordinate fuer slot 1), FullArray[03] (z-Koordinate fuer slot 1), + posXYZ[2] = fullArray[spawn * 3 + 2]; //dann holen wir uns also fullArray[3] = x-Koordinate slot 2, fullArray[4] = y-Koordinate slot 2 und fullArray[5] = z-Koordinate slot 2 + //Diese Art macht es beim Abspeichern etwas einfacher + } catch (Exception e) { + posXYZ[0] = 77889933; + posXYZ[1] = 77889933; + posXYZ[2] = 77889933; + } + return posXYZ; + } +} diff --git a/src/main/resources/reservermod.mixins.json b/src/main/resources/reservermod.mixins.json index 62e600b..91ec238 100644 --- a/src/main/resources/reservermod.mixins.json +++ b/src/main/resources/reservermod.mixins.json @@ -1,11 +1,11 @@ { - "required": true, - "package": "modchest.mixin", - "compatibilityLevel": "JAVA_17", - "mixins": [ - "ExampleMixin" - ], - "injectors": { - "defaultRequire": 1 + "required": true, + "package": "modchest.mixin", + "compatibilityLevel": "JAVA_17", + "mixins": [ + "ServerPlayerEntityMixin" + ], + "injectors": { + "defaultRequire": 1 } } \ No newline at end of file