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
This commit is contained in:
Ceikry
2022-06-19 23:20:01 +00:00
committed by Ryan
parent f503d710ab
commit 40dd58d610
12 changed files with 56 additions and 29 deletions
@@ -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);
}
@@ -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());
@@ -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<TrapWrapper> iterator = instance.traps.iterator();
TrapWrapper wrapper = null;
while (iterator.hasNext()) {
@@ -61,13 +61,20 @@ public class IoEventHandler {
ReadableByteChannel channel = (ReadableByteChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(100_000);
IoSession session = (IoSession) key.attachment();
try {
if (channel.read(buffer) == -1) {
if(session != null && session.getPlayer() != null){
if (session != null && session.getPlayer() != null) {
Repository.getDisconnectionQueue().add(session.getPlayer());
}
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) {
key.attach(session = new IoSession(key, service));
@@ -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;
}
@@ -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)
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)
@@ -86,6 +86,7 @@ class PlayerSaveParser(val player: Player) {
{
if(read)
contentHooks.forEach{it.parsePlayer(player, saveFile!!)}
player.details.saveParsed = true
}
fun parseVarps(){
@@ -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())
@@ -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)
}
/**
@@ -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)
}
}
@@ -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)
}
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) {
@@ -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){