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

bump, wip

MrSnowy c5e3f4a3 5b11df65

+101 -65
+23 -19
common/src/main/java/dev/mrsnowy/teleport_commands/TeleportCommands.java
··· 1 1 package dev.mrsnowy.teleport_commands; 2 2 3 - import com.google.gson.*; 4 3 import com.mojang.brigadier.CommandDispatcher; 5 4 import dev.mrsnowy.teleport_commands.storage.StorageManager; 6 5 import dev.mrsnowy.teleport_commands.commands.*; 7 6 import dev.mrsnowy.teleport_commands.storage.DeathLocationStorage; 8 7 import dev.mrsnowy.teleport_commands.storage.ConfigManager; 8 + import dev.mrsnowy.teleport_commands.utils.tools; 9 9 import net.minecraft.commands.CommandSourceStack; 10 10 import net.minecraft.server.MinecraftServer; 11 11 import net.minecraft.server.level.ServerPlayer; 12 12 import net.minecraft.world.level.storage.LevelResource; 13 13 import net.minecraft.core.BlockPos; 14 - import java.io.*; 14 + 15 15 import java.nio.file.Path; 16 16 import java.nio.file.Paths; 17 17 18 18 public class TeleportCommands { 19 - public static String MOD_LOADER; 20 - public static Path SAVE_DIR; 21 - public static Path CONFIG_DIR; 22 - public static MinecraftServer SERVER; 23 - 19 + public String modLoader; 20 + public Path saveDir; 21 + public Path configDir; 22 + public MinecraftServer server; 23 + public StorageManager storageManager; 24 + public ConfigManager config; 25 + public DeathLocationStorage deathLocationStorage; 26 + public tools tools; 24 27 25 28 // Gets ran when the server starts, initializes the mod :3 26 - public static void initializeMod(MinecraftServer server) { 27 - Constants.LOGGER.info("Initializing Teleport Commands (V{})! Hello {}!", Constants.VERSION, MOD_LOADER); 29 + public void initializeMod(MinecraftServer server) { 30 + Constants.LOGGER.info("Initializing Teleport Commands (V{})! Hello {}!", Constants.VERSION, modLoader); 28 31 29 - SAVE_DIR = Path.of(String.valueOf(server.getWorldPath(LevelResource.ROOT))); 30 - CONFIG_DIR = Paths.get(System.getProperty("user.dir")).resolve("config"); // Construct the game directory path 31 - SERVER = server; 32 + saveDir = Path.of(String.valueOf(server.getWorldPath(LevelResource.ROOT))); 33 + configDir = Paths.get(System.getProperty("user.dir")).resolve("config"); 34 + this.server = server; 35 + this.tools = new tools(); 36 + this.storageManager = new StorageManager(); 37 + this.config = new ConfigManager(); 32 38 33 - StorageManager.StorageInit(); // Initialize the storage file 34 - ConfigManager.ConfigInit(); 35 - DeathLocationStorage.clearDeathLocations(); // Clear data of death locations. 39 + deathLocationStorage = new DeathLocationStorage(); 36 40 } 37 41 38 42 // initialize commands, also allows me to easily disable any when there is a config 39 - public static void registerCommands(CommandDispatcher<CommandSourceStack> dispatcher) { 40 - back.register(dispatcher); 43 + public void registerCommands(CommandDispatcher<CommandSourceStack> dispatcher) { 44 + new back(dispatcher, this); 41 45 home.register(dispatcher); 42 46 tpa.register(dispatcher); 43 47 warp.register(dispatcher); ··· 46 50 } 47 51 48 52 // Runs when the playerDeath mixin calls it, updates the /back command position 49 - public static void onPlayerDeath(ServerPlayer player) { 53 + public void onPlayerDeath(ServerPlayer player) { 50 54 BlockPos pos = new BlockPos(player.getBlockX(), player.getBlockY(), player.getBlockZ()); 51 55 String world = player.serverLevel().dimension().location().toString(); 52 56 String uuid = player.getStringUUID(); 53 57 54 - DeathLocationStorage.setDeathLocation(uuid, pos, world); 58 + this.deathLocationStorage.setDeathLocation(uuid, pos, world); 55 59 } 56 60 }
+7 -4
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.TeleportCommands; 9 10 import dev.mrsnowy.teleport_commands.storage.DeathLocationStorage; 10 11 import dev.mrsnowy.teleport_commands.common.DeathLocation; 11 12 import dev.mrsnowy.teleport_commands.utils.tools; ··· 23 24 import static net.minecraft.commands.Commands.argument; 24 25 25 26 public class back { 27 + TeleportCommands teleportCommands; 26 28 27 - public static void register(CommandDispatcher<CommandSourceStack> commandDispatcher) { 29 + public back(CommandDispatcher<CommandSourceStack> commandDispatcher, TeleportCommands teleportCommands) { 30 + this.teleportCommands = teleportCommands; 28 31 29 32 commandDispatcher.register(Commands.literal("back") 30 33 .requires(source -> source.getPlayer() != null) ··· 64 67 // ----- 65 68 66 69 // Gets the DeathLocation of the player and teleports the player to it 67 - private static void ToDeathLocation(ServerPlayer player, boolean safetyDisabled) throws Exception { 68 - DeathLocation deathLocation = DeathLocationStorage 70 + private void ToDeathLocation(ServerPlayer player, boolean safetyDisabled) throws Exception { 71 + DeathLocation deathLocation = teleportCommands.deathLocationStorage 69 72 .getDeathLocation(player.getStringUUID()) 70 73 .orElse(null); 71 74 ··· 132 135 Vec3 teleportPos = new Vec3(teleportBlockPos.getX() + 0.5, teleportBlockPos.getY(), teleportBlockPos.getZ() + 0.5); 133 136 134 137 player.displayClientMessage(getTranslatedText("commands.teleport_commands.back.go", player), true); 135 - tools.Teleporter(player, deathLocationWorld, teleportPos); 138 + teleportCommands.tools.Teleporter(player, deathLocationWorld, teleportPos); 136 139 } 137 140 } 138 141 }
+1 -1
common/src/main/java/dev/mrsnowy/teleport_commands/commands/worldspawn.java
··· 62 62 63 63 private static void toWorldSpawn(ServerPlayer player, boolean safetyDisabled) throws NullPointerException { 64 64 // todo! make the dimension customizable 65 - ServerLevel world = TeleportCommands.SERVER.getLevel(OVERWORLD); 65 + ServerLevel world = TeleportCommands.server.getLevel(OVERWORLD); 66 66 BlockPos worldSpawn = Objects.requireNonNull(world,"Overworld cannot be null!").getSharedSpawnPos(); 67 67 68 68 if (!safetyDisabled) {
+1 -1
common/src/main/java/dev/mrsnowy/teleport_commands/common/DeathLocation.java
··· 31 31 32 32 // function to quickly filter the worlds and get the ServerLevel for the string 33 33 public Optional<ServerLevel> getWorld() { 34 - return StreamSupport.stream( TeleportCommands.SERVER.getAllLevels().spliterator(), false ) // woa, this looks silly 34 + return StreamSupport.stream( TeleportCommands.server.getAllLevels().spliterator(), false ) // woa, this looks silly 35 35 .filter(level -> Objects.equals( level.dimension().location().toString(), this.world )) 36 36 .findFirst(); 37 37 }
+1 -1
common/src/main/java/dev/mrsnowy/teleport_commands/common/NamedLocation.java
··· 53 53 54 54 // function to quickly filter the worlds and get the ServerLevel for the string 55 55 public Optional<ServerLevel> getWorld() { 56 - return StreamSupport.stream( TeleportCommands.SERVER.getAllLevels().spliterator(), false ) // woa, this looks silly 56 + return StreamSupport.stream( TeleportCommands.server.getAllLevels().spliterator(), false ) // woa, this looks silly 57 57 .filter(level -> Objects.equals( level.dimension().location().toString(), this.world )) 58 58 .findFirst(); 59 59 }
+12 -12
common/src/main/java/dev/mrsnowy/teleport_commands/storage/ConfigManager.java
··· 10 10 import java.nio.file.StandardOpenOption; 11 11 12 12 public class ConfigManager { 13 - public static Path CONFIG_FILE; 14 - public static ConfigClass CONFIG; 15 - private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); 16 - private static final int defaultVersion = new ConfigClass().getVersion(); 13 + public Path CONFIG_FILE; 14 + public ConfigClass CONFIG; 15 + private final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); 16 + private final int defaultVersion = new ConfigClass().getVersion(); 17 17 18 - public static void ConfigInit() { 19 - CONFIG_FILE = TeleportCommands.CONFIG_DIR.resolve("teleport_commands.json"); 18 + public ConfigManager() { 19 + CONFIG_FILE = TeleportCommands.TeleportCommands.configDir.resolve("teleport_commands.json"); 20 20 21 21 try { 22 22 ConfigLoader(); ··· 28 28 } 29 29 } 30 30 31 - public static void ConfigLoader() throws Exception { 31 + public void ConfigLoader() throws Exception { 32 32 if (!CONFIG_FILE.toFile().exists() || CONFIG_FILE.toFile().length() == 0) { 33 - Files.createDirectories(TeleportCommands.CONFIG_DIR); 33 + Files.createDirectories(TeleportCommands.configDir); 34 34 35 35 Constants.LOGGER.warn("Config file was not found or was empty! Initializing config"); 36 36 CONFIG = new ConfigClass(); ··· 53 53 } 54 54 55 55 /// This function checks what version the config file is and migrates it to the current version of the mod. 56 - public static void ConfigMigrator() throws Exception { 56 + public void ConfigMigrator() throws Exception { 57 57 FileReader reader = new FileReader(CONFIG_FILE.toFile()); 58 58 JsonObject jsonObject = GSON.fromJson(reader, JsonObject.class); 59 59 ··· 76 76 } 77 77 } 78 78 79 - public static void ConfigSaver() throws Exception { 79 + public void ConfigSaver() throws Exception { 80 80 // todo! maybe throttle saves? 81 81 byte[] json = GSON.toJson( ConfigManager.CONFIG ).getBytes(); 82 82 83 83 Files.write(CONFIG_FILE, json, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE); 84 84 } 85 85 86 - public static class ConfigClass { 86 + public class ConfigClass { 87 87 private final int version = 0; 88 88 public Teleporting teleporting = new Teleporting(); 89 89 public Back back = new Back(); ··· 96 96 return version; 97 97 } 98 98 99 - public static final class Teleporting { 99 + public final class Teleporting { 100 100 private int delay = 5; 101 101 private boolean whileMoving = true; 102 102 private boolean whileFighting = false;
+4 -4
common/src/main/java/dev/mrsnowy/teleport_commands/storage/DeathLocationStorage.java
··· 7 7 import java.util.Optional; 8 8 9 9 public class DeathLocationStorage { 10 - private static final HashMap<String, DeathLocation> deathLocations = new HashMap<>(); 10 + private final HashMap<String, DeathLocation> deathLocations = new HashMap<>(); 11 11 12 12 // filters the deathLocationList and finds the one with the matching player uuid (if there is one) 13 - public static Optional<DeathLocation> getDeathLocation(String uuid) { 13 + public Optional<DeathLocation> getDeathLocation(String uuid) { 14 14 return Optional.ofNullable(deathLocations.get(uuid)); 15 15 } 16 16 17 17 // updates the deathLocation of a player, if there is no existing entry it will create a new deathLocation. 18 - public static void setDeathLocation(String uuid, BlockPos pos, String world) { 18 + public void setDeathLocation(String uuid, BlockPos pos, String world) { 19 19 20 20 if (deathLocations.containsKey(uuid)) { 21 21 // modify existing deathLocation ··· 29 29 } 30 30 } 31 31 32 - public static void clearDeathLocations() { 32 + public void clearDeathLocations() { 33 33 deathLocations.clear(); 34 34 } 35 35 }
+14 -14
common/src/main/java/dev/mrsnowy/teleport_commands/storage/StorageManager.java
··· 18 18 import static java.util.Collections.unmodifiableList; 19 19 20 20 public class StorageManager { 21 - public static Path STORAGE_FOLDER; 22 - public static Path STORAGE_FILE; 23 - public static StorageClass STORAGE; 24 - private static final Gson GSON = new GsonBuilder().create(); 25 - private static final int defaultVersion = new StorageClass().getVersion(); 21 + public Path STORAGE_FOLDER; 22 + public Path STORAGE_FILE; 23 + public StorageClass STORAGE; 24 + private final Gson GSON = new GsonBuilder().create(); 25 + private final int defaultVersion = new StorageClass().getVersion(); 26 26 27 27 /// Initializes the StorageManager class and loads the storage from the filesystem. 28 - public static void StorageInit() { 29 - STORAGE_FOLDER = TeleportCommands.SAVE_DIR.resolve("TeleportCommands/"); 28 + public StorageManager() { 29 + STORAGE_FOLDER = TeleportCommands.TeleportCommands.saveDir.resolve("TeleportCommands/"); 30 30 STORAGE_FILE = STORAGE_FOLDER.resolve("storage.json"); 31 31 32 32 try { ··· 40 40 } 41 41 42 42 /// Loads the storage from the filesystem 43 - public static void StorageLoader() throws Exception { 43 + public void StorageLoader() throws Exception { 44 44 45 45 if (!STORAGE_FILE.toFile().exists() || STORAGE_FILE.toFile().length() == 0) { 46 46 Constants.LOGGER.warn("Storage file was not found or was empty! Initializing storage"); ··· 68 68 } 69 69 70 70 /// This function checks what version the storage file is and migrates it to the current version of the mod. 71 - public static void StorageMigrator() throws Exception { 71 + public void StorageMigrator() throws Exception { 72 72 FileReader reader = new FileReader(STORAGE_FILE.toFile()); 73 73 JsonObject jsonObject = GSON.fromJson(reader, JsonObject.class); 74 74 ··· 120 120 } 121 121 122 122 /// Saves the storage to the filesystem 123 - public static void StorageSaver() throws Exception { 123 + public void StorageSaver() throws Exception { 124 124 // todo! maybe throttle saves? 125 - byte[] json = GSON.toJson( StorageManager.STORAGE ).getBytes(); 125 + byte[] json = GSON.toJson( this.STORAGE ).getBytes(); 126 126 127 127 Files.write(STORAGE_FILE, json, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE); 128 128 } 129 129 130 130 131 - public static class StorageClass { 131 + public class StorageClass { 132 132 private final int version = 1; 133 133 private final ArrayList<NamedLocation> Warps = new ArrayList<>(); 134 134 private final ArrayList<Player> Players = new ArrayList<>(); ··· 144 144 List<NamedLocation> homes = player.getHomes(); 145 145 146 146 // Delete any homes with an invalid world_id (if enabled in config) 147 - if (ConfigManager.CONFIG.home.isDeleteInvalid()) { 147 + if (TeleportCommands.TeleportCommands.config.CONFIG.home.isDeleteInvalid()) { 148 148 homes.removeIf(home -> home.getWorld().isEmpty()); 149 149 } 150 150 ··· 155 155 } 156 156 157 157 // Delete any warps with an invalid world_id (if enabled in config) 158 - if (ConfigManager.CONFIG.warp.isDeleteInvalid()) { 158 + if (TeleportCommands.TeleportCommands.config.CONFIG.warp.isDeleteInvalid()) { 159 159 Warps.removeIf(warp -> warp.getWorld().isEmpty()); 160 160 } 161 161
+36 -7
common/src/main/java/dev/mrsnowy/teleport_commands/utils/tools.java
··· 11 11 import java.util.regex.Pattern; 12 12 import java.util.stream.StreamSupport; 13 13 14 + import dev.mrsnowy.teleport_commands.storage.ConfigManager; 14 15 import net.minecraft.core.BlockPos; 15 16 import net.minecraft.core.particles.ParticleTypes; 16 17 import net.minecraft.network.chat.Component; ··· 24 25 import static dev.mrsnowy.teleport_commands.Constants.MOD_ID; 25 26 import static net.minecraft.sounds.SoundEvents.ENDERMAN_TELEPORT; 26 27 28 + 27 29 public class tools { 30 + private final TeleportCommands teleportCommands; 28 31 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"); 32 + private 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"); 33 + 34 + private final Map<UUID, PlayerData> playerData = new HashMap<>(); 35 + 36 + private class PlayerData { 37 + long lastTeleportTime = 0; 38 + long lastHitTime = 0; 39 + Vec3 lastPosition = Vec3.ZERO; 40 + } 41 + 42 + public tools(TeleportCommands teleportCommands) { 43 + this.teleportCommands = teleportCommands; 44 + } 45 + 46 + /// Teleport the player :P 47 + public void Teleporter(ServerPlayer player, ServerLevel world, Vec3 coords) { 48 + // Check if user is allowed to teleport by config settings 49 + 50 + int delay = teleportCommands.config.CONFIG.teleporting.getDelay(); 51 + 52 + // save when they last teleported and check delay 53 + 54 + // save pos and check if they have moved. 55 + 56 + // check if they got hit? whileFighting 57 + 58 + // save when they last got hit and if it exceeds fightCooldown 59 + 30 60 31 - public static void Teleporter(ServerPlayer player, ServerLevel world, Vec3 coords) { 32 61 // teleportation effects & sounds before teleporting 33 62 world.sendParticles(ParticleTypes.SNOWFLAKE, player.getX(), player.getY() + 1, player.getZ(), 20, 0.0D, 0.0D, 0.0D, 0.01); 34 63 world.sendParticles(ParticleTypes.WHITE_SMOKE, player.getX(), player.getY(), player.getZ(), 15, 0.0D, 1.0D, 0.0D, 0.03); ··· 64 93 65 94 66 95 // checks a 7x7x7 location around the player in order to find a safe place to teleport them to. 67 - public static Optional<BlockPos> getSafeBlockPos(BlockPos blockPos, ServerLevel world) { 96 + public Optional<BlockPos> getSafeBlockPos(BlockPos blockPos, ServerLevel world) { 68 97 int row = 1; 69 98 int rows = 3; 70 99 ··· 108 137 109 138 110 139 // 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!) 111 - public static MutableComponent getTranslatedText(String key, ServerPlayer player, MutableComponent... args) { 140 + public MutableComponent getTranslatedText(String key, ServerPlayer player, MutableComponent... args) { 112 141 //todo! maybe make this also loaded in memory? 113 142 String language = player.clientInformation().language().toLowerCase(); 114 143 String regex = "%(\\d+)%"; ··· 193 222 194 223 195 224 // Gets the ids of all the worlds 196 - public static List<String> getWorldIds() { 197 - return StreamSupport.stream(TeleportCommands.SERVER.getAllLevels().spliterator(), false) 225 + public List<String> getWorldIds() { 226 + return StreamSupport.stream(teleportCommands.server.getAllLevels().spliterator(), false) 198 227 .map(level -> level.dimension().location().toString()) 199 228 .toList(); 200 229 } 201 230 202 231 203 232 // checks if a BlockPos is safe, used by the teleportSafetyChecker. 204 - private static boolean isBlockPosSafe(BlockPos bottomPlayer, ServerLevel world) { 233 + private boolean isBlockPosSafe(BlockPos bottomPlayer, ServerLevel world) { 205 234 206 235 // get the block below the player 207 236 BlockPos belowPlayer = new BlockPos(bottomPlayer.getX(), bottomPlayer.getY() -1, bottomPlayer.getZ()); // below the player
+1 -1
fabric/src/main/java/dev/mrsnowy/teleport_commands/fabricInit.java
··· 10 10 // However, some things (like resources) may still be uninitialized. 11 11 // Proceed with mild caution. 12 12 13 - TeleportCommands.MOD_LOADER = "Fabric"; 13 + TeleportCommands.modLoader = "Fabric"; 14 14 } 15 15 }
+1 -1
neoforge/src/main/java/dev/mrsnowy/teleport_commands/neoforgeInit.java
··· 11 11 // to load your mod. You can access NeoForge and Common code in this 12 12 // project. 13 13 14 - TeleportCommands.MOD_LOADER = "NeoForge"; 14 + TeleportCommands.modLoader = "NeoForge"; 15 15 } 16 16 } 17 17