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) {
|
||||
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,6 +61,7 @@ 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) {
|
||||
Repository.getDisconnectionQueue().add(session.getPlayer());
|
||||
@@ -68,6 +69,12 @@ public class IoEventHandler {
|
||||
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){
|
||||
|
||||
|
||||
Reference in New Issue
Block a user