From f5d7de0b41ef3659c069846ba7bf743c80c2888b Mon Sep 17 00:00:00 2001 From: samo_lego <34912839+samolego@users.noreply.github.com> Date: Thu, 23 Apr 2020 14:57:02 +0200 Subject: [PATCH] Starting with player position protection. RN throws NPE when leaving server --- .../org/samo_lego/simpleauth/SimpleAuth.java | 40 +++++++++- .../simpleauth/commands/AuthCommand.java | 79 +++++++++++++++---- .../simpleauth/event/AuthEventHandler.java | 16 ++-- .../simpleauth/storage/AuthConfig.java | 12 ++- .../simpleauth/storage/PlayerCache.java | 36 ++++++++- 5 files changed, 153 insertions(+), 30 deletions(-) diff --git a/src/main/java/org/samo_lego/simpleauth/SimpleAuth.java b/src/main/java/org/samo_lego/simpleauth/SimpleAuth.java index e9db4f4..f1198b5 100644 --- a/src/main/java/org/samo_lego/simpleauth/SimpleAuth.java +++ b/src/main/java/org/samo_lego/simpleauth/SimpleAuth.java @@ -6,9 +6,11 @@ import net.fabricmc.fabric.api.event.server.ServerStopCallback; import net.fabricmc.fabric.api.registry.CommandRegistry; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.LiteralText; import net.minecraft.text.Text; +import net.minecraft.world.dimension.DimensionType; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.samo_lego.simpleauth.commands.*; @@ -109,7 +111,11 @@ public class SimpleAuth implements DedicatedServerModInitializer { // Authenticates player and sends the message public static void authenticatePlayer(ServerPlayerEntity player, Text msg) { + // Teleporting player back + teleportPlayer(player, false); + deauthenticatedUsers.remove(convertUuid(player)); + // Player no longer needs to be invisible and invulnerable player.setInvulnerable(false); player.setInvisible(false); @@ -120,9 +126,12 @@ public class SimpleAuth implements DedicatedServerModInitializer { public static void deauthenticatePlayer(ServerPlayerEntity player) { if(db.isClosed()) return; + // Marking player as not authenticated, (re)setting login tries to zero String uuid = convertUuid(player); - SimpleAuth.deauthenticatedUsers.put(uuid, new PlayerCache(uuid, player.getIp())); + SimpleAuth.deauthenticatedUsers.put(uuid, new PlayerCache(uuid, player)); + // Teleporting player to spawn to hide its position + teleportPlayer(player, true); // Player is now not authenticated player.sendMessage(notAuthenticated(), false); @@ -144,4 +153,33 @@ public class SimpleAuth implements DedicatedServerModInitializer { // We ask CarpetHelper class since it has the imports needed return FabricLoader.getInstance().isModLoaded("carpet") && isPlayerCarpetFake(player); } + + // Teleports player to spawn or last location when authenticating + public static void teleportPlayer(ServerPlayerEntity player, boolean toSpawn) { + if(config.main.spawnOnJoin) { + MinecraftServer server = player.getServer(); + assert server != null; + if (toSpawn) { + // Teleports player to spawn + player.teleport( + server.getWorld(DimensionType.byRawId(config.worldSpawn.dimensionId)), + config.worldSpawn.x, + config.worldSpawn.y, + config.worldSpawn.z, + 0, + 0 + ); + return; + } + PlayerCache cache = deauthenticatedUsers.get(convertUuid(player)); + // Puts player to last cached position + player.setWorld(server.getWorld(DimensionType.byRawId(cache.lastDimId))); + player.setPos( + cache.lastX, + cache.lastY, + cache.lastZ + ); + player.updateNeeded = true; + } + } } \ No newline at end of file diff --git a/src/main/java/org/samo_lego/simpleauth/commands/AuthCommand.java b/src/main/java/org/samo_lego/simpleauth/commands/AuthCommand.java index c9d5af1..56d7f8d 100644 --- a/src/main/java/org/samo_lego/simpleauth/commands/AuthCommand.java +++ b/src/main/java/org/samo_lego/simpleauth/commands/AuthCommand.java @@ -15,19 +15,24 @@ import org.samo_lego.simpleauth.storage.PlayerCache; import org.samo_lego.simpleauth.utils.AuthHelper; import java.io.File; +import java.util.Objects; +import static com.mojang.brigadier.arguments.IntegerArgumentType.getInteger; +import static com.mojang.brigadier.arguments.IntegerArgumentType.integer; import static com.mojang.brigadier.arguments.StringArgumentType.getString; import static com.mojang.brigadier.arguments.StringArgumentType.word; import static net.minecraft.server.command.CommandManager.argument; import static net.minecraft.server.command.CommandManager.literal; +import static org.samo_lego.simpleauth.SimpleAuth.config; +import static org.samo_lego.simpleauth.SimpleAuth.db; public class AuthCommand { private static final Logger LOGGER = LogManager.getLogger(); - private static Text userdataDeleted = new LiteralText(SimpleAuth.config.lang.userdataDeleted); - private static Text userdataUpdated = new LiteralText(SimpleAuth.config.lang.userdataUpdated); - private static Text configurationReloaded = new LiteralText(SimpleAuth.config.lang.configurationReloaded); - private static Text globalPasswordSet = new LiteralText(SimpleAuth.config.lang.globalPasswordSet); + private static Text userdataDeleted = new LiteralText(config.lang.userdataDeleted); + private static Text userdataUpdated = new LiteralText(config.lang.userdataUpdated); + private static Text configurationReloaded = new LiteralText(config.lang.configurationReloaded); + private static Text globalPasswordSet = new LiteralText(config.lang.globalPasswordSet); public static void registerCommand(CommandDispatcher dispatcher) { // Registering the "/auth" command @@ -44,6 +49,32 @@ public class AuthCommand { )) ) ) + .then(literal("setSpawn") + .then(argument("here", word()) + .executes( ctx -> setSpawn( + ctx.getSource(), + Objects.requireNonNull(ctx.getSource().getEntity()).dimension.getRawId(), + ctx.getSource().getEntity().getX(), + ctx.getSource().getEntity().getY(), + ctx.getSource().getEntity().getZ() + )) + ) + .then(argument("dimensionId", integer()) + .then(argument("x", integer()) + .then(argument("y", integer()) + .then(argument("z", integer()) + .executes( ctx -> setSpawn( + ctx.getSource(), + getInteger(ctx, "dimensionId"), + getInteger(ctx, "x"), + getInteger(ctx, "y"), + getInteger(ctx, "z") + )) + ) + ) + ) + ) + ) .then(literal("remove") .then(argument("uuid", word()) .executes( ctx -> removeAccount( @@ -80,12 +111,12 @@ public class AuthCommand { // Reloading the config private static int reloadConfig(ServerCommandSource source) { Entity sender = source.getEntity(); - SimpleAuth.config = AuthConfig.load(new File("./mods/SimpleAuth/config.json")); + config = AuthConfig.load(new File("./mods/SimpleAuth/config.json")); if(sender != null) ((PlayerEntity) sender).sendMessage(configurationReloaded, false); else - LOGGER.info(SimpleAuth.config.lang.configurationReloaded); + LOGGER.info(config.lang.configurationReloaded); return 1; } @@ -94,27 +125,41 @@ public class AuthCommand { // Getting the player who send the command Entity sender = source.getEntity(); // Writing the global pass to config - SimpleAuth.config.main.globalPassword = AuthHelper.hashPass(pass.toCharArray()); - SimpleAuth.config.main.enableGlobalPassword = true; - SimpleAuth.config.save(new File("./mods/SimpleAuth/config.json")); + config.main.globalPassword = AuthHelper.hashPass(pass.toCharArray()); + config.main.enableGlobalPassword = true; + config.save(new File("./mods/SimpleAuth/config.json")); if(sender != null) ((PlayerEntity) sender).sendMessage(globalPasswordSet, false); else - LOGGER.info(SimpleAuth.config.lang.globalPasswordSet); + LOGGER.info(config.lang.globalPasswordSet); + return 1; + } + + // + private static int setSpawn(ServerCommandSource source, int dimensionId, double x, double y, double z) { + config.worldSpawn.dimensionId = dimensionId; + config.worldSpawn.x = x; + config.worldSpawn.y = y; + config.worldSpawn.z = z; + Entity sender = source.getEntity(); + if(sender != null) + sender.sendSystemMessage(new LiteralText(config.lang.worldSpawnSet)); + else + LOGGER.info(config.lang.worldSpawnSet); return 1; } // Deleting (unregistering) user's account private static int removeAccount(ServerCommandSource source, String uuid) { Entity sender = source.getEntity(); - SimpleAuth.db.deleteUserData(uuid); - SimpleAuth.deauthenticatedUsers.put(uuid, new PlayerCache(uuid, "")); + db.deleteUserData(uuid); + SimpleAuth.deauthenticatedUsers.put(uuid, new PlayerCache(uuid, null)); if(sender != null) ((PlayerEntity) sender).sendMessage(userdataDeleted, false); else - LOGGER.info(SimpleAuth.config.lang.userdataDeleted); + LOGGER.info(config.lang.userdataDeleted); return 1; // Success } @@ -128,11 +173,11 @@ public class AuthCommand { String hash = AuthHelper.hashPass(password.toCharArray()); playerdata.addProperty("password", hash); - if(SimpleAuth.db.registerUser(uuid, playerdata.toString())) { + if(db.registerUser(uuid, playerdata.toString())) { if(sender != null) ((PlayerEntity) sender).sendMessage(userdataUpdated, false); else - LOGGER.info(SimpleAuth.config.lang.userdataUpdated); + LOGGER.info(config.lang.userdataUpdated); return 1; } return 0; @@ -148,11 +193,11 @@ public class AuthCommand { String hash = AuthHelper.hashPass(password.toCharArray()); playerdata.addProperty("password", hash); - SimpleAuth.db.updateUserData(uuid, playerdata.toString()); + db.updateUserData(uuid, playerdata.toString()); if(sender != null) ((PlayerEntity) sender).sendMessage(userdataUpdated, false); else - LOGGER.info(SimpleAuth.config.lang.userdataUpdated); + LOGGER.info(config.lang.userdataUpdated); return 1; } // todo PlayerEntity.getOfflinePlayerUuid("") diff --git a/src/main/java/org/samo_lego/simpleauth/event/AuthEventHandler.java b/src/main/java/org/samo_lego/simpleauth/event/AuthEventHandler.java index ccd1a46..5db809d 100644 --- a/src/main/java/org/samo_lego/simpleauth/event/AuthEventHandler.java +++ b/src/main/java/org/samo_lego/simpleauth/event/AuthEventHandler.java @@ -71,6 +71,7 @@ public class AuthEventHandler { return null; } + // Player joining the server public static void onPlayerJoin(ServerPlayerEntity player) { // If player is fake auth is not needed @@ -89,8 +90,7 @@ public class AuthEventHandler { deauthenticatedUsers.remove(uuid); // Makes player authenticated return; } - else - deauthenticatePlayer(player); + deauthenticatePlayer(player); // Tries to rescue player from nether portal if(config.main.tryPortalRescue && player.getBlockState().getBlock().equals(Blocks.NETHER_PORTAL)) { @@ -163,11 +163,13 @@ public class AuthEventHandler { } public static void onPlayerLeave(ServerPlayerEntity player) { - if( - !isAuthenticated(player) || - config.main.sessionTimeoutTime == -1 || - isPlayerFake(player) - ) + if(isPlayerFake(player)) + return; + + // Teleporting player back + teleportPlayer(player, false); + + if(!isAuthenticated(player) || config.main.sessionTimeoutTime == -1) return; // Starting session diff --git a/src/main/java/org/samo_lego/simpleauth/storage/AuthConfig.java b/src/main/java/org/samo_lego/simpleauth/storage/AuthConfig.java index 784c676..d5e252f 100644 --- a/src/main/java/org/samo_lego/simpleauth/storage/AuthConfig.java +++ b/src/main/java/org/samo_lego/simpleauth/storage/AuthConfig.java @@ -40,7 +40,7 @@ public class AuthConfig { // Disables registering and forces logging in with global password // Visit https://github.com/samolego/SimpleAuth/wiki/Locking-server-with-global-password for more info public boolean enableGlobalPassword = false; - public String globalPassword = null; + public String globalPassword; // Tries to rescue players if they are stuck inside a portal on logging in // Visit https://github.com/samolego/SimpleAuth/wiki/Portal-Rescue for more info public boolean tryPortalRescue = true; @@ -54,6 +54,14 @@ public class AuthConfig { // Set to -1 to disable // Visit https://github.com/samolego/SimpleAuth/wiki/Sessions for more info public int sessionTimeoutTime = 60; + + public boolean spawnOnJoin = false; + public static class WorldSpawn { + public int dimensionId; + public double x; + public double y; + public double z; + }; } public static class LangConfig { public String enterPassword = "§6You need to enter your password!"; @@ -83,6 +91,7 @@ public class AuthConfig { public String minPasswordChars = "§6Password needs to be at least %d characters long!"; public String disallowedUsername = "§6Invalid username characters! Allowed character regex: %s"; public String playerAlreadyOnline = "§cPlayer %s is already online!"; + public String worldSpawnSet = ""; } public static class ExperimentalConfig { // Prevents player being kicked because another player with the same name has joined the server @@ -114,6 +123,7 @@ public class AuthConfig { .create(); public MainConfig main = new MainConfig(); + public MainConfig.WorldSpawn worldSpawn = new MainConfig.WorldSpawn(); public LangConfig lang = new LangConfig(); public ExperimentalConfig experimental = new ExperimentalConfig(); diff --git a/src/main/java/org/samo_lego/simpleauth/storage/PlayerCache.java b/src/main/java/org/samo_lego/simpleauth/storage/PlayerCache.java index 0fbfd69..4b2a1f1 100644 --- a/src/main/java/org/samo_lego/simpleauth/storage/PlayerCache.java +++ b/src/main/java/org/samo_lego/simpleauth/storage/PlayerCache.java @@ -2,7 +2,10 @@ package org.samo_lego.simpleauth.storage; import com.google.gson.JsonObject; import com.google.gson.JsonParser; -import org.samo_lego.simpleauth.SimpleAuth; +import net.minecraft.server.network.ServerPlayerEntity; + +import static org.samo_lego.simpleauth.SimpleAuth.config; +import static org.samo_lego.simpleauth.SimpleAuth.db; public class PlayerCache { public boolean isRegistered; @@ -11,15 +14,40 @@ public class PlayerCache { public int loginTries; public String lastIp; public long validUntil; + + public int lastDimId; + public double lastX; + public double lastY; + public double lastZ; + private static final JsonParser parser = new JsonParser(); - public PlayerCache(String uuid, String ip) { - SimpleAuthDatabase db = SimpleAuth.db; + public PlayerCache(String uuid, ServerPlayerEntity player) { + if(db.isClosed()) + return; + if(player != null) { + this.lastIp = player.getIp(); + + // Setting last coordinates + this.lastDimId = player.dimension.getRawId(); + this.lastX = player.getX(); + this.lastY = player.getY(); + this.lastZ = player.getZ(); + } + else { + this.lastIp = ""; + + // Setting last coordinates + this.lastDimId = config.worldSpawn.dimensionId; + this.lastX = config.worldSpawn.x; + this.lastY = config.worldSpawn.y; + this.lastZ = config.worldSpawn.z; + } this.wasAuthenticated = false; this.loginTries = 0; - this.lastIp = ip; + if(db.isUserRegistered(uuid)) { this.isRegistered = true;