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:
@@ -350,7 +350,6 @@ public class Player extends Entity {
|
|||||||
if (!artificial) {
|
if (!artificial) {
|
||||||
getProperties().setSpawnLocation(ServerConstants.HOME_LOCATION);
|
getProperties().setSpawnLocation(ServerConstants.HOME_LOCATION);
|
||||||
getDetails().getSession().setObject(this);
|
getDetails().getSession().setObject(this);
|
||||||
getDetails().getSession().setLastPing(System.currentTimeMillis() + 10_000L);
|
|
||||||
}
|
}
|
||||||
super.init();
|
super.init();
|
||||||
LoginConfiguration.configureLobby(this);
|
LoginConfiguration.configureLobby(this);
|
||||||
@@ -474,10 +473,6 @@ public class Player extends Entity {
|
|||||||
getAudioManager().send(2607);
|
getAudioManager().send(2607);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!artificial && (System.currentTimeMillis() - getSession().getLastPing()) > 20_000L) {
|
|
||||||
details.getSession().disconnect();
|
|
||||||
getSession().setLastPing(Long.MAX_VALUE);
|
|
||||||
}
|
|
||||||
if(getAttribute("infinite-special", false)) {
|
if(getAttribute("infinite-special", false)) {
|
||||||
settings.setSpecialEnergy(100);
|
settings.setSpecialEnergy(100);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ public class PlayerDetails {
|
|||||||
*/
|
*/
|
||||||
private IoSession session;
|
private IoSession session;
|
||||||
|
|
||||||
|
public boolean saveParsed = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new {@code PlayerDetails}.
|
* Constructs a new {@code PlayerDetails}.
|
||||||
* @param username the username to set.
|
* @param username the username to set.
|
||||||
@@ -253,6 +255,7 @@ public class PlayerDetails {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void save() {
|
public void save() {
|
||||||
|
if(!saveParsed) return;
|
||||||
if(isBanned()) return;
|
if(isBanned()) return;
|
||||||
try {
|
try {
|
||||||
accountInfo.setContacts(communicationInfo.getContactString());
|
accountInfo.setContacts(communicationInfo.getContactString());
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ public final class HunterManager implements LoginListener, LogoutListener, Event
|
|||||||
@Override
|
@Override
|
||||||
public void logout(@NotNull Player player) {
|
public void logout(@NotNull Player player) {
|
||||||
HunterManager instance = getInstance(player);
|
HunterManager instance = getInstance(player);
|
||||||
|
if (instance == null) return;
|
||||||
Iterator<TrapWrapper> iterator = instance.traps.iterator();
|
Iterator<TrapWrapper> iterator = instance.traps.iterator();
|
||||||
TrapWrapper wrapper = null;
|
TrapWrapper wrapper = null;
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
|
|||||||
@@ -61,12 +61,19 @@ public class IoEventHandler {
|
|||||||
ReadableByteChannel channel = (ReadableByteChannel) key.channel();
|
ReadableByteChannel channel = (ReadableByteChannel) key.channel();
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(100_000);
|
ByteBuffer buffer = ByteBuffer.allocate(100_000);
|
||||||
IoSession session = (IoSession) key.attachment();
|
IoSession session = (IoSession) key.attachment();
|
||||||
if (channel.read(buffer) == -1) {
|
try {
|
||||||
if(session != null && session.getPlayer() != null){
|
if (channel.read(buffer) == -1) {
|
||||||
Repository.getDisconnectionQueue().add(session.getPlayer());
|
if (session != null && session.getPlayer() != null) {
|
||||||
|
Repository.getDisconnectionQueue().add(session.getPlayer());
|
||||||
|
}
|
||||||
|
key.cancel();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
key.cancel();
|
} catch (IOException e) {
|
||||||
return;
|
if (e.getMessage().contains("reset by peer")) {
|
||||||
|
session.disconnect();
|
||||||
|
session.getPlayer().clear(true);
|
||||||
|
} else e.printStackTrace();
|
||||||
}
|
}
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
if (session == null) {
|
if (session == null) {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import rs09.auth.AuthResponse;
|
|||||||
import rs09.game.world.GameWorld;
|
import rs09.game.world.GameWorld;
|
||||||
import core.net.producer.HSEventProducer;
|
import core.net.producer.HSEventProducer;
|
||||||
import core.net.producer.LoginEventProducer;
|
import core.net.producer.LoginEventProducer;
|
||||||
|
import rs09.game.world.repository.Repository;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
@@ -114,6 +115,8 @@ public class IoSession {
|
|||||||
*/
|
*/
|
||||||
private ClientInfo clientInfo;
|
private ClientInfo clientInfo;
|
||||||
|
|
||||||
|
public String associatedUsername;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new {@code IoSession}.
|
* Constructs a new {@code IoSession}.
|
||||||
* @param key The selection key.
|
* @param key The selection key.
|
||||||
@@ -329,6 +332,9 @@ public class IoSession {
|
|||||||
* @return The player.
|
* @return The player.
|
||||||
*/
|
*/
|
||||||
public Player getPlayer() {
|
public Player getPlayer() {
|
||||||
|
if (object == null) {
|
||||||
|
object = Repository.getPlayerByName(associatedUsername);
|
||||||
|
}
|
||||||
return object instanceof Player ? ((Player) object) : null;
|
return object instanceof Player ? ((Player) object) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ import java.util.function.Consumer
|
|||||||
* Parses the login of a player.
|
* Parses the login of a player.
|
||||||
*/
|
*/
|
||||||
class LoginParser(val details: PlayerDetails, private val type: LoginType) {
|
class LoginParser(val details: PlayerDetails, private val type: LoginType) {
|
||||||
|
companion object {
|
||||||
|
var monkeywrench = true
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* The player in the game, used for reconnect login type.
|
* 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) {
|
fun initialize(player: Player, reconnect: Boolean) {
|
||||||
if(!validateRequest()) return
|
if(!validateRequest()) return
|
||||||
if (reconnect) {
|
|
||||||
reconnect(player)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
lateinit var parser: PlayerSaveParser
|
lateinit var parser: PlayerSaveParser
|
||||||
try {
|
try {
|
||||||
parser = PlayerParser.parse(player)
|
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
|
loginListeners.forEach(Consumer { listener: LoginListener -> listener.login(player) }) //Run our login hooks
|
||||||
parser.runContentHooks() //Run our saved-content-parsing hooks
|
parser.runContentHooks() //Run our saved-content-parsing hooks
|
||||||
player.details.session.setObject(player)
|
player.details.session.setObject(player)
|
||||||
flag(AuthResponse.Success)
|
if (reconnect) {
|
||||||
player.init()
|
reconnect(player)
|
||||||
|
} else {
|
||||||
|
flag(AuthResponse.Success)
|
||||||
|
player.init()
|
||||||
|
}
|
||||||
player.monitor.log(player.details.ipAddress, PlayerMonitor.ADDRESS_LOG)
|
player.monitor.log(player.details.ipAddress, PlayerMonitor.ADDRESS_LOG)
|
||||||
player.monitor.log(player.details.serial, PlayerMonitor.ADDRESS_LOG)
|
player.monitor.log(player.details.serial, PlayerMonitor.ADDRESS_LOG)
|
||||||
player.monitor.log(player.details.macAddress, PlayerMonitor.ADDRESS_LOG)
|
player.monitor.log(player.details.macAddress, PlayerMonitor.ADDRESS_LOG)
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ class PlayerSaveParser(val player: Player) {
|
|||||||
{
|
{
|
||||||
if(read)
|
if(read)
|
||||||
contentHooks.forEach{it.parsePlayer(player, saveFile!!)}
|
contentHooks.forEach{it.parsePlayer(player, saveFile!!)}
|
||||||
|
player.details.saveParsed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun parseVarps(){
|
fun parseVarps(){
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ class PlayerSaver (val player: Player){
|
|||||||
return saveFile
|
return saveFile
|
||||||
}
|
}
|
||||||
fun save() = runBlocking {
|
fun save() = runBlocking {
|
||||||
|
if (!player.details.saveParsed) return@runBlocking
|
||||||
val manager = ScriptEngineManager()
|
val manager = ScriptEngineManager()
|
||||||
val scriptEngine = manager.getEngineByName("JavaScript")
|
val scriptEngine = manager.getEngineByName("JavaScript")
|
||||||
scriptEngine.put("jsonString", populate().toJSONString())
|
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.map.RegionManager
|
||||||
import core.game.world.repository.NodeList
|
import core.game.world.repository.NodeList
|
||||||
import rs09.ServerConstants
|
import rs09.ServerConstants
|
||||||
|
import rs09.game.world.update.UpdateSequence
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.CopyOnWriteArrayList
|
import java.util.concurrent.CopyOnWriteArrayList
|
||||||
|
|
||||||
@@ -146,6 +147,7 @@ object Repository {
|
|||||||
players.remove(player)
|
players.remove(player)
|
||||||
uid_map.remove(player.details.usernameHashcode)
|
uid_map.remove(player.details.usernameHashcode)
|
||||||
playerNames.remove(player.name)
|
playerNames.remove(player.name)
|
||||||
|
UpdateSequence.renderablePlayers.remove(player)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ class LoginReadEvent(session: IoSession?, buffer: ByteBuffer?) : IoReadEvent(ses
|
|||||||
details.communication.parse(accountInfo)
|
details.communication.parse(accountInfo)
|
||||||
session.clientInfo = ClientInfo(info.displayMode, info.windowMode, info.screenWidth, info.screenHeight)
|
session.clientInfo = ClientInfo(info.displayMode, info.windowMode, info.screenWidth, info.screenHeight)
|
||||||
session.isaacPair = info.isaacPair
|
session.isaacPair = info.isaacPair
|
||||||
|
session.associatedUsername = info.username
|
||||||
Login.proceedWith(session, details, info.opcode)
|
Login.proceedWith(session, details, info.opcode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -121,11 +121,19 @@ object Login {
|
|||||||
details.session = session
|
details.session = session
|
||||||
details.info.translate(UIDInfo(details.ipAddress, "DEPRECATED", "DEPRECATED", "DEPRECATED"))
|
details.info.translate(UIDInfo(details.ipAddress, "DEPRECATED", "DEPRECATED", "DEPRECATED"))
|
||||||
val player = Player(details)
|
val player = Player(details)
|
||||||
if (!Repository.players.contains(player)) {
|
if (Repository.getPlayerByName(player.name) == null) {
|
||||||
Repository.addPlayer(player)
|
Repository.addPlayer(player)
|
||||||
}
|
}
|
||||||
LoginParser(details, LoginType.fromType(opcode)).initialize(player, opcode == RECONNECT_LOGIN_OP)
|
session.lastPing = System.currentTimeMillis()
|
||||||
sendMSEvents(details)
|
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) {
|
private fun sendMSEvents(details: PlayerDetails) {
|
||||||
|
|||||||
@@ -1,15 +1,8 @@
|
|||||||
package rs09.worker
|
package rs09.worker
|
||||||
|
|
||||||
import api.submitWorldPulse
|
import api.submitWorldPulse
|
||||||
import core.game.system.SystemManager
|
|
||||||
import core.game.system.SystemState
|
|
||||||
import core.game.system.task.Pulse
|
import core.game.system.task.Pulse
|
||||||
import core.plugin.CorePluginTypes.Managers
|
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.Server
|
||||||
import rs09.ServerConstants
|
import rs09.ServerConstants
|
||||||
import rs09.ServerStore
|
import rs09.ServerStore
|
||||||
@@ -18,13 +11,10 @@ import rs09.game.system.SystemLogger
|
|||||||
import rs09.game.world.GameWorld
|
import rs09.game.world.GameWorld
|
||||||
import rs09.game.world.repository.Repository
|
import rs09.game.world.repository.Repository
|
||||||
import rs09.game.world.update.UpdateSequence
|
import rs09.game.world.update.UpdateSequence
|
||||||
import rs09.net.packet.PacketWriteQueue
|
|
||||||
import rs09.tools.stringtools.colorize
|
import rs09.tools.stringtools.colorize
|
||||||
import java.lang.Long.max
|
import java.lang.Long.max
|
||||||
import java.lang.Long.min
|
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.collections.ArrayList
|
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -46,6 +36,15 @@ class MajorUpdateWorker {
|
|||||||
|
|
||||||
handleTickActions()
|
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
|
//Handle daily restart if enabled
|
||||||
if(sdf.format(Date()).toInt() == 0){
|
if(sdf.format(Date()).toInt() == 0){
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user