diff --git a/.gitignore b/.gitignore index 9b222ae..36dfa2c 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,9 @@ build/ out/ classes/ +.gradlew +.gradle-wrapper.properties + # eclipse *.launch diff --git a/src/main/java/modchest/REServerMod.java b/src/main/java/modchest/REServerMod.java index 38b063e..fe7cbcc 100644 --- a/src/main/java/modchest/REServerMod.java +++ b/src/main/java/modchest/REServerMod.java @@ -1,15 +1,10 @@ package modchest; -import modchest.block.entity.modBlockEntities; -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; import org.slf4j.LoggerFactory; +import modchest.util.initializer; //Main file; Hier wird alles aufgesetzt public class REServerMod implements ModInitializer { @@ -17,14 +12,11 @@ public class REServerMod implements ModInitializer { public static final Logger LOGGER = LoggerFactory.getLogger("modchest"); // Erster Error Logger @Override - public void onInitialize() { - modItemGroup.modchest(); // Item Gruppe fürs Creative-Inventar wird erstellt; In dieser Gruppe sollen - // dann alle Items und Blöcke dieser Mod angezeigt werden - modItems.setItems(); // die Items werden erstellt - 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 + public void onInitialize() { //Der uebersicht halber sind jetzt alle initializer in Klassen in util in initializer + initializer.itemGroups(); + initializer.itemsAndBlocks(); + initializer.events(); + initializer.networking(); LOGGER.info("Modchest successfully loaded!"); } diff --git a/src/main/java/modchest/event/entitySleepStartSleepingEventHandler.java b/src/main/java/modchest/event/entitySleepStartSleepingEventHandler.java deleted file mode 100644 index 0f939fc..0000000 --- a/src/main/java/modchest/event/entitySleepStartSleepingEventHandler.java +++ /dev/null @@ -1,21 +0,0 @@ -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 - entity.sendMessage(Text.of("Schlafmütze!")); - } - } -} \ No newline at end of file diff --git a/src/main/java/modchest/event/playerAfterRespawnEvent.java b/src/main/java/modchest/event/playerAfterRespawnEvent.java new file mode 100644 index 0000000..fc098ae --- /dev/null +++ b/src/main/java/modchest/event/playerAfterRespawnEvent.java @@ -0,0 +1,36 @@ +package modchest.event; + +import modchest.REServerMod; +import modchest.util.setAndGetMultiButtonsSpawn; +import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.registry.Registry; +import net.minecraft.util.registry.RegistryKey; +import net.minecraft.world.World; + +public class playerAfterRespawnEvent implements ServerPlayerEvents.AfterRespawn { //Wenn die Multi-Spawn mod verwendet wurde, muss der Vanillaspawn wieder gesetzt werden + @Override + public void afterRespawn(ServerPlayerEntity oldPlayer, ServerPlayerEntity newPlayer, boolean alive) { + setAndGetMultiButtonsSpawn setAndGet = new setAndGetMultiButtonsSpawn(); //Damit die Mehtoden benutzt werden koennen, muss ein Objekt erstellt werden; ist aber egal, weil eh keine Daten in dieser Klasse gespeichert werden + NbtCompound nbt = setAndGet.getMultiSpawnVanilla(newPlayer); //holt sich den nbt-tag + if (nbt != null) { + try { + int[] location = nbt.getIntArray("location"); //holt sich den gespeicherten Ort + BlockPos blockPos = new BlockPos(location[0], location[1], location[2]); + + String[] parts = nbt.getString("dimension").split(":"); //holt sich die gespeicherte Dimension; trennt den String entspreichend; damit sollte es auch funktionieren, sollte eine Mod weiter Dimensionen hinzufuegen + parts = parts[2].split("]"); + RegistryKey dim = RegistryKey.of(Registry.WORLD_KEY, new Identifier(parts[0])); + + float angle = nbt.getFloat("angle"); //Und den blickwinkel + + newPlayer.setSpawnPoint(dim, blockPos, angle, true, false); + } catch (Exception e) { + REServerMod.LOGGER.info("Following error when trying set " + newPlayer.getDisplayName() + "'s Vanilla Spawn: " + e); + } + } + } +} diff --git a/src/main/java/modchest/mixin/ServerPlayerEntityMixin.java b/src/main/java/modchest/mixin/ServerPlayerEntityMixin.java index 3555b3c..b43c67b 100644 --- a/src/main/java/modchest/mixin/ServerPlayerEntityMixin.java +++ b/src/main/java/modchest/mixin/ServerPlayerEntityMixin.java @@ -1,5 +1,6 @@ package modchest.mixin; +import modchest.REServerMod; import modchest.util.ServerPlayerEntityInterface; import net.minecraft.nbt.NbtCompound; import net.minecraft.server.network.ServerPlayerEntity; @@ -9,40 +10,41 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import java.util.Arrays; + @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 + private NbtCompound dataSaver = new NbtCompound(); //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 + public NbtCompound getDataSaver() { //Um errors zu vermeiden, sorgt er dafuer, dass es immer ein persistentData gibt if (this.dataSaver == null) { - this.dataSaver = new int[1]; + this.dataSaver = new NbtCompound(); } return this.dataSaver; } @Override - public void setDataSaver(int[] data) { //Um errors zu vermeiden, sorgt er dafuer, dass es immer ein persistentData gibt + public void setDataSaver(NbtCompound 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); - } + nbt.put("REServerMod", this.dataSaver); + REServerMod.LOGGER.info("writeCustomDataToNbt called"); } @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"); - } + dataSaver = (NbtCompound) nbt.get("REServerMod"); + REServerMod.LOGGER.info("readCustomDataFromNbt called with following Data: " + Arrays.toString(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(); + REServerMod.LOGGER.info("copyFrom called"); } } diff --git a/src/main/java/modchest/mixin/bedBlock.java b/src/main/java/modchest/mixin/bedBlock.java new file mode 100644 index 0000000..d11e348 --- /dev/null +++ b/src/main/java/modchest/mixin/bedBlock.java @@ -0,0 +1,59 @@ +package modchest.mixin; + +import modchest.REServerMod; +import modchest.util.setAndGetMultiButtonsSpawn; +import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import net.minecraft.block.BedBlock; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.Arrays; +import java.util.List; + +@Mixin(BedBlock.class) +public class bedBlock { + + @Inject(method = "onBreak", at = @At("HEAD")) + public void onBreak(World world, BlockPos pos, BlockState state, PlayerEntity player, CallbackInfo ci) { //Ueberprueft, wenn ein Bett zerstoert wird, ob jemand dieses Bett als Spawnpunkt hat + if (!world.isClient) { //Stellt sicher, dass das ganze nciht auf dem CLient rechnet wird, weil der Code sonst abstuertzt + setAndGetMultiButtonsSpawn setAndGet = new setAndGetMultiButtonsSpawn(); //Damit die Mehtoden benutzt werden koennen, muss ein Objekt erstellt werden; ist aber egal, weil eh keine Daten in dieser Klasse gespeichert werden + List playerArray = null; + try { //Sollte der Code doch ausversehen auf dem Client ausgefuehrt werden, wuerde die folgende Zeile einen Error schmeissen + playerArray = world.getPlayers(); //holt sich die liste aller Spieler auf dem server + } catch (Exception e) { + REServerMod.LOGGER.info("Error when trying to get players Array after Bed was destroyed: " + e); + } + for (int i = 0; i < playerArray.size(); i++) { //geht fuer jeden Spieler durch + for (int j = 1; j <= 5; j++) { //und fuer alle Speicherslots dieser + int[] posXYZ = new int[0]; + try { //Sollte der Code doch ausversehen auf dem Client ausgefuehrt werden, wuerde die folgende Zeile einen Error schmeissen + posXYZ = setAndGet.getMultiSpawn((ServerPlayerEntity) playerArray.get(i), j); + } catch (Exception e) { + REServerMod.LOGGER.info("Error casting playerArray to ServerPlayerEntity: " + e); + } + if (inRange(pos.getX(), posXYZ[0], 1) && inRange(pos.getY(), posXYZ[1], 1) && inRange(pos.getZ(), posXYZ[2], 1)) { //Gleicht ab, ob die Koordinaten uebereinstimmen; die Spawnpunkte sind nicht immer ganz sauber, daher wird in Blockrange 1 geschaut + player.sendMessage(Text.of(Text.of(pos.toShortString()) + " zu " + new BlockPos(posXYZ[0], posXYZ[1], posXYZ[2]))); + try { //Sollte der Code doch ausversehen auf dem Client ausgefuehrt werden, wuerde die folgende Zeile einen Error schmeissen + setAndGet.setMultiSpawnBlank((ServerPlayerEntity) playerArray.get(i), j); //Wird ein bett zerstoert, wird der Spawnpunkt geblanked + } catch (Exception e) { + REServerMod.LOGGER.info("Error when trying to get players Array after Bed was destroyed: " + e); + } + + } + } + } + } + } + + private boolean inRange(int one, int two, int range) { + one = (one - two); + return (-range) <= one && one <= range; + } +} diff --git a/src/main/java/modchest/networking/packet/deathScreenMultiButtonsC2SPacket.java b/src/main/java/modchest/networking/packet/deathScreenMultiButtonsC2SPacket.java index 0292061..1597a00 100644 --- a/src/main/java/modchest/networking/packet/deathScreenMultiButtonsC2SPacket.java +++ b/src/main/java/modchest/networking/packet/deathScreenMultiButtonsC2SPacket.java @@ -12,9 +12,9 @@ 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.awt.*; import java.util.Arrays; public class deathScreenMultiButtonsC2SPacket { @@ -28,9 +28,8 @@ public class deathScreenMultiButtonsC2SPacket { 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 " + setAndGet.setMultiSpawnVanilla(player); + 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 @@ -38,14 +37,19 @@ public class deathScreenMultiButtonsC2SPacket { 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 + "! ")); + player.sendMessage((Text.translatable("chat.modchest.multispawn.respawned", num))); REServerMod.LOGGER.info("Respawned Player: " + player.getDisplayName() + "at " + Arrays.toString(setAndGet.getMultiSpawn(player, num))); + setAndGet.setMultiSpawn(player, 6); } 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!")); + if (posXYZ[0] == 77889944) { //Dieser Errorcode bedeutet, dass das Bett zerstoert wurde + player.sendMessage(Text.translatable("chat.modchest.multispawn.beddestroyed")); + } else { + player.sendMessage(Text.translatable("chat.modchest.multispawn.spawnnotset")); + } } - //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 index 4cab0f3..92419bf 100644 --- a/src/main/java/modchest/networking/packet/setNewRespawnsC2SPacket.java +++ b/src/main/java/modchest/networking/packet/setNewRespawnsC2SPacket.java @@ -19,27 +19,27 @@ public class setNewRespawnsC2SPacket { 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)))); + player.sendMessage(Text.translatable("chat.modchest.multispawn.setspawn", "1")); break; case 2: setAndGet.setMultiSpawn(player, 2); - player.sendMessage(Text.of("Respawn #2 gesetzt! " + Arrays.toString(setAndGet.getMultiSpawn(player, 2)))); + player.sendMessage(Text.translatable("chat.modchest.multispawn.setspawn", "2")); break; case 3: setAndGet.setMultiSpawn(player, 3); - player.sendMessage(Text.of("Respawn #3 gesetzt! " + Arrays.toString(setAndGet.getMultiSpawn(player, 3)))); + player.sendMessage(Text.translatable("chat.modchest.multispawn.setspawn", "3")); break; case 4: setAndGet.setMultiSpawn(player, 4); - player.sendMessage(Text.of("Respawn #4 gesetzt! " + Arrays.toString(setAndGet.getMultiSpawn(player, 4)))); + player.sendMessage(Text.translatable("chat.modchest.multispawn.setspawn", "4")); break; case 5: setAndGet.setMultiSpawn(player, 5); - player.sendMessage(Text.of("Respawn #5 gesetzt! " + Arrays.toString(setAndGet.getMultiSpawn(player, 5)))); + player.sendMessage(Text.translatable("chat.modchest.multispawn.setspawn", "5")); break; } } catch (Exception e) { - player.sendMessage(Text.of("Uff! Error beim Speichern! Schaue in die Logs fuer mehr details")); + player.sendMessage(Text.translatable("chat.modchest.multispawn.setspawnerror")); 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 index 6be28b3..2f43ab9 100644 --- a/src/main/java/modchest/util/ServerPlayerEntityInterface.java +++ b/src/main/java/modchest/util/ServerPlayerEntityInterface.java @@ -5,6 +5,6 @@ import net.minecraft.server.network.ServerPlayerEntity; import org.spongepowered.asm.mixin.Unique; public interface ServerPlayerEntityInterface { - int[] getDataSaver(); - void setDataSaver(int[] data); + NbtCompound getDataSaver(); + void setDataSaver(NbtCompound data); } diff --git a/src/main/java/modchest/util/initializer.java b/src/main/java/modchest/util/initializer.java new file mode 100644 index 0000000..6308369 --- /dev/null +++ b/src/main/java/modchest/util/initializer.java @@ -0,0 +1,30 @@ +package modchest.util; + +import modchest.block.entity.modBlockEntities; +import modchest.block.modBlocks; +import modchest.event.playerAfterRespawnEvent; +import modchest.item.modItemGroup; +import modchest.item.modItems; +import modchest.networking.modNetworkingServer; +import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents; + +public class initializer { + public static void itemGroups() { + modItemGroup.modchest(); // Item Gruppe fürs Creative-Inventar wird erstellt; In dieser Gruppe sollen + // dann alle Items und Blöcke dieser Mod angezeigt werden + } + + public static void itemsAndBlocks() { + modItems.setItems(); // die Items werden erstellt + modBlocks.setBlocks(); // Hier werden die Blöcke erstellt + modBlockEntities.registerBlockEntities(); // Die Interaktionsmenüs für die Blöcke werden erstellt + } + + public static void events() { //Events, bei denen custom Code ausgefuehrt wird, werden eingefuehrt + ServerPlayerEvents.AFTER_RESPAWN.register(new playerAfterRespawnEvent()); + } + + public static void networking() { //Identifier unter denen der Server zuhoert werden registriert + modNetworkingServer.registerS2CPackets(); + } +} diff --git a/src/main/java/modchest/util/setAndGetMultiButtonsSpawn.java b/src/main/java/modchest/util/setAndGetMultiButtonsSpawn.java index 10a79bf..bfc08de 100644 --- a/src/main/java/modchest/util/setAndGetMultiButtonsSpawn.java +++ b/src/main/java/modchest/util/setAndGetMultiButtonsSpawn.java @@ -1,63 +1,162 @@ package modchest.util; import modchest.REServerMod; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtElement; 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; 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 - } + ServerPlayerEntityInterface castedPlayer = (ServerPlayerEntityInterface) player; + NbtCompound topNbt = ((ServerPlayerEntityInterface) player).getDataSaver(); //alle daten der mod werden in diesem NBT Gespeichert + if (topNbt.get("multi_sleep") == null) { //die daten fuer multi-sleep werden in dem nbt-tag "multi_sleep" gespeichert, der wiederum um anderen nbt gespeichert wird + topNbt.put("multi_sleep", new NbtCompound()); //sollte dieser nbt-tag nicht existieren, wird ein neuer erstellt } - fullArray[spawn * 3 + 0] = (int) player.getX(); - fullArray[spawn * 3 + 1] = (int) player.getY(); - fullArray[spawn * 3 + 2] = (int) player.getZ(); + NbtCompound subNbt = (NbtCompound) topNbt.get("multi_sleep"); //nbt tag mit allen daten fuer multi-sleep wird geladen + spawn--; //weil der Array mit Slot 0 beginnt, rutscht alles eins auf + int[] fullArray = new int[3]; //ein kleiner zwischenspeicher + + fullArray[0] = (int) player.getX(); + fullArray[1] = (int) player.getY(); + fullArray[2] = (int) player.getZ(); try { - castedPlayer.setDataSaver(fullArray); -} catch (Exception e) { + assert subNbt != null; + subNbt.putIntArray(String.valueOf(spawn), fullArray); //speichert unseren array an der entsprechenden nummer ab + topNbt.put("multi_sleep", subNbt); //speichert den tag unter multi_sleep im top-tag ab + castedPlayer.setDataSaver(topNbt); //speichert den top-tag wieder im spieler ab + } 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)); + player.sendMessage(Text.translatable("chat.modchest.multispawn.spawnnotsaved")); } } 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++) { + ServerPlayerEntityInterface castedPlayer = (ServerPlayerEntityInterface) player; + NbtCompound topNbt = ((ServerPlayerEntityInterface) player).getDataSaver(); + if (topNbt.get("multi_sleep") == null) { + topNbt.put("multi_sleep", new NbtCompound()); + } + NbtCompound subNbt = (NbtCompound) topNbt.get("multi_sleep"); //wie bei setMultiSpawn() + spawn--; //weil der Array mit Slot 0 beginnt, rutscht alles eins auf + int[] fullArray = new int[0]; + if (subNbt != null) { + fullArray = subNbt.getIntArray(String.valueOf(spawn)); //holt sich den ganzen Array, mit allen gespeicherten Spawnpunkten; struktur wird etwas weiter unten erklaert + } + + if (fullArray.length != 3) { //sollte der Array leer oder anderweitig ungueltig sein wird er neu erstellt + int[] tempArray = new int[3]; + for (int i = 0; i < 3; i++) { tempArray[i] = 77889922; //Lueckenfueller; wird in deathScreenMultiButtonsC2SPacket uebrprueft und rausgefiltert } - try { - castedPlayer.setDataSaver(fullArray); - } catch (Exception e) { + try { //wenn wir gerade den Array erstellt haben, weil er ungueltig war, wird er hier in den nbt-tag abgespseichert + subNbt.putIntArray(String.valueOf(spawn), fullArray); + topNbt.put("multi_sleep", subNbt); + castedPlayer.setDataSaver(topNbt); + } 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)); + player.sendMessage(Text.translatable("chat.modchest.multispawn.getable")); } } - 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) { + fullArray = subNbt.getIntArray(String.valueOf(spawn)); //wir laden ihn uns wieder, nur um sicher zu gehen + int[] posXYZ = new int[3]; //zwischenspeicher + try { //schaut, ob wir die daten laden koennen + posXYZ[0] = fullArray[0]; + posXYZ[1] = fullArray[1]; + posXYZ[2] = fullArray[2]; + } catch (Exception e) { //sonst geben wir folgenden Errorcode zurueck posXYZ[0] = 77889933; posXYZ[1] = 77889933; posXYZ[2] = 77889933; } return posXYZ; } + + public synchronized void setMultiSpawnVanilla(ServerPlayerEntity player) { //bevor der Spieler respawnt, speichern wir einmal seinen Vanillaspawn ab, um ihn spaeter wieder darauf zu setzen + BlockPos posAlt = player.getSpawnPointPosition(); //Spawnpunkt der Vanilla-respawn-funktion wird gespeichert + RegistryKey dimAlt = player.getSpawnPointDimension();//Dimension " + float angleAlt = player.getSpawnAngle(); //Blickrichtung " + ServerPlayerEntityInterface castedPlayer = (ServerPlayerEntityInterface) player; + NbtCompound topNbt = ((ServerPlayerEntityInterface) player).getDataSaver(); + if (topNbt.get("multi_sleep") == null) { + topNbt.put("multi_sleep", new NbtCompound()); + } + NbtCompound subNbt = (NbtCompound) topNbt.get("multi_sleep"); //alles in der set-Methode ganz oben erklaert + + try { //sicheerheit, weil hier mal wieder viel zwischen datentypen gewechselt wird + NbtCompound vanillaSpawnData = new NbtCompound(); + int[] location = new int[3]; //spawnpunkt wird in einen Array komprimiert + location[0] = posAlt.getX(); + location[1] = posAlt.getY(); + location[2] = posAlt.getZ(); + vanillaSpawnData.putIntArray("location", location); //und abgespeichert + vanillaSpawnData.putString("dimension", dimAlt.toString()); //dimension wird abgespeichert + vanillaSpawnData.putFloat("angle", angleAlt); //auch die Blickrichtung + vanillaSpawnData.putBoolean("used", false); //wird auf true gesetzt, sobald der Spawnpunkt wieder zurueck gesetzt wurde + + subNbt.put("vanillaSpawnData", vanillaSpawnData); //spawnpunkt wird im sub-nbt gespeichert + topNbt.put("multi_sleep", subNbt); //und im top-nbt + castedPlayer.setDataSaver(topNbt); //um dann im player gespeichert zu werden + } catch (Exception e) { + REServerMod.LOGGER.info("Sorry! Error when saving Spawnpoint! Exception: " + e); + } + } + + public synchronized NbtCompound getMultiSpawnVanilla(ServerPlayerEntity player) { + ServerPlayerEntityInterface castedPlayer = (ServerPlayerEntityInterface) player; + NbtCompound topNbt = ((ServerPlayerEntityInterface) player).getDataSaver(); + if (topNbt.get("multi_sleep") == null) { + topNbt.put("multi_sleep", new NbtCompound()); + } + NbtCompound subNbt = (NbtCompound) topNbt.get("multi_sleep"); //steht alles wieder in der ersten methode + + if (subNbt != null) { + NbtCompound nbt = (NbtCompound) subNbt.get("vanillaSpawnData"); //hollt sich die daten + assert nbt != null; + if (!nbt.getBoolean("used")) { + nbt.putBoolean("used", true); //setzt den verwendet boolean auf true; nicht ganz perfekt, sollte ein fehler beim speichern auftreten wird es nicht nochmal versucht, speichert aber massiv an coding und leistung + subNbt.put("vanillaSpawnData", nbt); + topNbt.put("multi_sleep", subNbt); //muss den bearbeiteten nbt wieder abgespeichert (nur der boolean wurde ueberschrieben) + castedPlayer.setDataSaver(topNbt); + return nbt; //gibt den nbt-tag an die aufrufende Methode + } else { + return null; + } + } else { + return null; + } + } + + public synchronized void setMultiSpawnBlank(ServerPlayerEntity player, int spawn) { //wird aufgerufen wenn das Bett dieses Spielers zerstoert wurde + ServerPlayerEntityInterface castedPlayer = (ServerPlayerEntityInterface) player; + NbtCompound topNbt = ((ServerPlayerEntityInterface) player).getDataSaver(); + if (topNbt.get("multi_sleep") == null) { + topNbt.put("multi_sleep", new NbtCompound()); + } + NbtCompound subNbt = (NbtCompound) topNbt.get("multi_sleep"); //alles wieder wie in der ersten Methode; + spawn--; //weil der Array mit Slot 0 beginnt, rutscht alles eins auf + int[] fullArray = new int[0]; + if (subNbt != null) { + fullArray = subNbt.getIntArray(String.valueOf(spawn)); //holt sich den ganzen Array, mit allen gespeicherten Spawnpunkten; struktur wird etwas weiter unten erklaert + } + + fullArray[0] = 77889944; //Errorcode der in deathScreenMultiButtonsC2SPacket als zerstoertes Bett rausgefiltert wird + fullArray[1] = 77889944; + fullArray[2] = 77889944; + + try { + subNbt.putIntArray(String.valueOf(spawn), fullArray); //wird abgespeichert + topNbt.put("multi_sleep", subNbt); + castedPlayer.setDataSaver(topNbt); + } catch (Exception e) { + REServerMod.LOGGER.info("Sorry! Error when saving Spawnpoint! Exception: " + e); + } + } } diff --git a/src/main/resources/assets/modchest/lang/de_de.json b/src/main/resources/assets/modchest/lang/de_de.json index 0a9d8e2..4f2ddfd 100644 --- a/src/main/resources/assets/modchest/lang/de_de.json +++ b/src/main/resources/assets/modchest/lang/de_de.json @@ -2,5 +2,13 @@ "item.modchest.shipblock": "Schiffsblock", "item.modchest.pirates_coin": "OP Piraten ding zum Testen", "block.modchest.steering_wheel": "Lenkrad", - "itemGroup.modchest.itemlist1": "Malte's Mod" + "itemGroup.modchest.itemlist1": "Malte's Mod", + + "chat.modchest.multispawn.beddestroyed": "Scheint so, als wäre das Bett zerstört worden!", + "chat.modchest.multispawn.respawned": "Respawne bei #%s", + "chat.modchest.multispawn.setspawn": "Nutze spawn #%s", + "chat.modchest.multispawn.setspawnerror": "Fehler beim speichern!", + "chat.modchest.multispawn.spawnnotset": "Es scheint so, als wäre dieser Spawn nicht gesetzt!", + "chat.modchest.multispawn.spawnnotsaved": "Fehler beim Versuch, diesen Spawn zu speichern!", + "chat.modchest.multispawn.getable": "Diese spawn location konnte nicht geladen werden!" } \ No newline at end of file diff --git a/src/main/resources/assets/modchest/lang/en_pt.json b/src/main/resources/assets/modchest/lang/en_pt.json index 1b36e5b..46ba5c9 100644 --- a/src/main/resources/assets/modchest/lang/en_pt.json +++ b/src/main/resources/assets/modchest/lang/en_pt.json @@ -2,5 +2,13 @@ "item.modchest.shipblock": "Hanno, änder die Sprache!", "item.modchest.pirates_coin": "Ya coin for tha pirrrrrates!", "block.modchest.steering_wheel": "Ne, du kriegst keine hilfreichen Angaben mit der Sprache!", - "itemGroup.modchest.itemlist1": "Änder doch endlich die Sprache..." + "itemGroup.modchest.itemlist1": "Änder doch endlich die Sprache...", + + "chat.modchest.multispawn.beddestroyed": "Sorry, mate! Looks like that cap'n doesn't like you", + "chat.modchest.multispawn.respawned": "Prepare to board some ship, lads!", + "chat.modchest.multispawn.setspawn": "Boarded random ship!", + "chat.modchest.multispawn.setspawnerror": "oh, that hammock is full!", + "chat.modchest.multispawn.spawnnotset": "No hammocks a'board!", + "chat.modchest.multispawn.spawnnotsaved": "Couldn't remember that ship...", + "chat.modchest.multispawn.getable": "Na ship could be found!" } \ No newline at end of file diff --git a/src/main/resources/assets/modchest/lang/en_us.json b/src/main/resources/assets/modchest/lang/en_us.json index 678dc00..ee5426e 100644 --- a/src/main/resources/assets/modchest/lang/en_us.json +++ b/src/main/resources/assets/modchest/lang/en_us.json @@ -2,5 +2,13 @@ "item.modchest.shipblock": "Shipblock", "item.modchest.pirates_coin": "Pirate's Coin", "block.modchest.steering_wheel": "Steering Wheel", - "itemGroup.modchest.itemlist1": "Theo macht unfug" + "itemGroup.modchest.itemlist1": "new blocks", + + "chat.modchest.multispawn.beddestroyed": "Oh shit! Looks like that bed got destroyed!", + "chat.modchest.multispawn.respawned": "Respawn #%s used", + "chat.modchest.multispawn.setspawn": "Set spawn #%s", + "chat.modchest.multispawn.setspawnerror": "Sorry! Error when setting that spawn!", + "chat.modchest.multispawn.spawnnotset": "Sorry! Looks like that Spawnpoint isn't set yet!", + "chat.modchest.multispawn.spawnnotsaved": "Sorry! Error when trying to save your spawn!", + "chat.modchest.multispawn.getable": "Sorry! Couldn't get your spawnlocation!" } \ No newline at end of file diff --git a/src/main/resources/reservermod.mixins.json b/src/main/resources/reservermod.mixins.json index 91ec238..62856ee 100644 --- a/src/main/resources/reservermod.mixins.json +++ b/src/main/resources/reservermod.mixins.json @@ -3,7 +3,8 @@ "package": "modchest.mixin", "compatibilityLevel": "JAVA_17", "mixins": [ - "ServerPlayerEntityMixin" + "ServerPlayerEntityMixin", + "bedBlock" ], "injectors": { "defaultRequire": 1