From 40dd58d610fcef3c5b25ce1222687dc975b3ea33 Mon Sep 17 00:00:00 2001 From: Ceikry Date: Sun, 19 Jun 2022 23:20:01 +0000 Subject: [PATCH] Fixed many issues with login Reconnecting to an existing session can no longer cause an account wipe Player saves can no longer be saved unless they've already been parsed Sessions now have their most recent ping properly set Sessions can now recover from a hypothetical scenario where the session's player reference becomes null but the player is still in-game Players now disconnected properly if no packets have been received from the client in the last 20 seconds --- .../core/game/node/entity/player/Player.java | 5 ----- .../entity/player/info/PlayerDetails.java | 3 +++ .../entity/skill/hunter/HunterManager.java | 1 + .../main/java/core/net/IoEventHandler.java | 17 ++++++++++++----- Server/src/main/java/core/net/IoSession.java | 6 ++++++ .../entity/player/info/login/LoginParser.kt | 15 +++++++++------ .../player/info/login/PlayerSaveParser.kt | 1 + .../entity/player/info/login/PlayerSaver.kt | 1 + .../rs09/game/world/repository/Repository.kt | 2 ++ .../kotlin/rs09/net/event/LoginReadEvent.kt | 1 + .../main/kotlin/rs09/net/packet/in/Login.kt | 14 +++++++++++--- .../kotlin/rs09/worker/MajorUpdateWorker.kt | 19 +++++++++---------- 12 files changed, 56 insertions(+), 29 deletions(-) diff --git a/Server/src/main/java/core/game/node/entity/player/Player.java b/Server/src/main/java/core/game/node/entity/player/Player.java index e2abd8bd8..88d88d352 100644 --- a/Server/src/main/java/core/game/node/entity/player/Player.java +++ b/Server/src/main/java/core/game/node/entity/player/Player.java @@ -350,7 +350,6 @@ public class Player extends Entity { if (!artificial) { getProperties().setSpawnLocation(ServerConstants.HOME_LOCATION); getDetails().getSession().setObject(this); - getDetails().getSession().setLastPing(System.currentTimeMillis() + 10_000L); } super.init(); LoginConfiguration.configureLobby(this); @@ -474,10 +473,6 @@ public class Player extends Entity { getAudioManager().send(2607); } } - if (!artificial && (System.currentTimeMillis() - getSession().getLastPing()) > 20_000L) { - details.getSession().disconnect(); - getSession().setLastPing(Long.MAX_VALUE); - } if(getAttribute("infinite-special", false)) { settings.setSpecialEnergy(100); } diff --git a/Server/src/main/java/core/game/node/entity/player/info/PlayerDetails.java b/Server/src/main/java/core/game/node/entity/player/info/PlayerDetails.java index 8924a1a08..2221223d4 100644 --- a/Server/src/main/java/core/game/node/entity/player/info/PlayerDetails.java +++ b/Server/src/main/java/core/game/node/entity/player/info/PlayerDetails.java @@ -40,6 +40,8 @@ public class PlayerDetails { */ private IoSession session; + public boolean saveParsed = false; + /** * Constructs a new {@code PlayerDetails}. * @param username the username to set. @@ -253,6 +255,7 @@ public class PlayerDetails { } public void save() { + if(!saveParsed) return; if(isBanned()) return; try { accountInfo.setContacts(communicationInfo.getContactString()); diff --git a/Server/src/main/java/core/game/node/entity/skill/hunter/HunterManager.java b/Server/src/main/java/core/game/node/entity/skill/hunter/HunterManager.java index a30f87f3c..357ac6423 100644 --- a/Server/src/main/java/core/game/node/entity/skill/hunter/HunterManager.java +++ b/Server/src/main/java/core/game/node/entity/skill/hunter/HunterManager.java @@ -54,6 +54,7 @@ public final class HunterManager implements LoginListener, LogoutListener, Event @Override public void logout(@NotNull Player player) { HunterManager instance = getInstance(player); + if (instance == null) return; Iterator iterator = instance.traps.iterator(); TrapWrapper wrapper = null; while (iterator.hasNext()) { diff --git a/Server/src/main/java/core/net/IoEventHandler.java b/Server/src/main/java/core/net/IoEventHandler.java index 93adb6918..dfcd684db 100644 --- a/Server/src/main/java/core/net/IoEventHandler.java +++ b/Server/src/main/java/core/net/IoEventHandler.java @@ -61,12 +61,19 @@ public class IoEventHandler { ReadableByteChannel channel = (ReadableByteChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(100_000); IoSession session = (IoSession) key.attachment(); - if (channel.read(buffer) == -1) { - if(session != null && session.getPlayer() != null){ - Repository.getDisconnectionQueue().add(session.getPlayer()); + try { + if (channel.read(buffer) == -1) { + if (session != null && session.getPlayer() != null) { + Repository.getDisconnectionQueue().add(session.getPlayer()); + } + key.cancel(); + return; } - key.cancel(); - return; + } catch (IOException e) { + if (e.getMessage().contains("reset by peer")) { + session.disconnect(); + session.getPlayer().clear(true); + } else e.printStackTrace(); } buffer.flip(); if (session == null) { diff --git a/Server/src/main/java/core/net/IoSession.java b/Server/src/main/java/core/net/IoSession.java index 1f2e74078..61c2e2f3c 100644 --- a/Server/src/main/java/core/net/IoSession.java +++ b/Server/src/main/java/core/net/IoSession.java @@ -9,6 +9,7 @@ import rs09.auth.AuthResponse; import rs09.game.world.GameWorld; import core.net.producer.HSEventProducer; import core.net.producer.LoginEventProducer; +import rs09.game.world.repository.Repository; import java.io.IOException; import java.nio.ByteBuffer; @@ -114,6 +115,8 @@ public class IoSession { */ private ClientInfo clientInfo; + public String associatedUsername; + /** * Constructs a new {@code IoSession}. * @param key The selection key. @@ -329,6 +332,9 @@ public class IoSession { * @return The player. */ public Player getPlayer() { + if (object == null) { + object = Repository.getPlayerByName(associatedUsername); + } return object instanceof Player ? ((Player) object) : null; } diff --git a/Server/src/main/kotlin/rs09/game/node/entity/player/info/login/LoginParser.kt b/Server/src/main/kotlin/rs09/game/node/entity/player/info/login/LoginParser.kt index 58e1d9201..f44e68f5b 100644 --- a/Server/src/main/kotlin/rs09/game/node/entity/player/info/login/LoginParser.kt +++ b/Server/src/main/kotlin/rs09/game/node/entity/player/info/login/LoginParser.kt @@ -25,6 +25,9 @@ import java.util.function.Consumer * Parses the login of a player. */ class LoginParser(val details: PlayerDetails, private val type: LoginType) { + companion object { + var monkeywrench = true + } /** * The player in the game, used for reconnect login type. */ @@ -39,10 +42,6 @@ class LoginParser(val details: PlayerDetails, private val type: LoginType) { */ fun initialize(player: Player, reconnect: Boolean) { if(!validateRequest()) return - if (reconnect) { - reconnect(player) - return - } lateinit var parser: PlayerSaveParser try { parser = PlayerParser.parse(player) @@ -65,8 +64,12 @@ class LoginParser(val details: PlayerDetails, private val type: LoginType) { loginListeners.forEach(Consumer { listener: LoginListener -> listener.login(player) }) //Run our login hooks parser.runContentHooks() //Run our saved-content-parsing hooks player.details.session.setObject(player) - flag(AuthResponse.Success) - player.init() + if (reconnect) { + reconnect(player) + } else { + flag(AuthResponse.Success) + player.init() + } player.monitor.log(player.details.ipAddress, PlayerMonitor.ADDRESS_LOG) player.monitor.log(player.details.serial, PlayerMonitor.ADDRESS_LOG) player.monitor.log(player.details.macAddress, PlayerMonitor.ADDRESS_LOG) diff --git a/Server/src/main/kotlin/rs09/game/node/entity/player/info/login/PlayerSaveParser.kt b/Server/src/main/kotlin/rs09/game/node/entity/player/info/login/PlayerSaveParser.kt index 55474e959..2af90200e 100644 --- a/Server/src/main/kotlin/rs09/game/node/entity/player/info/login/PlayerSaveParser.kt +++ b/Server/src/main/kotlin/rs09/game/node/entity/player/info/login/PlayerSaveParser.kt @@ -86,6 +86,7 @@ class PlayerSaveParser(val player: Player) { { if(read) contentHooks.forEach{it.parsePlayer(player, saveFile!!)} + player.details.saveParsed = true } fun parseVarps(){ diff --git a/Server/src/main/kotlin/rs09/game/node/entity/player/info/login/PlayerSaver.kt b/Server/src/main/kotlin/rs09/game/node/entity/player/info/login/PlayerSaver.kt index cd75513c6..f7d9175fb 100644 --- a/Server/src/main/kotlin/rs09/game/node/entity/player/info/login/PlayerSaver.kt +++ b/Server/src/main/kotlin/rs09/game/node/entity/player/info/login/PlayerSaver.kt @@ -61,6 +61,7 @@ class PlayerSaver (val player: Player){ return saveFile } fun save() = runBlocking { + if (!player.details.saveParsed) return@runBlocking val manager = ScriptEngineManager() val scriptEngine = manager.getEngineByName("JavaScript") scriptEngine.put("jsonString", populate().toJSONString()) diff --git a/Server/src/main/kotlin/rs09/game/world/repository/Repository.kt b/Server/src/main/kotlin/rs09/game/world/repository/Repository.kt index 085bc4271..4e9cc7d6d 100644 --- a/Server/src/main/kotlin/rs09/game/world/repository/Repository.kt +++ b/Server/src/main/kotlin/rs09/game/world/repository/Repository.kt @@ -7,6 +7,7 @@ import core.game.world.map.Location import core.game.world.map.RegionManager import core.game.world.repository.NodeList import rs09.ServerConstants +import rs09.game.world.update.UpdateSequence import java.util.* import java.util.concurrent.CopyOnWriteArrayList @@ -146,6 +147,7 @@ object Repository { players.remove(player) uid_map.remove(player.details.usernameHashcode) playerNames.remove(player.name) + UpdateSequence.renderablePlayers.remove(player) } /** diff --git a/Server/src/main/kotlin/rs09/net/event/LoginReadEvent.kt b/Server/src/main/kotlin/rs09/net/event/LoginReadEvent.kt index dee6dc961..92bc47236 100644 --- a/Server/src/main/kotlin/rs09/net/event/LoginReadEvent.kt +++ b/Server/src/main/kotlin/rs09/net/event/LoginReadEvent.kt @@ -33,6 +33,7 @@ class LoginReadEvent(session: IoSession?, buffer: ByteBuffer?) : IoReadEvent(ses details.communication.parse(accountInfo) session.clientInfo = ClientInfo(info.displayMode, info.windowMode, info.screenWidth, info.screenHeight) session.isaacPair = info.isaacPair + session.associatedUsername = info.username Login.proceedWith(session, details, info.opcode) } } \ No newline at end of file diff --git a/Server/src/main/kotlin/rs09/net/packet/in/Login.kt b/Server/src/main/kotlin/rs09/net/packet/in/Login.kt index 5641fec32..7c49b3778 100644 --- a/Server/src/main/kotlin/rs09/net/packet/in/Login.kt +++ b/Server/src/main/kotlin/rs09/net/packet/in/Login.kt @@ -121,11 +121,19 @@ object Login { details.session = session details.info.translate(UIDInfo(details.ipAddress, "DEPRECATED", "DEPRECATED", "DEPRECATED")) val player = Player(details) - if (!Repository.players.contains(player)) { + if (Repository.getPlayerByName(player.name) == null) { Repository.addPlayer(player) } - LoginParser(details, LoginType.fromType(opcode)).initialize(player, opcode == RECONNECT_LOGIN_OP) - sendMSEvents(details) + session.lastPing = System.currentTimeMillis() + try { + LoginParser(details, LoginType.fromType(opcode)).initialize(player, opcode == RECONNECT_LOGIN_OP) + sendMSEvents(details) + } catch (e: Exception) { + e.printStackTrace() + session.disconnect() + Repository.removePlayer(player) + player.clear(true) + } } private fun sendMSEvents(details: PlayerDetails) { diff --git a/Server/src/main/kotlin/rs09/worker/MajorUpdateWorker.kt b/Server/src/main/kotlin/rs09/worker/MajorUpdateWorker.kt index 95f808039..1e82f3395 100644 --- a/Server/src/main/kotlin/rs09/worker/MajorUpdateWorker.kt +++ b/Server/src/main/kotlin/rs09/worker/MajorUpdateWorker.kt @@ -1,15 +1,8 @@ package rs09.worker import api.submitWorldPulse -import core.game.system.SystemManager -import core.game.system.SystemState import core.game.system.task.Pulse import core.plugin.CorePluginTypes.Managers -import gui.GuiEvent -import gui.ServerMonitor -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch import rs09.Server import rs09.ServerConstants import rs09.ServerStore @@ -18,13 +11,10 @@ import rs09.game.system.SystemLogger import rs09.game.world.GameWorld import rs09.game.world.repository.Repository import rs09.game.world.update.UpdateSequence -import rs09.net.packet.PacketWriteQueue import rs09.tools.stringtools.colorize import java.lang.Long.max -import java.lang.Long.min import java.text.SimpleDateFormat import java.util.* -import kotlin.collections.ArrayList import kotlin.system.exitProcess /** @@ -46,6 +36,15 @@ class MajorUpdateWorker { handleTickActions() + for (player in Repository.players.filter {!it.isArtificial}) { + if (System.currentTimeMillis() - player.session.lastPing > 20000L) { + player?.details?.session?.disconnect() + player?.session?.lastPing = Long.MAX_VALUE + player?.clear(true) + Repository.removePlayer(player) + } + } + //Handle daily restart if enabled if(sdf.format(Date()).toInt() == 0){