A Minecraft server-side mod that adds various teleportation related commands
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Doing more java stuffz, very wip, it will brick your save!

Improved how I use classes and added alot of get & set methods to make
it more like normal java lol. Finished storing the deathLocation in memory. Storage seems to currently be fully bricked tho, gonna need to look into that.

+226 -112
+3 -2
CHANGELOG.md
··· 6 6 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 7 8 8 ### [W.I.P] 9 - - Storage is loaded in memory instead of reading it again and again, Improves speed and IO usage 10 - - Made it so the DeathLocation is only kept in memory (WIP) 9 + - Storage is loaded in memory instead of reading it again and again, Improves speed and IO usage. (W.I.P) 10 + - Adding comments to alot of code (W.I.P) 11 + - Made it so the DeathLocation is only kept in memory 11 12 - Improved the Storage classes and functions (I'm doing proper java, yipie) 12 13 13 14 ### [v1.2.2]
+8 -27
common/src/main/java/dev/mrsnowy/teleport_commands/TeleportCommands.java
··· 4 4 import com.mojang.datafixers.util.Pair; 5 5 import dev.mrsnowy.teleport_commands.storage.StorageManager; 6 6 import dev.mrsnowy.teleport_commands.commands.*; 7 + import dev.mrsnowy.teleport_commands.storage.backListStorage; 7 8 import net.minecraft.commands.Commands; 8 9 import net.minecraft.server.MinecraftServer; 9 10 import net.minecraft.server.level.ServerPlayer; ··· 17 18 import java.nio.file.Path; 18 19 import java.nio.file.Paths; 19 20 import java.nio.file.StandardOpenOption; 21 + 20 22 import net.minecraft.core.BlockPos; 21 23 22 24 import static dev.mrsnowy.teleport_commands.storage.StorageManager.*; ··· 57 59 58 60 // Runs when the playerDeath mixin calls it, updates the /back command position 59 61 public static void onPlayerDeath(ServerPlayer player) { 60 - try { 61 - BlockPos pos = new BlockPos(player.getBlockX(), player.getBlockY(), player.getBlockZ()); 62 - 63 - Pair<StorageManager.StorageClass, StorageManager.StorageClass.Player> storages = GetPlayerStorage(player.getStringUUID()); 64 - 65 - StorageManager.StorageClass.Player playerStorage = storages.getSecond(); 66 - 67 - playerStorage.deathLocation.x = pos.getX(); 68 - playerStorage.deathLocation.y = pos.getY(); 69 - playerStorage.deathLocation.z = pos.getZ(); 70 - playerStorage.deathLocation.world = player.serverLevel().dimension().location().toString(); 62 + BlockPos pos = new BlockPos(player.getBlockX(), player.getBlockY(), player.getBlockZ()); 63 + String world = player.serverLevel().dimension().location().toString(); 64 + String uuid = player.getStringUUID(); 71 65 72 - StorageSaver(); 73 - 74 - } catch (Exception e) { 75 - LOGGER.error("Error while saving the player death location! => ", e); 76 - } 66 + backListStorage.backList backList = backListStorage.backList; 67 + backList.setDeathLocation(uuid, pos, world); 77 68 } 78 69 79 70 // private static StorageManager.StorageClass loadStorage() throws Exception { ··· 83 74 // String jsonContent = Files.readString(STORAGE_FILE); 84 75 // Gson gson = new GsonBuilder().create(); 85 76 // 86 - //} 77 + // } 87 78 88 79 // cleans and updates Storage to the newest "version". This is painful 89 80 private static StorageClass storageValidator() { ··· 155 146 String DefaultHome = player.has("DefaultHome") 156 147 ? player.get("DefaultHome").getAsString() : ""; 157 148 158 - 159 - // Clean death location after server restart 160 - JsonObject deathLocation = new JsonObject(); 161 - 162 - deathLocation.addProperty("x", 0); 163 - deathLocation.addProperty("y", 0); 164 - deathLocation.addProperty("z", 0); 165 - deathLocation.addProperty("world", ""); 166 - 167 149 JsonArray homes = new JsonArray(); 168 150 169 151 if (player.has("Homes") && player.get("Homes").isJsonArray() ) { ··· 226 208 227 209 newPlayer.addProperty("UUID", UUID); 228 210 newPlayer.addProperty("DefaultHome", DefaultHome); 229 - newPlayer.add("deathLocationClass", deathLocation); 230 211 newPlayer.add("Homes", homes); 231 212 232 213 newPlayersArray.add(newPlayer);
+12 -22
common/src/main/java/dev/mrsnowy/teleport_commands/commands/back.java
··· 6 6 7 7 import java.util.*; 8 8 9 + import dev.mrsnowy.teleport_commands.storage.backListStorage; 9 10 import dev.mrsnowy.teleport_commands.utils.tools; 10 11 import net.minecraft.ChatFormatting; 11 12 import net.minecraft.commands.Commands; ··· 19 20 import static net.minecraft.commands.Commands.argument; 20 21 21 22 public class back { 22 - public static final ArrayList<deathLocationClass> backList = new ArrayList<>(); 23 - 24 - public static class deathLocationClass { 25 - final public String UUID; 26 - final public BlockPos pos; 27 - final public String world; 28 - 29 - public deathLocationClass(String uuid, BlockPos pos, String world) { 30 - this.UUID = uuid; 31 - this.pos = pos; 32 - this.world = world; 33 - backList.add(this); 34 - } 35 - } 36 23 37 24 public static void register(Commands commandManager) { 38 25 ··· 73 60 74 61 private static void ToDeathLocation(ServerPlayer player, boolean safetyDisabled) { 75 62 76 - Optional<deathLocationClass> OptionalDeathLocation = backList.stream() 77 - .filter( deathLocation -> Objects.equals( deathLocation.UUID, player.getStringUUID() )) 78 - .findFirst(); 63 + backListStorage.backList backList = backListStorage.backList; 79 64 80 - if (OptionalDeathLocation.isEmpty()) { 81 - player.displayClientMessage(getTranslatedText("commands.teleport_commands.common.noLocation", player).withStyle(ChatFormatting.RED), true); 65 + // get the deathLocation 66 + Optional<backListStorage.deathLocationClass> optionalDeathLocation = backList.getDeathLocation( player.getStringUUID() ); 67 + if (optionalDeathLocation.isEmpty()) { 68 + player.displayClientMessage(getTranslatedText("commands.teleport_commands.common.noLocation", player) 69 + .withStyle(ChatFormatting.RED), true); 82 70 return; 83 71 } 84 72 85 - deathLocationClass deathLocation = OptionalDeathLocation.get(); 73 + backListStorage.deathLocationClass deathLocation = optionalDeathLocation.get(); 86 74 75 + // get the world 87 76 Optional<ServerLevel> OptionalWorld = tools.getWorld( deathLocation.world ); 88 77 if (OptionalWorld.isEmpty()) { 89 - player.displayClientMessage(getTranslatedText("commands.teleport_commands.common.noLocation", player).withStyle(ChatFormatting.RED), true); 78 + player.displayClientMessage(getTranslatedText("commands.teleport_commands.common.noLocation", player) 79 + .withStyle(ChatFormatting.RED), true); 90 80 return; 91 81 } 92 82 93 83 ServerLevel world = OptionalWorld.get(); 94 84 95 - // check if the death location isn't safe and that safety isn't enabled 85 + // if safety is enabled, check if the death location is safe. 96 86 if (!safetyDisabled) { 97 87 98 88 Pair<Integer, Optional<Vec3>> teleportData = teleportSafetyChecker(deathLocation.pos, world, player);
+137 -49
common/src/main/java/dev/mrsnowy/teleport_commands/storage/StorageManager.java
··· 2 2 3 3 import com.google.gson.Gson; 4 4 import com.google.gson.GsonBuilder; 5 - import com.mojang.datafixers.util.Pair; 6 5 import dev.mrsnowy.teleport_commands.TeleportCommands; 7 6 import net.minecraft.core.BlockPos; 8 7 ··· 48 47 } 49 48 } 50 49 51 - public static StorageClass.Player PlayerAdd(String UUID) { 52 - 53 - // try to find an exising storage for this player 54 - Optional<StorageClass.Player> playerStorage = STORAGE.Players.stream() 55 - .filter(player -> Objects.equals(UUID, player.UUID)) 56 - .findFirst(); 57 - 58 - if (playerStorage.isEmpty()) { 59 - StorageClass.Player newPlayer = new StorageClass.Player(UUID); // TODO! verify that it creates the player proper 60 - 61 - List<StorageClass.Player> playerList = STORAGE.Players; 62 - playerList.add(newPlayer); 63 - 64 - // StorageSaver(); // no need to save since no data is actually set yet! 65 - TeleportCommands.LOGGER.info("Player '{}' added successfully in storage!", UUID); 66 - return newPlayer; 67 - } else { 68 - TeleportCommands.LOGGER.info("Player '{}' already exists!", UUID); 69 - return playerStorage.get(); 70 - } 71 - } 50 + // public static StorageClass.Player PlayerAdd(String UUID) { 51 + // 52 + // // try to find an exising storage for this player 53 + // Optional<StorageClass.Player> playerStorage = STORAGE.Players.stream() 54 + // .filter(player -> Objects.equals(UUID, player.UUID)) 55 + // .findFirst(); 56 + // 57 + // if (playerStorage.isEmpty()) { 58 + // StorageClass.Player newPlayer = new StorageClass.Player(UUID); // TODO! verify that it creates the player proper 59 + // 60 + // List<StorageClass.Player> playerList = STORAGE.Players; 61 + // playerList.add(newPlayer); 62 + // 63 + //// StorageSaver(); // no need to save since no data is actually set yet! 64 + // TeleportCommands.LOGGER.info("Player '{}' added successfully in storage!", UUID); 65 + // return newPlayer; 66 + // } else { 67 + // TeleportCommands.LOGGER.info("Player '{}' already exists!", UUID); 68 + // return playerStorage.get(); 69 + // } 70 + // } 72 71 73 72 public static void StorageSaver() throws Exception { 74 73 Gson gson = new GsonBuilder().create(); 75 74 byte[] json = gson.toJson( STORAGE ).getBytes(); 75 + 76 + TeleportCommands.LOGGER.info(STORAGE.toString()); 76 77 77 78 Files.write(STORAGE_FILE, json, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING); 78 79 } 79 80 80 - public static Pair<StorageClass, List<StorageClass.NamedLocation>> getWarpStorage() { 81 - return new Pair<>(STORAGE, STORAGE.Warps); 82 - } 83 - 84 - public static Pair<StorageClass, StorageClass.Player> GetPlayerStorage(String UUID) { 81 + // public static Pair<StorageClass, List<StorageClass.NamedLocation>> getWarpStorage() { 82 + // return new Pair<>(STORAGE, STORAGE.Warps); 83 + // } 85 84 86 - // try to find an exising storage for this player 87 - Optional<StorageClass.Player> playerStorage = STORAGE.Players.stream() 88 - .filter(player -> Objects.equals(UUID, player.UUID)) 89 - .findFirst(); 90 - 91 - if (playerStorage.isEmpty()) { 92 - StorageClass.Player player = PlayerAdd(UUID); // create a new player 93 - 94 - return new Pair<>(STORAGE, player); 95 - } 96 - 97 - return new Pair<>(STORAGE, playerStorage.get()); 98 - } 85 + // public static Pair<StorageClass, StorageClass.Player> GetPlayerStorage(String UUID) { 86 + // 87 + // // try to find an exising storage for this player 88 + // Optional<StorageClass.Player> playerStorage = STORAGE.Players.stream() 89 + // .filter(player -> Objects.equals(UUID, player.UUID)) 90 + // .findFirst(); 91 + // 92 + // if (playerStorage.isEmpty()) { 93 + // StorageClass.Player player = PlayerAdd(UUID); // create a new player 94 + // 95 + // return new Pair<>(STORAGE, player); 96 + // } 97 + // 98 + // return new Pair<>(STORAGE, playerStorage.get()); 99 + // } 99 100 100 101 101 102 public static class StorageClass { 102 - public static List<NamedLocation> Warps = new ArrayList<>(); 103 - public static List<Player> Players = new ArrayList<>(); 103 + public static warpList Warps = new warpList(); 104 + public static playerList Players = new playerList(); 104 105 105 106 public static class NamedLocation { 106 107 public String name; ··· 118 119 } 119 120 } 120 121 121 - public static class Location { 122 - public int x = 0; 123 - public int y = 0; 124 - public int z = 0; 125 - public String world = ""; 122 + public static class warpList { 123 + private final ArrayList<NamedLocation> warpList = new ArrayList<>(); 124 + 125 + // filters the warpList and finds the one with the name (if there is one) 126 + public Optional<NamedLocation> getWarp(String name) { 127 + return warpList.stream() 128 + .filter( warp -> Objects.equals( warp.name, name )) 129 + .findFirst(); 130 + } 131 + 132 + // returns all warps 133 + public ArrayList<NamedLocation> getWarps() { 134 + return warpList; 135 + } 136 + 137 + // creates a new warp, if there already is a warp it will update the existing one 138 + public void setWarp(String name, BlockPos pos, String world) throws Exception { 139 + Optional<NamedLocation> OptionalWarp = getWarp(name); 140 + 141 + if (OptionalWarp.isEmpty()) { 142 + // create a new warp 143 + NamedLocation warp = new NamedLocation(name, pos, world); 144 + warpList.add(warp); 145 + StorageSaver(); 146 + } else { 147 + // modify existing warp 148 + NamedLocation warp = OptionalWarp.get(); 149 + warp.name = name; 150 + } 151 + } 126 152 } 127 153 154 + public static class playerList { 155 + private final ArrayList<Player> playerList = new ArrayList<>(); 156 + 157 + // filters the playerList and finds the one with the uuid (if there is one) 158 + public Optional<Player> getPlayer(String uuid) { 159 + return playerList.stream() 160 + .filter( player -> Objects.equals( player.UUID, uuid )) 161 + .findFirst(); 162 + } 163 + 164 + // creates a new player, if there already is a player it will return the existing one 165 + public Player addPlayer(String uuid, BlockPos pos, String world) { 166 + Optional<Player> OptionalPlayer = getPlayer(uuid); 167 + 168 + if (OptionalPlayer.isEmpty()) { 169 + // create new player 170 + Player player = new Player(uuid); 171 + playerList.add(player); 172 + TeleportCommands.LOGGER.info("Player '{}' added successfully in storage!", uuid); 173 + 174 + return player; 175 + } else { 176 + // return existing player 177 + TeleportCommands.LOGGER.info("Player '{}' already exists!", uuid); 178 + return OptionalPlayer.get(); 179 + } 180 + } 181 + } 182 + 183 + 128 184 public static class Player { 129 185 public final String UUID; 130 186 public String DefaultHome = ""; 131 - public Location deathLocation; // todo! deprecate 132 - public List<NamedLocation> Homes = new ArrayList<>(); 187 + public homeList Homes = new homeList(); 133 188 134 189 public Player(String uuid) { 135 190 this.UUID = uuid; 191 + } 192 + 193 + public static class homeList { 194 + private final List<NamedLocation> Homes = new ArrayList<>(); 195 + 196 + // filters the Homes and finds the one with the name (if there is one) 197 + public Optional<NamedLocation> getHome(String name) { 198 + return Homes.stream() 199 + .filter( home -> Objects.equals( home.name, name )) 200 + .findFirst(); 201 + } 202 + 203 + // returns all homes 204 + public List<NamedLocation> getHomes() { 205 + return Homes; 206 + } 207 + 208 + // creates a new home, if there already is a home it will update the existing one 209 + public void setHome(String name, BlockPos pos, String world) throws Exception { 210 + Optional<NamedLocation> OptionalHome = getHome(name); 211 + 212 + if (OptionalHome.isEmpty()) { 213 + NamedLocation home = new NamedLocation(name, pos, world); 214 + 215 + Homes.add(home); 216 + StorageSaver(); 217 + } else { 218 + NamedLocation home = OptionalHome.get(); 219 + 220 + home.name = name; 221 + StorageSaver(); 222 + } 223 + } 136 224 } 137 225 } 138 226 }
+51
common/src/main/java/dev/mrsnowy/teleport_commands/storage/backListStorage.java
··· 1 + package dev.mrsnowy.teleport_commands.storage; 2 + 3 + import net.minecraft.core.BlockPos; 4 + 5 + import java.util.ArrayList; 6 + import java.util.Objects; 7 + import java.util.Optional; 8 + 9 + public class backListStorage { 10 + public static final backList backList = new backList(); 11 + 12 + public static class backList { 13 + private final ArrayList<deathLocationClass> backList = new ArrayList<>(); 14 + 15 + // filters the deathLocationList and finds the one with the matching player uuid (if there is one) 16 + public Optional<deathLocationClass> getDeathLocation(String uuid) { 17 + return backList.stream() 18 + .filter( deathLocation -> Objects.equals( deathLocation.UUID, uuid )) 19 + .findFirst(); 20 + } 21 + 22 + // updates the deathLocation of a player, if there is no existing entry it will create a new deathLocation. 23 + public void setDeathLocation(String uuid, BlockPos pos, String world) { 24 + Optional<deathLocationClass> OptionalDeathLocation = getDeathLocation(uuid); 25 + 26 + if (OptionalDeathLocation.isEmpty()) { 27 + // create a new deathLocation 28 + deathLocationClass deathLocation = new deathLocationClass(uuid, pos, world); 29 + backList.add(deathLocation); 30 + } else { 31 + // modify existing deathLocation 32 + deathLocationClass deathLocation = OptionalDeathLocation.get(); 33 + 34 + deathLocation.pos = pos; 35 + deathLocation.world = world; 36 + } 37 + } 38 + } 39 + 40 + public static class deathLocationClass { 41 + public String UUID; 42 + public BlockPos pos; 43 + public String world; 44 + 45 + private deathLocationClass(String uuid, BlockPos pos, String world) { 46 + this.UUID = uuid; 47 + this.pos = pos; 48 + this.world = world; 49 + } 50 + } 51 + }
+15 -12
common/src/main/java/dev/mrsnowy/teleport_commands/utils/tools.java
··· 4 4 import com.mojang.datafixers.util.Pair; 5 5 import dev.mrsnowy.teleport_commands.TeleportCommands; 6 6 7 - 8 7 import java.io.*; 9 8 import java.nio.charset.StandardCharsets; 10 9 import java.util.*; ··· 30 29 private static final Set<String> unsafeCollisionFreeBlocks = Set.of("block.minecraft.lava", "block.minecraft.flowing_lava", "block.minecraft.end_portal", "block.minecraft.end_gateway","block.minecraft.fire", "block.minecraft.soul_fire", "block.minecraft.powder_snow", "block.minecraft.nether_portal"); 31 30 32 31 public static void Teleporter(ServerPlayer player, ServerLevel world, Vec3 coords) { 33 - // before teleportation effects 32 + // teleportation effects & sounds before teleporting 34 33 world.sendParticles(ParticleTypes.SNOWFLAKE, player.getX(), player.getY() + 1, player.getZ(), 20, 0.0D, 0.0D, 0.0D, 0.01); 35 34 world.sendParticles(ParticleTypes.WHITE_SMOKE, player.getX(), player.getY(), player.getZ(), 15, 0.0D, 1.0D, 0.0D, 0.03); 36 35 world.playSound(null, player.blockPosition(), SoundEvent.createVariableRangeEvent(ENDERMAN_TELEPORT.location()), SoundSource.PLAYERS, 0.4f, 1.0f); 37 36 38 - var flying = player.getAbilities().flying; 37 + // check if the player is currently flying 38 + boolean flying = player.getAbilities().flying; 39 39 40 40 // teleport! 41 41 player.teleportTo(world, coords.x, coords.y, coords.z, Set.of(), player.getYRot(), player.getXRot(), false); ··· 46 46 player.onUpdateAbilities(); 47 47 } 48 48 49 - 49 + // teleportation sound after teleport 50 50 world.playSound(null, player.blockPosition(), SoundEvent.createVariableRangeEvent(ENDERMAN_TELEPORT.location()), SoundSource.PLAYERS, 0.4f, 1.0f); 51 - Timer timer = new Timer(); 52 51 53 52 // delay visual effects so the player can see it when switching dimensions 53 + Timer timer = new Timer(); 54 54 timer.schedule( 55 55 new TimerTask() { 56 56 @Override ··· 58 58 world.sendParticles(ParticleTypes.SNOWFLAKE, player.getX(), player.getY() , player.getZ(), 20, 0.0D, 1.0D, 0.0D, 0.01); 59 59 world.sendParticles(ParticleTypes.WHITE_SMOKE, player.getX(), player.getY(), player.getZ(), 15, 0.0D, 0.0D, 0.0D, 0.03); 60 60 } 61 - }, 100 // hopefully good, ~ 2 ticks 61 + }, 100 // hopefully a good delay, ~ 2 ticks 62 62 ); 63 63 } 64 64 65 - 65 + // checks a 7x7x7 location around the player in order to find a safe place to teleport them to. 66 66 public static Pair<Integer, Optional<Vec3>> teleportSafetyChecker(BlockPos blockPos, ServerLevel world, ServerPlayer player) { 67 67 int row = 1; 68 68 int rows = 3; ··· 70 70 BlockPos playerBlockPos = new BlockPos(player.getBlockX(), player.getBlockY(), player.getBlockZ()); 71 71 int playerX = blockPos.getX(); 72 72 int playerY = blockPos.getY(); 73 - int playerZ= blockPos.getZ(); 73 + int playerZ = blockPos.getZ(); 74 74 75 75 // find a safe location in an x row radius 76 76 if (isBlockPosUnsafe(blockPos, world)) { ··· 126 126 } 127 127 128 128 129 - // Gets the translated text for each player based on their language, this is fully server side and actually works (UNLIKE MOJANG'S TRANSLATED KEY'S WHICH ARE CLIENT SIDE) (I'm not mad, I swear) 129 + // Gets the translated text for each player based on their language, this is fully server side and actually works (UNLIKE MOJANG'S TRANSLATED KEY'S WHICH ARE CLIENT SIDE) (I'm not mad, I swear!) 130 130 public static MutableComponent getTranslatedText(String key, ServerPlayer player, MutableComponent... args) { 131 131 String language = player.clientInformation().language().toLowerCase(); 132 132 String regex = "%(\\d+)%"; ··· 197 197 } 198 198 } 199 199 200 - 200 + // checks if a bock position is unsafe, used by the teleportSafetyChecker. 201 201 private static boolean isBlockPosUnsafe(BlockPos bottomPlayer, ServerLevel world) { 202 202 203 + // get the block below the player 203 204 BlockPos belowPlayer = new BlockPos(bottomPlayer.getX(), bottomPlayer.getY() -1, bottomPlayer.getZ()); // below the player 204 205 String belowPlayerId = world.getBlockState(belowPlayer).getBlock().getDescriptionId(); // below the player 205 206 207 + // get the bottom of the player 206 208 String BottomPlayerId = world.getBlockState(bottomPlayer).getBlock().getDescriptionId(); // bottom of player 207 209 210 + // get the top of the player 208 211 BlockPos TopPlayer = new BlockPos(bottomPlayer.getX(), bottomPlayer.getY() + 1, bottomPlayer.getZ()); // top of player 209 212 String TopPlayerId = world.getBlockState(TopPlayer).getBlock().getDescriptionId(); // top of player 210 213 211 214 212 - // check if the death location isn't safe 215 + // check if the block position isn't safe 213 216 if ((belowPlayerId.equals("block.minecraft.water") || !world.getBlockState(belowPlayer).getCollisionShape(world, belowPlayer).isEmpty()) // check if the player is going to fall on teleport 214 - && (world.getBlockState(bottomPlayer).getCollisionShape(world, bottomPlayer).isEmpty() && !unsafeCollisionFreeBlocks.contains(BottomPlayerId)) // check if it is a collision free block, that isn't dangerous 217 + && (world.getBlockState(bottomPlayer).getCollisionShape(world, bottomPlayer).isEmpty() && !unsafeCollisionFreeBlocks.contains(BottomPlayerId)) // check if it is a collision free block that isn't dangerous 215 218 && (!unsafeCollisionFreeBlocks.contains(TopPlayerId))) // check if it is a dangerous collision free block, if it is solid then the player crawls 216 219 { 217 220 return false; // it's safe