diff --git a/src/main/java/MelonUtilities/command/commandlogic/CommandLogicSpawn.java b/src/main/java/MelonUtilities/command/commandlogic/CommandLogicSpawn.java new file mode 100644 index 0000000..469d49b --- /dev/null +++ b/src/main/java/MelonUtilities/command/commandlogic/CommandLogicSpawn.java @@ -0,0 +1,43 @@ +package MelonUtilities.command.commandlogic; + +import MelonUtilities.config.Data; +import MelonUtilities.config.datatypes.data.Spawn; +import MelonUtilities.utility.MUtil; +import MelonUtilities.utility.feedback.FeedbackArg; +import MelonUtilities.utility.feedback.FeedbackHandlerServer; +import MelonUtilities.utility.feedback.FeedbackType; +import com.mojang.brigadier.Command; +import net.minecraft.server.entity.player.PlayerServer; + +public class CommandLogicSpawn { + public static int spawnTP(PlayerServer sender){ + if (Data.MainConfig.config.spawnData == null){ + FeedbackHandlerServer.sendFeedback(FeedbackType.error, sender, "Spawn isn't set"); + } else { + FeedbackHandlerServer.sendFeedback(FeedbackType.success, sender, "Teleporting to Spawn"); + MUtil.sendToSpawn(sender); + } + + return Command.SINGLE_SUCCESS; + } + + public static int spawnReset(PlayerServer sender){ + if (Data.MainConfig.config.spawnData == null){ + FeedbackHandlerServer.sendFeedback(FeedbackType.error, sender, "Spawn isn't set"); + } else { + Data.MainConfig.config.spawnData = null; + Data.MainConfig.save(); + FeedbackHandlerServer.sendFeedback(FeedbackType.destructive, sender, "Deleted Spawn"); + } + + return Command.SINGLE_SUCCESS; + } + + public static int spawnSet(PlayerServer sender){ + Spawn spawn = new Spawn(sender.x, sender.y, sender.z, sender.dimension); + Data.MainConfig.config.spawnData = spawn; + Data.MainConfig.save(); + FeedbackHandlerServer.sendFeedback(FeedbackType.success, sender, "Set Spawn to %s", new FeedbackArg(spawn)); + return Command.SINGLE_SUCCESS; + } +} diff --git a/src/main/java/MelonUtilities/command/commands/CommandSpawn.java b/src/main/java/MelonUtilities/command/commands/CommandSpawn.java new file mode 100644 index 0000000..1c771a1 --- /dev/null +++ b/src/main/java/MelonUtilities/command/commands/CommandSpawn.java @@ -0,0 +1,64 @@ +package MelonUtilities.command.commands; + +import MelonUtilities.command.commandlogic.CommandLogicSpawn; +import MelonUtilities.config.Data; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.builder.ArgumentBuilderLiteral; +import com.mojang.brigadier.builder.ArgumentBuilderRequired; +import net.minecraft.core.net.command.CommandManager; +import net.minecraft.core.net.command.CommandSource; +import net.minecraft.server.entity.player.PlayerServer; + +@SuppressWarnings("UnusedReturnValue") +public class CommandSpawn implements CommandManager.CommandRegistry{ + public static ArgumentBuilder> spawn(ArgumentBuilder> builder) { + builder.then(ArgumentBuilderLiteral.literal("")).executes(context -> + { + PlayerServer sender = (PlayerServer) context.getSource().getSender(); if(sender == null){return 0;} + + return CommandLogicSpawn.spawnTP(sender); + } + ); + return builder; + } + + public static ArgumentBuilder> spawnSet(ArgumentBuilder> builder) { + builder.then(ArgumentBuilderLiteral.literal("set").requires(CommandSource::hasAdmin) + .executes(context -> + { + PlayerServer sender = (PlayerServer) context.getSource().getSender(); if(sender == null){return 0;} + + return CommandLogicSpawn.spawnSet(sender); + } + ) + ); + return builder; + } + + public static ArgumentBuilder> spawnReset(ArgumentBuilder> builder) { + builder.then(ArgumentBuilderLiteral.literal("reset").requires(CommandSource::hasAdmin) + .executes(context -> + { + PlayerServer sender = (PlayerServer) context.getSource().getSender(); if(sender == null){return 0;} + + return CommandLogicSpawn.spawnReset(sender); + } + ) + ); + return builder; + } + + + + @Override + public void register(CommandDispatcher dispatcher) { + ArgumentBuilderLiteral builder = ArgumentBuilderLiteral.literal("spawn"); + + spawn(builder); + spawnSet(builder); + spawnReset(builder); + + dispatcher.register(builder); + } +} diff --git a/src/main/java/MelonUtilities/config/Data.java b/src/main/java/MelonUtilities/config/Data.java index bafed55..23322d6 100644 --- a/src/main/java/MelonUtilities/config/Data.java +++ b/src/main/java/MelonUtilities/config/Data.java @@ -27,6 +27,7 @@ public class Data { .registerTypeAdapter(User.class, new UserJsonAdapter()) .registerTypeAdapter(Home.class, new HomeJsonAdapter()) .registerTypeAdapter(Warp.class, new WarpJsonAdapter()) + .registerTypeAdapter(Spawn.class, new SpawnJsonAdapter()) .setPrettyPrinting().create(); public static class Roles { diff --git a/src/main/java/MelonUtilities/config/datatypes/data/Config.java b/src/main/java/MelonUtilities/config/datatypes/data/Config.java index 160eda1..f8c516c 100644 --- a/src/main/java/MelonUtilities/config/datatypes/data/Config.java +++ b/src/main/java/MelonUtilities/config/datatypes/data/Config.java @@ -15,6 +15,7 @@ public class Config { public boolean enableTPA = true; public boolean enableWarps = true; public boolean enableHomes = true; + public boolean enableSpawn = true; public boolean enableElevators = true; public boolean enableKits = true; public boolean enableRules = true; @@ -54,5 +55,6 @@ public class Config { public String serverPFPURL = "https://i.imgur.com/dJUId0O.png"; public String serverName = "BTA! Server"; + public Spawn spawnData; public List warpData = new ArrayList<>(); } diff --git a/src/main/java/MelonUtilities/config/datatypes/data/Spawn.java b/src/main/java/MelonUtilities/config/datatypes/data/Spawn.java new file mode 100644 index 0000000..778b127 --- /dev/null +++ b/src/main/java/MelonUtilities/config/datatypes/data/Spawn.java @@ -0,0 +1,44 @@ +package MelonUtilities.config.datatypes.data; + +import net.minecraft.core.net.command.TextFormatting; +import net.minecraft.core.world.Dimension; + +public class Spawn { + public double x; + public double y; + public double z; + public int dimID; + + public Spawn(double x, double y, double z, int dimID) { + this.x = x; + this.y = y; + this.z = z; + this.dimID = dimID; + } + + @Override + public String toString(){ + return String.format("%d %d %d", (int) x, (int) y, (int) z); + } + + public String toDescriptiveString(){ + String dimensionName = Dimension.getDimensionList().get(dimID).languageKey; + dimensionName = Character.toUpperCase(dimensionName.charAt(0)) + dimensionName.substring(1); + TextFormatting dimColor = TextFormatting.LIGHT_GRAY; + if(dimID == Dimension.OVERWORLD.id){ + dimColor = TextFormatting.LIME; + } else if(dimID == Dimension.NETHER.id){ + dimColor = TextFormatting.RED; + } else if(dimID == Dimension.PARADISE.id){ + dimColor = TextFormatting.LIGHT_BLUE; + } + + return String.format( + TextFormatting.GRAY + "[SPAWN] [" + + dimColor + "%s" + + TextFormatting.GRAY + "] [" + + TextFormatting.LIGHT_GRAY + "x: %.1f y: %.1f z: %.1f" + + TextFormatting.GRAY + "]", + dimensionName, x, y, z); + } +} diff --git a/src/main/java/MelonUtilities/config/datatypes/jsonadapters/ConfigJsonAdapter.java b/src/main/java/MelonUtilities/config/datatypes/jsonadapters/ConfigJsonAdapter.java index 72ccf6a..39b1ee9 100644 --- a/src/main/java/MelonUtilities/config/datatypes/jsonadapters/ConfigJsonAdapter.java +++ b/src/main/java/MelonUtilities/config/datatypes/jsonadapters/ConfigJsonAdapter.java @@ -2,6 +2,7 @@ import MelonUtilities.MelonUtilities; import MelonUtilities.config.datatypes.data.Config; +import MelonUtilities.config.datatypes.data.Spawn; import MelonUtilities.config.datatypes.data.Warp; import MelonUtilities.config.datatypes.legacydeserializers.ConfigLDs; import com.google.gson.*; @@ -29,6 +30,7 @@ public Config deserialize(JsonElement json, Type typeOfT, JsonDeserializationCon JsonObject elevatorConfig = obj.getAsJsonObject("Elevator Config"); JsonObject sqlLogConfig = obj.getAsJsonObject("SQL Log Config"); JsonObject warpConfig = obj.getAsJsonObject("Warp Data"); + JsonObject spawnConfig = obj.getAsJsonObject("Spawn Data"); JsonObject discordIntegrationConfig = obj.getAsJsonObject("Discord Integration Config"); @@ -39,6 +41,7 @@ public Config deserialize(JsonElement json, Type typeOfT, JsonDeserializationCon config.enableTPA = mainConfig.get("enableTPA").getAsBoolean(); config.enableHomes = mainConfig.get("enableHomes").getAsBoolean(); config.enableWarps = mainConfig.get("enableWarps").getAsBoolean(); + config.enableSpawn = mainConfig.get("enableSpawn").getAsBoolean(); config.enableElevators = mainConfig.get("enableElevators").getAsBoolean(); config.enableKits = mainConfig.get("enableKits").getAsBoolean(); config.enableRules = mainConfig.get("enableRules").getAsBoolean(); @@ -93,6 +96,11 @@ public Config deserialize(JsonElement json, Type typeOfT, JsonDeserializationCon } } + //Spawn Options + if(spawnConfig != null){ + config.spawnData = context.deserialize(spawnConfig.getAsJsonObject("spawn"), Spawn.class); + } + return config; } @@ -108,6 +116,7 @@ public JsonElement serialize(Config src, Type typeOfSrc, JsonSerializationContex JsonObject elevatorConfig = new JsonObject(); JsonObject sqlLogConfig = new JsonObject(); JsonObject warpConfig = new JsonObject(); + JsonObject spawnConfig = new JsonObject(); JsonObject discordIntegrationConfig = new JsonObject(); mainConfig.addProperty("enableContainerLocking", src.enableContainerLocking); @@ -116,6 +125,7 @@ public JsonElement serialize(Config src, Type typeOfSrc, JsonSerializationContex mainConfig.addProperty("enableTPA", src.enableTPA); mainConfig.addProperty("enableHomes", src.enableHomes); mainConfig.addProperty("enableWarps", src.enableWarps); + mainConfig.addProperty("enableSpawn", src.enableSpawn); mainConfig.addProperty("enableElevators", src.enableElevators); mainConfig.addProperty("enableKits", src.enableKits); mainConfig.addProperty("enableRules", src.enableRules); @@ -168,6 +178,9 @@ public JsonElement serialize(Config src, Type typeOfSrc, JsonSerializationContex warpConfig.add("warps", warps); obj.add("Warp Data", warpConfig); + spawnConfig.add("spawn", context.serialize(src.spawnData)); + obj.add("Spawn Data", spawnConfig); + return obj; } diff --git a/src/main/java/MelonUtilities/config/datatypes/jsonadapters/SpawnJsonAdapter.java b/src/main/java/MelonUtilities/config/datatypes/jsonadapters/SpawnJsonAdapter.java new file mode 100644 index 0000000..6e9d0d4 --- /dev/null +++ b/src/main/java/MelonUtilities/config/datatypes/jsonadapters/SpawnJsonAdapter.java @@ -0,0 +1,28 @@ +package MelonUtilities.config.datatypes.jsonadapters; + +import MelonUtilities.config.datatypes.data.Spawn; +import com.google.gson.*; + +import java.lang.reflect.Type; + +public class SpawnJsonAdapter implements JsonDeserializer, JsonSerializer { + + @Override + public Spawn deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + JsonObject obj = json.getAsJsonObject(); + return new Spawn(obj.get("x").getAsDouble(), obj.get("y").getAsDouble(), obj.get("z").getAsDouble(), obj.get("dimID").getAsInt()); + } + + @Override + public JsonElement serialize(Spawn src, Type typeOfSrc, JsonSerializationContext context) { + JsonObject obj = new JsonObject(); + obj.addProperty("x", src.x); + obj.addProperty("y", src.y); + obj.addProperty("z", src.z); + obj.addProperty("dimID", src.dimID); + return obj; + } + + + +} diff --git a/src/main/java/MelonUtilities/mixins/PlayerServerMixin.java b/src/main/java/MelonUtilities/mixins/PlayerServerMixin.java new file mode 100644 index 0000000..dfb3af6 --- /dev/null +++ b/src/main/java/MelonUtilities/mixins/PlayerServerMixin.java @@ -0,0 +1,29 @@ +package MelonUtilities.mixins; + +import MelonUtilities.config.Data; +import MelonUtilities.config.datatypes.data.Spawn; +import net.minecraft.server.entity.player.PlayerServer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(value = PlayerServer.class, remap = false) +public class PlayerServerMixin { + + /** + * @author ipiepiepie + * @reason removing randomized spawn point + */ + @Redirect( + method = "", + at = @At(value = "INVOKE", target = "Lnet/minecraft/server/entity/player/PlayerServer;moveTo(DDDFF)V") + ) + private void setSpawn(PlayerServer instance, double x, double y, double z, float yRot, float xRot) { + Spawn spawn = Data.MainConfig.config.spawnData; + if (spawn != null && Data.MainConfig.config.enableSpawn) + instance.moveTo(spawn.x, spawn.y, spawn.z, yRot, xRot); + else + instance.moveTo(x, y, z, yRot, xRot); + } + +} diff --git a/src/main/java/MelonUtilities/mixins/SpawnCommandMixin.java b/src/main/java/MelonUtilities/mixins/SpawnCommandMixin.java new file mode 100644 index 0000000..d97dcf9 --- /dev/null +++ b/src/main/java/MelonUtilities/mixins/SpawnCommandMixin.java @@ -0,0 +1,32 @@ +package MelonUtilities.mixins; + +import MelonUtilities.config.Data; +import com.mojang.brigadier.CommandDispatcher; +import net.minecraft.core.net.command.CommandSource; +import net.minecraft.core.net.command.commands.CommandSpawn; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(value = CommandSpawn.class, remap = false) +public class SpawnCommandMixin { + + /** + * @author ipiepiepie + * @reason override default spawn command, which accessible only for admins. + */ + @Inject( + method = "register", + at = @At("HEAD"), + cancellable = true + ) + private void setSpawn(CommandDispatcher dispatcher, CallbackInfo ci) { + if(!Data.MainConfig.config.enableSpawn) return; + + new MelonUtilities.command.commands.CommandSpawn().register(dispatcher); + + ci.cancel(); + } + +} diff --git a/src/main/java/MelonUtilities/utility/MUtil.java b/src/main/java/MelonUtilities/utility/MUtil.java index df6565f..6185958 100644 --- a/src/main/java/MelonUtilities/utility/MUtil.java +++ b/src/main/java/MelonUtilities/utility/MUtil.java @@ -3,6 +3,7 @@ import MelonUtilities.MelonUtilities; import MelonUtilities.config.Data; import MelonUtilities.config.datatypes.data.Home; +import MelonUtilities.config.datatypes.data.Spawn; import MelonUtilities.config.datatypes.data.Warp; import MelonUtilities.interfaces.Lockable; import MelonUtilities.interfaces.PlayerMagnetInterface; @@ -447,6 +448,14 @@ public static TileEntityChest getOtherChest(World world, TileEntityChest chest){ return null; } + public static void sendToSpawn(Player player) { + Spawn spawn = Data.MainConfig.config.spawnData; + + if(spawn == null) return; + + teleport(spawn.x, spawn.y, spawn.z, player, Dimension.getDimensionList().get(spawn.dimID)); + } + public static void sendToHome(Player player, Home home) { teleport(home.x, home.y, home.z, player, Dimension.getDimensionList().get(home.dimID)); } diff --git a/src/main/resources/MelonUtilities.mixins.json b/src/main/resources/MelonUtilities.mixins.json index 12fd6e3..fa3cef4 100644 --- a/src/main/resources/MelonUtilities.mixins.json +++ b/src/main/resources/MelonUtilities.mixins.json @@ -5,6 +5,7 @@ "compatibilityLevel": "JAVA_8", "mixins": [ "CommandManagerMixin", + "SpawnCommandMixin" "PaintBrushMixin", "PlayerMixinElevator" ], @@ -28,6 +29,7 @@ "PlayerListMixin", "PlayerMixinInputInterface", "PlayerMixinMagnet", + "PlayerServerMixin", "ServerPlayerControllerMixin", "WorldMixin", "tile_entities.activator.BlockLogicActivatorMixin",