From 2df2c7848eed945da37ea0dbe9237c4e4dfab50c Mon Sep 17 00:00:00 2001 From: Zontreck Date: Sat, 8 Oct 2022 18:33:24 -0700 Subject: [PATCH] Refactor code to use a common storage format for warps and homes --- gradle.properties | 2 +- src/main/java/dev/zontreck/otemod/OTEMod.java | 13 +- .../otemod/commands/CommandRegistry.java | 15 +++ .../zontreck/otemod/commands/FlyCommand.java | 2 +- .../commands/{ => homes}/DelHomeCommand.java | 8 +- .../commands/{ => homes}/HomeCommand.java | 29 +++-- .../commands/{ => homes}/HomesCommand.java | 4 +- .../commands/{ => homes}/SetHomeCommand.java | 13 +- .../profilecmds/ChatColorCommand.java | 3 +- .../otemod/commands/teleport/RTPCommand.java | 73 ++++++++++- .../otemod/commands/warps/DelWarpCommand.java | 74 ++++++++++++ .../otemod/commands/warps/RTPWarpCommand.java | 76 ++++++++++++ .../otemod/commands/warps/SetWarpCommand.java | 76 ++++++++++++ .../otemod/commands/warps/WarpCommand.java | 113 ++++++++++++++++++ .../otemod/commands/warps/WarpsCommand.java | 95 +++++++++++++++ .../zontreck/otemod/containers/Vector2.java | 69 +++++++++++ .../zontreck/otemod/containers/Vector3.java | 27 +++++ .../otemod/database/TeleportDestination.java | 43 +++++++ src/main/resources/META-INF/mods.toml | 2 +- .../resources/assets/otemod/lang/en_us.json | 8 +- 20 files changed, 712 insertions(+), 33 deletions(-) rename src/main/java/dev/zontreck/otemod/commands/{ => homes}/DelHomeCommand.java (87%) rename src/main/java/dev/zontreck/otemod/commands/{ => homes}/HomeCommand.java (83%) rename src/main/java/dev/zontreck/otemod/commands/{ => homes}/HomesCommand.java (90%) rename src/main/java/dev/zontreck/otemod/commands/{ => homes}/SetHomeCommand.java (75%) create mode 100644 src/main/java/dev/zontreck/otemod/commands/warps/DelWarpCommand.java create mode 100644 src/main/java/dev/zontreck/otemod/commands/warps/RTPWarpCommand.java create mode 100644 src/main/java/dev/zontreck/otemod/commands/warps/SetWarpCommand.java create mode 100644 src/main/java/dev/zontreck/otemod/commands/warps/WarpCommand.java create mode 100644 src/main/java/dev/zontreck/otemod/commands/warps/WarpsCommand.java create mode 100644 src/main/java/dev/zontreck/otemod/containers/Vector2.java create mode 100644 src/main/java/dev/zontreck/otemod/database/TeleportDestination.java diff --git a/gradle.properties b/gradle.properties index 731f455..ae2f2fd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx8G org.gradle.daemon=false -my_version=1.3.3.3 +my_version=1.3.3.4 mc_version=1.19.2 forge_version=43.1.32 diff --git a/src/main/java/dev/zontreck/otemod/OTEMod.java b/src/main/java/dev/zontreck/otemod/OTEMod.java index 9c8cace..62ca946 100644 --- a/src/main/java/dev/zontreck/otemod/OTEMod.java +++ b/src/main/java/dev/zontreck/otemod/OTEMod.java @@ -167,12 +167,7 @@ public class OTEMod " `number` int(11) NOT NULL," + " `user` varchar(255) NOT NULL," + " `home_name` varchar(255) NOT NULL," + -" `x` varchar(20) NOT NULL," + -" `y` varchar(20) NOT NULL," + -" `z` varchar(20) NOT NULL," + -" `rot_x` varchar(20) NOT NULL," + -" `rot_y` varchar(20) NOT NULL," + -" `dimension` varchar(255) NOT NULL)"); // 10/04/2022 - fix dimension column size due to a bug where mods might have long names! +" `teleporter` text not null)"); // 10/04/2022 - fix dimension column size due to a bug where mods might have long names! lookup.execute("CREATE TABLE IF NOT EXISTS `profiles` ("+ "`username` varchar (255) not null,"+ @@ -188,6 +183,12 @@ public class OTEMod "`number` int (11) not null," + "`data` text not null);"); + lookup.execute("CREATE TABLE IF NOT EXISTS `warps` (" + + "`warpname` varchar (128) not null, " + + "`owner` varchar(128) not null, " + + "`warptype` int (2) not null, "+ + "`teleporter` text not null)"); + con.endRequest(); // Set up the repeating task to expire a TeleportContainer diff --git a/src/main/java/dev/zontreck/otemod/commands/CommandRegistry.java b/src/main/java/dev/zontreck/otemod/commands/CommandRegistry.java index fd4b8f3..0895b4a 100644 --- a/src/main/java/dev/zontreck/otemod/commands/CommandRegistry.java +++ b/src/main/java/dev/zontreck/otemod/commands/CommandRegistry.java @@ -5,6 +5,10 @@ import java.util.HashMap; import java.util.Map; import dev.zontreck.otemod.OTEMod; +import dev.zontreck.otemod.commands.homes.DelHomeCommand; +import dev.zontreck.otemod.commands.homes.HomeCommand; +import dev.zontreck.otemod.commands.homes.HomesCommand; +import dev.zontreck.otemod.commands.homes.SetHomeCommand; import dev.zontreck.otemod.commands.profilecmds.ChatColorCommand; import dev.zontreck.otemod.commands.profilecmds.NameColorCommand; import dev.zontreck.otemod.commands.profilecmds.NickCommand; @@ -18,6 +22,11 @@ import dev.zontreck.otemod.commands.teleport.TPCancelCommand; import dev.zontreck.otemod.commands.teleport.TPDenyCommand; import dev.zontreck.otemod.commands.vaults.TrashCommand; import dev.zontreck.otemod.commands.vaults.VaultCommand; +import dev.zontreck.otemod.commands.warps.DelWarpCommand; +import dev.zontreck.otemod.commands.warps.RTPWarpCommand; +import dev.zontreck.otemod.commands.warps.SetWarpCommand; +import dev.zontreck.otemod.commands.warps.WarpCommand; +import dev.zontreck.otemod.commands.warps.WarpsCommand; import dev.zontreck.otemod.configs.OTEServerConfig; import net.minecraftforge.event.RegisterCommandsEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; @@ -106,6 +115,12 @@ public class CommandRegistry { VaultCommand.register(ev.getDispatcher()); TrashCommand.register(ev.getDispatcher()); + + SetWarpCommand.register(ev.getDispatcher()); + DelWarpCommand.register(ev.getDispatcher()); + RTPWarpCommand.register(ev.getDispatcher()); + WarpsCommand.register(ev.getDispatcher()); + WarpCommand.register(ev.getDispatcher()); } diff --git a/src/main/java/dev/zontreck/otemod/commands/FlyCommand.java b/src/main/java/dev/zontreck/otemod/commands/FlyCommand.java index 1dd2014..7d18896 100644 --- a/src/main/java/dev/zontreck/otemod/commands/FlyCommand.java +++ b/src/main/java/dev/zontreck/otemod/commands/FlyCommand.java @@ -33,7 +33,7 @@ public class FlyCommand { if(! ctx.isPlayer()) { - ctx.sendFailure(MutableComponent.create( new TranslatableContents("dev.zontreck.otemod.msgs.homes.only_player"))); + ctx.sendFailure(MutableComponent.create( new TranslatableContents("dev.zontreck.otemod.msgs.only_player"))); return 1; } ServerPlayer p = ctx.getPlayer(); diff --git a/src/main/java/dev/zontreck/otemod/commands/DelHomeCommand.java b/src/main/java/dev/zontreck/otemod/commands/homes/DelHomeCommand.java similarity index 87% rename from src/main/java/dev/zontreck/otemod/commands/DelHomeCommand.java rename to src/main/java/dev/zontreck/otemod/commands/homes/DelHomeCommand.java index 0a89e85..18ddd46 100644 --- a/src/main/java/dev/zontreck/otemod/commands/DelHomeCommand.java +++ b/src/main/java/dev/zontreck/otemod/commands/homes/DelHomeCommand.java @@ -1,4 +1,4 @@ -package dev.zontreck.otemod.commands; +package dev.zontreck.otemod.commands.homes; import java.sql.Array; import java.sql.Connection; @@ -15,6 +15,8 @@ import com.mojang.brigadier.context.CommandContext; import com.mojang.math.Vector3d; import dev.zontreck.otemod.OTEMod; +import dev.zontreck.otemod.chat.ChatColor; +import dev.zontreck.otemod.chat.ChatServerOverride; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; import net.minecraft.network.chat.contents.TranslatableContents; @@ -49,7 +51,7 @@ public class DelHomeCommand { if(! ctx.isPlayer()) { - ctx.sendFailure(MutableComponent.create( new TranslatableContents("dev.zontreck.otemod.msgs.homes.only_player"))); + ChatServerOverride.broadcastTo(ctx.getPlayer().getUUID(), Component.literal(ChatColor.DARK_RED).append(Component.translatable("dev.zontreck.otemod.msgs.only_player")), ctx.getServer()); return 1; } ServerPlayer p = ctx.getPlayer(); @@ -57,8 +59,6 @@ public class DelHomeCommand { try { con.beginRequest(); //Statement stat = con.createStatement(); - Vec3 position = p.position(); - Vec2 rot = p.getRotationVector(); String SQL = "DELETE FROM `homes` WHERE `user`=? AND `home_name`=?;"; diff --git a/src/main/java/dev/zontreck/otemod/commands/HomeCommand.java b/src/main/java/dev/zontreck/otemod/commands/homes/HomeCommand.java similarity index 83% rename from src/main/java/dev/zontreck/otemod/commands/HomeCommand.java rename to src/main/java/dev/zontreck/otemod/commands/homes/HomeCommand.java index 4e1c326..7c9df77 100644 --- a/src/main/java/dev/zontreck/otemod/commands/HomeCommand.java +++ b/src/main/java/dev/zontreck/otemod/commands/homes/HomeCommand.java @@ -1,4 +1,4 @@ -package dev.zontreck.otemod.commands; +package dev.zontreck.otemod.commands.homes; import java.sql.Array; import java.sql.Connection; @@ -9,18 +9,23 @@ import java.sql.Statement; import java.util.ArrayList; import java.util.List; +import com.ibm.icu.impl.InvalidFormatException; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.math.Vector3d; import dev.zontreck.otemod.OTEMod; import dev.zontreck.otemod.chat.ChatColor; +import dev.zontreck.otemod.chat.ChatServerOverride; import dev.zontreck.otemod.commands.teleport.TeleportActioner; import dev.zontreck.otemod.commands.teleport.TeleportContainer; import dev.zontreck.otemod.configs.PlayerFlyCache; +import dev.zontreck.otemod.database.TeleportDestination; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; +import net.minecraft.nbt.NbtUtils; import net.minecraft.network.chat.contents.TranslatableContents; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; @@ -63,7 +68,7 @@ public class HomeCommand { if(! ctx.isPlayer()) { - ctx.sendFailure(MutableComponent.create( new TranslatableContents("dev.zontreck.otemod.msgs.homes.only_player"))); + ChatServerOverride.broadcastTo(ctx.getPlayer().getUUID(), Component.literal(ChatColor.DARK_RED).append(Component.translatable("dev.zontreck.otemod.msgs.only_player")), ctx.getServer()); return 1; } ServerPlayer p = ctx.getPlayer(); @@ -91,18 +96,14 @@ public class HomeCommand { while(rs.next()){ has_home=true; // Now, begin to extract the home data - double x = Double.parseDouble(rs.getString("x")); - double y = Double.parseDouble(rs.getString("y")); - double z = Double.parseDouble(rs.getString("z")); - - float rx = Float.parseFloat(rs.getString("rot_x")); - float ry = Float.parseFloat(rs.getString("rot_y")); + TeleportDestination dest = new TeleportDestination(NbtUtils.snbtToStructure(rs.getString("teleporter"))); + - position = new Vec3(x, y, z); - rot = new Vec2(rx, ry); + position = dest.Position.asMinecraftVector(); + rot = dest.Rotation.asMinecraftVector(); - String dim = rs.getString("dimension"); + String dim = dest.Dimension; String[] dims = dim.split(":"); ResourceLocation rl = new ResourceLocation(dims[0], dims[1]); @@ -147,6 +148,12 @@ public class HomeCommand { ctx.sendFailure(Component.translatable("dev.zontreck.otemod.msgs.homes.goto.fail")); else ctx.sendFailure(Component.literal("FAILED SQL: "+ ChatColor.GOLD+ SQL)); + } catch (InvalidFormatException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (CommandSyntaxException e) { + // TODO Auto-generated catch block + e.printStackTrace(); } return 0; diff --git a/src/main/java/dev/zontreck/otemod/commands/HomesCommand.java b/src/main/java/dev/zontreck/otemod/commands/homes/HomesCommand.java similarity index 90% rename from src/main/java/dev/zontreck/otemod/commands/HomesCommand.java rename to src/main/java/dev/zontreck/otemod/commands/homes/HomesCommand.java index a6124dd..8361c7e 100644 --- a/src/main/java/dev/zontreck/otemod/commands/HomesCommand.java +++ b/src/main/java/dev/zontreck/otemod/commands/homes/HomesCommand.java @@ -1,4 +1,4 @@ -package dev.zontreck.otemod.commands; +package dev.zontreck.otemod.commands.homes; import java.sql.Array; import java.sql.Connection; @@ -44,7 +44,7 @@ public class HomesCommand { if(! ctx.getSource().isPlayer()) { - ctx.getSource().sendFailure(MutableComponent.create( new TranslatableContents("dev.zontreck.otemod.msgs.homes.only_player"))); + ChatServerOverride.broadcastTo(ctx.getSource().getPlayer().getUUID(), Component.literal(ChatColor.DARK_RED).append(Component.translatable("dev.zontreck.otemod.msgs.only_player")), ctx.getSource().getServer()); return 1; } ServerPlayer p = ctx.getSource().getPlayer(); diff --git a/src/main/java/dev/zontreck/otemod/commands/SetHomeCommand.java b/src/main/java/dev/zontreck/otemod/commands/homes/SetHomeCommand.java similarity index 75% rename from src/main/java/dev/zontreck/otemod/commands/SetHomeCommand.java rename to src/main/java/dev/zontreck/otemod/commands/homes/SetHomeCommand.java index 09734e2..58d42aa 100644 --- a/src/main/java/dev/zontreck/otemod/commands/SetHomeCommand.java +++ b/src/main/java/dev/zontreck/otemod/commands/homes/SetHomeCommand.java @@ -1,4 +1,4 @@ -package dev.zontreck.otemod.commands; +package dev.zontreck.otemod.commands.homes; import java.sql.Array; import java.sql.Connection; @@ -14,6 +14,11 @@ import com.mojang.brigadier.context.CommandContext; import com.mojang.math.Vector3d; import dev.zontreck.otemod.OTEMod; +import dev.zontreck.otemod.chat.ChatColor; +import dev.zontreck.otemod.chat.ChatServerOverride; +import dev.zontreck.otemod.containers.Vector2; +import dev.zontreck.otemod.containers.Vector3; +import dev.zontreck.otemod.database.TeleportDestination; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; import net.minecraft.network.chat.contents.TranslatableContents; @@ -48,7 +53,7 @@ public class SetHomeCommand { if(! ctx.isPlayer()) { - ctx.sendFailure(MutableComponent.create( new TranslatableContents("dev.zontreck.otemod.msgs.homes.only_player"))); + ChatServerOverride.broadcastTo(ctx.getPlayer().getUUID(), Component.literal(ChatColor.DARK_RED).append(Component.translatable("dev.zontreck.otemod.msgs.only_player")), ctx.getServer()); return 1; } ServerPlayer p = ctx.getPlayer(); @@ -59,7 +64,9 @@ public class SetHomeCommand { Vec3 position = p.position(); Vec2 rot = p.getRotationVector(); - stat.execute("REPLACE INTO `homes` (user, home_name, x, y, z, rot_x, rot_y, dimension) values (\"" + p.getStringUUID() + "\", \""+ homeName + "\", "+String.valueOf(position.x)+", "+String.valueOf(position.y)+", "+String.valueOf(position.z)+", "+String.valueOf(rot.x)+", "+String.valueOf(rot.y)+", \"" + p.getLevel().dimension().location().getNamespace() + ":" + p.getLevel().dimension().location().getPath() + "\");"); + TeleportDestination dest = new TeleportDestination(new Vector3(position), new Vector2(rot), p.getLevel().dimension().location().getNamespace() + ":" + p.getLevel().dimension().location().getPath()); + + stat.execute("REPLACE INTO `homes` (user, home_name, teleporter) values (\"" + p.getStringUUID() + "\", \""+ homeName + "\", \""+ dest.toString() + "\");"); ctx.sendSuccess(MutableComponent.create(new TranslatableContents("dev.zontreck.otemod.msgs.homes.set.success")), true); diff --git a/src/main/java/dev/zontreck/otemod/commands/profilecmds/ChatColorCommand.java b/src/main/java/dev/zontreck/otemod/commands/profilecmds/ChatColorCommand.java index 15e9cb3..8b77dfa 100644 --- a/src/main/java/dev/zontreck/otemod/commands/profilecmds/ChatColorCommand.java +++ b/src/main/java/dev/zontreck/otemod/commands/profilecmds/ChatColorCommand.java @@ -4,6 +4,7 @@ import com.mojang.brigadier.CommandDispatcher; import dev.zontreck.otemod.OTEMod; import dev.zontreck.otemod.chat.ChatColor; +import dev.zontreck.otemod.chat.ChatServerOverride; import dev.zontreck.otemod.chat.ChatColor.ColorOptions; import dev.zontreck.otemod.configs.Profile; import net.minecraft.commands.CommandSourceStack; @@ -36,7 +37,7 @@ public class ChatColorCommand { // Get profile if(source.getPlayer()==null){ - source.sendFailure(Component.literal(ChatColor.DARK_RED+"Only a player can use this command")); + ChatServerOverride.broadcastTo(source.getPlayer().getUUID(), Component.literal(ChatColor.DARK_RED).append(Component.translatable("dev.zontreck.otemod.msgs.only_player")), source.getServer()); return 1; } Profile p = Profile.get_profile_of(source.getPlayer().getStringUUID()); diff --git a/src/main/java/dev/zontreck/otemod/commands/teleport/RTPCommand.java b/src/main/java/dev/zontreck/otemod/commands/teleport/RTPCommand.java index 4956e6f..8e0893b 100644 --- a/src/main/java/dev/zontreck/otemod/commands/teleport/RTPCommand.java +++ b/src/main/java/dev/zontreck/otemod/commands/teleport/RTPCommand.java @@ -1,5 +1,6 @@ package dev.zontreck.otemod.commands.teleport; +import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.Random; @@ -18,8 +19,10 @@ import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.DoubleBlockCombiner.BlockType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; @@ -38,6 +41,68 @@ public class RTPCommand { //})); } + public static Vector3 findPosition(ServerLevel lvl, boolean allowWater) + { + Vector3 v = new Vector3(); + boolean found_place = false; + // We do not care how many tries it takes + + while (!found_place) + { + + // Take our current position, and send us in a random direction + Random rng = new Random(Instant.now().getEpochSecond()); + v.y = 300; + v.x = rng.nextDouble(0xffff); + v.z = rng.nextDouble(0xffff); + + boolean is_invalid_location = false; + String block_place=""; + + while(v.y!=-30) + { + + BlockState b = lvl.getBlockState(new BlockPos(v.asMinecraftVector())); + BlockState b2 = lvl.getBlockState(new BlockPos(v.moveUp().asMinecraftVector())); + BlockState b3 = lvl.getBlockState(new BlockPos(v.moveDown().asMinecraftVector())); + + if(b.isAir()){ + if(b2.isAir()){ + if(!b3.isAir()) + { + // Check names + boolean valid=true; + List blackLists = new ArrayList<>(); + if(!allowWater) + blackLists.add(Blocks.WATER); + blackLists.add(Blocks.LAVA); + + block_place = b3.getBlock().getName().getString(); + OTEMod.LOGGER.info(b3.getBlock().getName().getString()); + for(Block bx : blackLists) + { + if(b.is(bx) || b2.is(bx) || b3.is(bx)){ + valid=false; + is_invalid_location=true; + } + } + + if(valid){ + + found_place = true; + break; + } + + } + } + } + v=v.moveDown(); + } + } + + return v; + } + private static int rtp(CommandSourceStack source, boolean allowWater) { /*if(!CommandRegistry.canUse("rtp")) { @@ -64,6 +129,9 @@ public class RTPCommand { int tries=0; ChatServerOverride.broadcastTo(pla.getUUID(), Component.literal(ChatColor.DARK_GRAY + "["+ChatColor.DARK_GREEN+"OTEMOD"+ChatColor.DARK_GRAY+"] "+ChatColor.GREEN+"Searching for a suitable landing location..."), source.getServer()); + /* + * + * while(!found_place){ // Take our current position, and send us in a random direction @@ -76,7 +144,7 @@ public class RTPCommand { String block_place=""; // Begin to scan for ground - while(v.y != 0) + while(v.y != -30) { // check block above and below BlockState b = source.getLevel().getBlockState(new BlockPos(v.asMinecraftVector())); @@ -144,7 +212,8 @@ public class RTPCommand { // TODO Auto-generated catch block e.printStackTrace(); } - } + }*/ + v=findPosition(source.getLevel(), allowWater); ChatServerOverride.broadcastTo(pla.getUUID(), Component.literal(ChatColor.DARK_GRAY + "["+ChatColor.DARK_GREEN + "OTEMOD" + ChatColor.DARK_GRAY + "] "+ChatColor.DARK_PURPLE+" A suitable location has been found. Wormhole opening now!"), source.getServer()); diff --git a/src/main/java/dev/zontreck/otemod/commands/warps/DelWarpCommand.java b/src/main/java/dev/zontreck/otemod/commands/warps/DelWarpCommand.java new file mode 100644 index 0000000..424ed5b --- /dev/null +++ b/src/main/java/dev/zontreck/otemod/commands/warps/DelWarpCommand.java @@ -0,0 +1,74 @@ +package dev.zontreck.otemod.commands.warps; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Statement; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.StringArgumentType; + +import dev.zontreck.otemod.OTEMod; +import dev.zontreck.otemod.chat.ChatColor; +import dev.zontreck.otemod.chat.ChatServerOverride; +import dev.zontreck.otemod.containers.Vector2; +import dev.zontreck.otemod.containers.Vector3; +import dev.zontreck.otemod.database.TeleportDestination; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.contents.TranslatableContents; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.phys.Vec2; +import net.minecraft.world.phys.Vec3; + +public class DelWarpCommand { + + public static void register(CommandDispatcher dispatcher) + { + dispatcher.register(Commands.literal("delwarp").then(Commands.argument("nickname", StringArgumentType.string()).executes(c -> setWarp(c.getSource(), StringArgumentType.getString(c, "nickname"))))); + + //dispatcher.register(Commands.literal("sethome").then(Commands.argument("nickname", StringArgumentType.string())).executes(command -> { + //String arg = StringArgumentType.getString(command, "nickname"); + //return setHome(command.getSource(), arg); + //})); + } + + private static int setWarp(CommandSourceStack source, String string) { + + if(! source.isPlayer()) + { + + ChatServerOverride.broadcastTo(source.getPlayer().getUUID(), Component.literal(ChatColor.DARK_RED).append(Component.translatable("dev.zontreck.otemod.msgs.only_player")), source.getServer()); + return 1; + } + ServerPlayer p = source.getPlayer(); + Connection con = OTEMod.DB.getConnection(); + try { + con.beginRequest(); + PreparedStatement pstat; + Vec3 position = p.position(); + Vec2 rot = p.getRotationVector(); + + TeleportDestination dest = new TeleportDestination(new Vector3(position), new Vector2(rot), p.getLevel().dimension().location().getNamespace() + ":" + p.getLevel().dimension().location().getPath()); + + String SQL = "DELETE FROM `warps` WHERE `warpname`=? AND `owner`=?;"; + pstat = con.prepareStatement(SQL); + pstat.setString(1, string); + pstat.setString(2, p.getStringUUID()); + pstat.execute(); + + + ChatServerOverride.broadcastTo(source.getPlayer().getUUID(), Component.literal(ChatColor.GREEN).append(Component.translatable("dev.zontreck.otemod.msgs.warps.del.success")), source.getServer()); + + con.endRequest(); + } catch (SQLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + ChatServerOverride.broadcastTo(source.getPlayer().getUUID(), Component.literal(ChatColor.DARK_RED).append(Component.translatable("dev.zontreck.otemod.msgs.warps.del.fail")), source.getServer()); + } + + return 0; + } +} diff --git a/src/main/java/dev/zontreck/otemod/commands/warps/RTPWarpCommand.java b/src/main/java/dev/zontreck/otemod/commands/warps/RTPWarpCommand.java new file mode 100644 index 0000000..b47c227 --- /dev/null +++ b/src/main/java/dev/zontreck/otemod/commands/warps/RTPWarpCommand.java @@ -0,0 +1,76 @@ +package dev.zontreck.otemod.commands.warps; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Statement; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.StringArgumentType; + +import dev.zontreck.otemod.OTEMod; +import dev.zontreck.otemod.chat.ChatColor; +import dev.zontreck.otemod.chat.ChatServerOverride; +import dev.zontreck.otemod.containers.Vector2; +import dev.zontreck.otemod.containers.Vector3; +import dev.zontreck.otemod.database.TeleportDestination; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.contents.TranslatableContents; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.phys.Vec2; +import net.minecraft.world.phys.Vec3; + +public class RTPWarpCommand { + + public static void register(CommandDispatcher dispatcher) + { + dispatcher.register(Commands.literal("rtpwarp").then(Commands.argument("nickname", StringArgumentType.string()).executes(c -> setWarp(c.getSource(), StringArgumentType.getString(c, "nickname"))))); + + //dispatcher.register(Commands.literal("sethome").then(Commands.argument("nickname", StringArgumentType.string())).executes(command -> { + //String arg = StringArgumentType.getString(command, "nickname"); + //return setHome(command.getSource(), arg); + //})); + } + + private static int setWarp(CommandSourceStack source, String string) { + + if(! source.isPlayer()) + { + + ChatServerOverride.broadcastTo(source.getPlayer().getUUID(), Component.literal(ChatColor.DARK_RED).append(Component.translatable("dev.zontreck.otemod.msgs.only_player")), source.getServer()); + return 1; + } + ServerPlayer p = source.getPlayer(); + Connection con = OTEMod.DB.getConnection(); + try { + con.beginRequest(); + PreparedStatement pstat; + Vec3 position = p.position(); + Vec2 rot = p.getRotationVector(); + + TeleportDestination dest = new TeleportDestination(new Vector3(position), new Vector2(rot), p.getLevel().dimension().location().getNamespace() + ":" + p.getLevel().dimension().location().getPath()); + + String SQL = "REPLACE INTO `warps` (warpname, owner, warptype, teleporter) values (?, ?, ?, ?);"; + pstat = con.prepareStatement(SQL); + pstat.setString(1, string); + pstat.setString(2, p.getStringUUID()); + pstat.setInt(3, 1); + pstat.setString(4, dest.toString()); + pstat.execute(); + + + ChatServerOverride.broadcastTo(source.getPlayer().getUUID(), Component.literal(ChatColor.GREEN).append(Component.translatable("dev.zontreck.otemod.msgs.warps.set.success")), source.getServer()); + + con.endRequest(); + } catch (SQLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + ChatServerOverride.broadcastTo(source.getPlayer().getUUID(), Component.literal(ChatColor.DARK_RED).append(Component.translatable("dev.zontreck.otemod.msgs.warps.set.fail")), source.getServer()); + } + + return 0; + } +} diff --git a/src/main/java/dev/zontreck/otemod/commands/warps/SetWarpCommand.java b/src/main/java/dev/zontreck/otemod/commands/warps/SetWarpCommand.java new file mode 100644 index 0000000..97f2e01 --- /dev/null +++ b/src/main/java/dev/zontreck/otemod/commands/warps/SetWarpCommand.java @@ -0,0 +1,76 @@ +package dev.zontreck.otemod.commands.warps; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Statement; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.StringArgumentType; + +import dev.zontreck.otemod.OTEMod; +import dev.zontreck.otemod.chat.ChatColor; +import dev.zontreck.otemod.chat.ChatServerOverride; +import dev.zontreck.otemod.containers.Vector2; +import dev.zontreck.otemod.containers.Vector3; +import dev.zontreck.otemod.database.TeleportDestination; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.contents.TranslatableContents; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.phys.Vec2; +import net.minecraft.world.phys.Vec3; + +public class SetWarpCommand { + + public static void register(CommandDispatcher dispatcher) + { + dispatcher.register(Commands.literal("setwarp").then(Commands.argument("nickname", StringArgumentType.string()).executes(c -> setWarp(c.getSource(), StringArgumentType.getString(c, "nickname"))))); + + //dispatcher.register(Commands.literal("sethome").then(Commands.argument("nickname", StringArgumentType.string())).executes(command -> { + //String arg = StringArgumentType.getString(command, "nickname"); + //return setHome(command.getSource(), arg); + //})); + } + + private static int setWarp(CommandSourceStack source, String string) { + + if(! source.isPlayer()) + { + + ChatServerOverride.broadcastTo(source.getPlayer().getUUID(), Component.literal(ChatColor.DARK_RED).append(Component.translatable("dev.zontreck.otemod.msgs.only_player")), source.getServer()); + return 1; + } + ServerPlayer p = source.getPlayer(); + Connection con = OTEMod.DB.getConnection(); + try { + con.beginRequest(); + PreparedStatement pstat; + Vec3 position = p.position(); + Vec2 rot = p.getRotationVector(); + + TeleportDestination dest = new TeleportDestination(new Vector3(position), new Vector2(rot), p.getLevel().dimension().location().getNamespace() + ":" + p.getLevel().dimension().location().getPath()); + + String SQL = "REPLACE INTO `warps` (warpname, owner, warptype, teleporter) values (?, ?, ?, ?);"; + pstat = con.prepareStatement(SQL); + pstat.setString(1, string); + pstat.setString(2, p.getStringUUID()); + pstat.setInt(3, 0); + pstat.setString(4, dest.toString()); + pstat.execute(); + + + ChatServerOverride.broadcastTo(source.getPlayer().getUUID(), Component.literal(ChatColor.GREEN).append(Component.translatable("dev.zontreck.otemod.msgs.warps.set.success")), source.getServer()); + + con.endRequest(); + } catch (SQLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + ChatServerOverride.broadcastTo(source.getPlayer().getUUID(), Component.literal(ChatColor.DARK_RED).append(Component.translatable("dev.zontreck.otemod.msgs.warps.set.fail")), source.getServer()); + } + + return 0; + } +} diff --git a/src/main/java/dev/zontreck/otemod/commands/warps/WarpCommand.java b/src/main/java/dev/zontreck/otemod/commands/warps/WarpCommand.java new file mode 100644 index 0000000..5bff4a2 --- /dev/null +++ b/src/main/java/dev/zontreck/otemod/commands/warps/WarpCommand.java @@ -0,0 +1,113 @@ +package dev.zontreck.otemod.commands.warps; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.StringArgumentType; + +import dev.zontreck.otemod.OTEMod; +import dev.zontreck.otemod.chat.ChatColor; +import dev.zontreck.otemod.chat.ChatServerOverride; +import dev.zontreck.otemod.chat.Clickable; +import dev.zontreck.otemod.commands.teleport.RTPCommand; +import dev.zontreck.otemod.commands.teleport.TeleportActioner; +import dev.zontreck.otemod.commands.teleport.TeleportContainer; +import dev.zontreck.otemod.database.TeleportDestination; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.Style; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; + +public class WarpCommand { + + public static void register(CommandDispatcher dispatcher) + { + dispatcher.register(Commands.literal("warp").executes(c-> nowarp(c.getSource())).then(Commands.argument("name", StringArgumentType.string()).executes(c->warp(c.getSource(), StringArgumentType.getString(c, "name"))))); + + //dispatcher.register(Commands.literal("sethome").then(Commands.argument("nickname", StringArgumentType.string())).executes(command -> { + //String arg = StringArgumentType.getString(command, "nickname"); + //return setHome(command.getSource(), arg); + //})); + } + + private static int warp(CommandSourceStack source, String string) { + if(!source.isPlayer())return 1; + + ServerPlayer p = source.getPlayer(); + Connection con = OTEMod.DB.getConnection(); + String SQL = ""; + try{ + con.beginRequest(); + + PreparedStatement pstat; + SQL = "SELECT * FROM `warps` WHERE `warpname`=?;"; + pstat=con.prepareStatement(SQL); + pstat.setString(1, string); + ResultSet rs = pstat.executeQuery(); + // Get the first result + if(rs.next()) + { + TeleportDestination dest = new TeleportDestination(NbtUtils.snbtToStructure(rs.getString("teleporter"))); + + String dim = dest.Dimension; + String[] dims = dim.split(":"); + + ResourceLocation rl = new ResourceLocation(dims[0], dims[1]); + + ServerLevel dimL = null; + for (ServerLevel lServerLevel : p.server.getAllLevels()) { + ResourceLocation XL = lServerLevel.dimension().location(); + + if(XL.getNamespace().equals(rl.getNamespace())){ + if(XL.getPath().equals(rl.getPath())){ + dimL = lServerLevel; + } + } + } + + if(dimL == null) + { + ChatServerOverride.broadcastTo(source.getPlayer().getUUID(), Component.literal(ChatColor.RED+"DIMENSION COULD NOT BE FOUND"), source.getServer()); + return 1; + } + + final int type = rs.getInt("warptype"); + final ServerLevel f_dim = dimL; + + Thread tx = new Thread(new Runnable(){ + public void run(){ + + if(type==1){ + dest.Position = RTPCommand.findPosition(source.getLevel(), false); + } + + TeleportActioner.ApplyTeleportEffect(p); + TeleportContainer tc = new TeleportContainer(p, dest.Position.asMinecraftVector(), dest.Rotation.asMinecraftVector(), f_dim); + TeleportActioner.PerformTeleport(tc); + } + }); + tx.start(); + }else { + ChatServerOverride.broadcastTo(source.getPlayer().getUUID(), Component.literal(ChatColor.DARK_RED+"No such warp"), source.getServer()); + } + + + con.endRequest(); + }catch(Exception e){ + e.printStackTrace(); + } + return 0; + } + + private static int nowarp(CommandSourceStack source) { + ChatServerOverride.broadcastTo(source.getPlayer().getUUID(), Component.literal(ChatColor.DARK_RED + "You must supply the warp name. If you need to know what warps are available, please use the warps command, or click this message.").withStyle(Style.EMPTY.withFont(Style.DEFAULT_FONT).withClickEvent(Clickable.command("/warps"))), source.getServer()); + return 0; + } + +} diff --git a/src/main/java/dev/zontreck/otemod/commands/warps/WarpsCommand.java b/src/main/java/dev/zontreck/otemod/commands/warps/WarpsCommand.java new file mode 100644 index 0000000..0a5dec3 --- /dev/null +++ b/src/main/java/dev/zontreck/otemod/commands/warps/WarpsCommand.java @@ -0,0 +1,95 @@ +package dev.zontreck.otemod.commands.warps; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +import com.mojang.brigadier.CommandDispatcher; + +import dev.zontreck.otemod.OTEMod; +import dev.zontreck.otemod.chat.ChatColor; +import dev.zontreck.otemod.chat.ChatServerOverride; +import dev.zontreck.otemod.chat.Clickable; +import dev.zontreck.otemod.chat.HoverTip; +import dev.zontreck.otemod.configs.Profile; +import dev.zontreck.otemod.containers.Vector2; +import dev.zontreck.otemod.containers.Vector3; +import dev.zontreck.otemod.database.TeleportDestination; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.network.chat.ClickEvent; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.HoverEvent; +import net.minecraft.network.chat.Style; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.phys.Vec2; +import net.minecraft.world.phys.Vec3; + +public class WarpsCommand { + + public static void register(CommandDispatcher dispatcher) + { + dispatcher.register(Commands.literal("warps").executes(c-> warps(c.getSource()))); + + //dispatcher.register(Commands.literal("sethome").then(Commands.argument("nickname", StringArgumentType.string())).executes(command -> { + //String arg = StringArgumentType.getString(command, "nickname"); + //return setHome(command.getSource(), arg); + //})); + } + + private static int warps(CommandSourceStack source) { + if(!source.isPlayer()) + { + return 1; + } + + ServerPlayer p = source.getPlayer(); + Connection con = OTEMod.DB.getConnection(); + try{ + // Begin + con.beginRequest(); + PreparedStatement pstat = con.prepareStatement("SELECT * FROM `warps`;"); // We want the warp owner, and the warp type, and name. We don't really care about the teleport properties right now, but a future version will show lore on the tooltip to indicate where it goes + + ResultSet rs = pstat.executeQuery(); + int count=0; + while(rs.next()) + { + // Lets do it! + count++; + } + rs=pstat.executeQuery();// Reset the query + ChatServerOverride.broadcastTo(p.getUUID(), Component.literal(ChatColor.DARK_GRAY+"["+ChatColor.DARK_GREEN+"OTEMOD" + ChatColor.DARK_GRAY+"] "+ChatColor.resetChat() + "There are "+count+" warps available"), source.getServer()); + + while(rs.next()) + { + // This is a warp! + // Pull the owner profile + Profile prof = Profile.get_profile_of(rs.getString("owner")); + String warpName = rs.getString("warpname"); + int warpType = rs.getInt("warptype"); + String appendType = (warpType == 0) ? "standard warp." : "RTP Warp. This has a position randomizer."; + + HoverEvent hover = HoverTip.get(ChatColor.BOLD + ChatColor.DARK_PURPLE + "This warp is a "+appendType); + ClickEvent click = Clickable.command("/warp "+warpName); + Style S = Style.EMPTY.withFont(Style.DEFAULT_FONT).withHoverEvent(hover).withClickEvent(click); + + Component warpMsg = Component.literal(ChatColor.GREEN + warpName + ChatColor.resetChat()).withStyle(S); + + // Now, display the warp name, along with the warp's owner information + HoverEvent h2 = HoverTip.get(prof.name_color+prof.nickname+ChatColor.resetChat()+ChatColor.AQUA+" is the owner of this warp"); + S = Style.EMPTY.withFont(Style.DEFAULT_FONT).withHoverEvent(h2); + Component ownerInfo = Component.literal(ChatColor.GOLD+ " [Hover to see the warp's info]").withStyle(S); + + // Combine the two + warpMsg = Component.literal("").append(warpMsg).append(ownerInfo); + ChatServerOverride.broadcastTo(source.getPlayer().getUUID(), warpMsg, source.getServer()); + } + }catch (Exception E) + { + E.printStackTrace(); + } + return 0; + } + +} diff --git a/src/main/java/dev/zontreck/otemod/containers/Vector2.java b/src/main/java/dev/zontreck/otemod/containers/Vector2.java new file mode 100644 index 0000000..d9878c5 --- /dev/null +++ b/src/main/java/dev/zontreck/otemod/containers/Vector2.java @@ -0,0 +1,69 @@ +package dev.zontreck.otemod.containers; + +import com.ibm.icu.impl.InvalidFormatException; + +import net.minecraft.world.phys.Vec2; +import net.minecraft.world.phys.Vec3; + +public class Vector2 +{ + public float x; + public float y; + + public Vec2 asMinecraftVector(){ + return new Vec2(x, y); + } + + public Vector2() + { + + } + + public Vector2(float x, float y) + { + this.x=x; + this.y=y; + } + + public Vector2(Vec2 pos) + { + x=pos.x; + y=pos.y; + } + + public Vector2(String pos) throws InvalidFormatException + { + // This will be serialized most likely from the ToString method + // Parse + if(pos.startsWith("<")) + { + pos=pos.substring(1, pos.length()-1); // Rip off the ending bracket too + String[] positions = pos.split(", "); + if(positions.length!=2) + { + positions = pos.split(","); + } + + if(positions.length!=2) + { + throw new InvalidFormatException("Positions must be in the same format provided by ToString() (ex. <1,1> or <1, 1>"); + } + + this.x = Float.parseFloat(positions[0]); + this.y = Float.parseFloat(positions[1]); + // We are done now + } + } + + public Vector2 Clone() + { + Vector2 n = new Vector2(x, y); + return n; + } + + @Override + public String toString() + { + return "<"+String.valueOf(x)+", "+String.valueOf(y) + ">"; + } +} diff --git a/src/main/java/dev/zontreck/otemod/containers/Vector3.java b/src/main/java/dev/zontreck/otemod/containers/Vector3.java index a29b810..f4baf37 100644 --- a/src/main/java/dev/zontreck/otemod/containers/Vector3.java +++ b/src/main/java/dev/zontreck/otemod/containers/Vector3.java @@ -1,5 +1,7 @@ package dev.zontreck.otemod.containers; +import com.ibm.icu.impl.InvalidFormatException; + import net.minecraft.world.phys.Vec3; public class Vector3 @@ -31,6 +33,31 @@ public class Vector3 z=pos.z; } + public Vector3(String pos) throws InvalidFormatException + { + // This will be serialized most likely from the ToString method + // Parse + if(pos.startsWith("<")) + { + pos=pos.substring(1, pos.length()-1); // Rip off the ending bracket too + String[] positions = pos.split(", "); + if(positions.length!=3) + { + positions = pos.split(","); + } + + if(positions.length!=3) + { + throw new InvalidFormatException("Positions must be in the same format provided by ToString() (ex. <1,1,1> or <1, 1, 1>"); + } + + this.x = Double.parseDouble(positions[0]); + this.y = Double.parseDouble(positions[1]); + this.z = Double.parseDouble(positions[2]); + // We are done now + } + } + public Vector3 moveUp() { Vector3 up = Clone(); diff --git a/src/main/java/dev/zontreck/otemod/database/TeleportDestination.java b/src/main/java/dev/zontreck/otemod/database/TeleportDestination.java new file mode 100644 index 0000000..8673e60 --- /dev/null +++ b/src/main/java/dev/zontreck/otemod/database/TeleportDestination.java @@ -0,0 +1,43 @@ +package dev.zontreck.otemod.database; + +import com.ibm.icu.impl.InvalidFormatException; + +import dev.zontreck.otemod.containers.Vector2; +import dev.zontreck.otemod.containers.Vector3; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtUtils; + +/** + * This defines the data structure, and methods for deserializing and serializing teleport destinations, for easier storage in the database + **/ +public class TeleportDestination { + public Vector3 Position; + public Vector2 Rotation; + public String Dimension; + + public TeleportDestination(CompoundTag tag) throws InvalidFormatException + { + Position = new Vector3(tag.getString("Position")); + Rotation = new Vector2(tag.getString("Rotation")); + Dimension = tag.getString("Dimension"); + } + public TeleportDestination(Vector3 pos, Vector2 rot, String dim) + { + Position = pos; + Rotation = rot; + Dimension = dim; + } + + @Override + public String toString() + { + CompoundTag tag = new CompoundTag(); + tag.putString("Position", Position.toString()); + tag.putString("Rotation", Rotation.toString()); + tag.putString("Dimension", Dimension); + + return NbtUtils.structureToSnbt(tag); + + } + +} diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index a5a00ff..a1acd85 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -19,7 +19,7 @@ modId="otemod" #mandatory # The version number of the mod - there's a few well known ${} variables useable here or just hardcode it # ${file.jarVersion} will substitute the value of the Implementation-Version as read from the mod's JAR file metadata # see the associated build.gradle script for how to populate this completely automatically during a build -version="1.3.3.3" #mandatory +version="1.3.3.4" #mandatory # A display name for the mod displayName="OTEMod Resources" #mandatory # A URL to query for updates for this mod. See the JSON update specification https://mcforge.readthedocs.io/en/latest/gettingstarted/autoupdate/ diff --git a/src/main/resources/assets/otemod/lang/en_us.json b/src/main/resources/assets/otemod/lang/en_us.json index 4d64a18..fe50715 100644 --- a/src/main/resources/assets/otemod/lang/en_us.json +++ b/src/main/resources/assets/otemod/lang/en_us.json @@ -18,7 +18,8 @@ "block.otemod.aurora_block": "Aurora Block", "block.otemod.aurora_door": "Aurora Door", - "dev.zontreck.otemod.msgs.homes.only_player": "§cOnly players are allowed to execute this command", + "dev.zontreck.otemod.msgs.only_player": "§cOnly players are allowed to execute this command", + "dev.zontreck.otemod.msgs.homes.total": "§3Total number of homes: §6", "dev.zontreck.otemod.msgs.homes.set.success": "§2Home created or updated successfully", "dev.zontreck.otemod.msgs.homes.set.fail": "§cHome could not be created or updated due to an unknown error", @@ -30,6 +31,11 @@ "dev.zontreck.otemod.msgs.command_cooling_down": "This command is currently on cooldown. You must wait for ", "dev.zontreck.otemod.msgs.command_cooling_down_seconds": "seconds.", + "dev.zontreck.otemod.msgs.warps.set.success": "Warp successfully created", + "dev.zontreck.otemod.msgs.warps.del.success": "Warp successfully deleted", + "dev.zontreck.otemod.msgs.warps.set.fail": "Failed to create warp", + "dev.zontreck.otemod.msgs.warps.del.fail": "Failed to delete warp", + "minecraft.player.joined": "", "minecraft.player.joined.renamed": "", "minecraft.player.quit": ""