Handle disconnect solely in TransitionService
This commit is contained in:
@@ -1755,32 +1755,31 @@ public class Character extends AbstractCharacterObject {
|
|||||||
|
|
||||||
sendPacket(warpPacket);
|
sendPacket(warpPacket);
|
||||||
map.removePlayer(this);
|
map.removePlayer(this);
|
||||||
if (client.getChannelServer().getPlayerStorage().getCharacterById(getId()) != null) {
|
if (client.getChannelServer().getPlayerStorage().getCharacterById(id) == null) {
|
||||||
map = to;
|
|
||||||
setPosition(pos);
|
|
||||||
map.addPlayer(this);
|
|
||||||
visitMap(map);
|
|
||||||
|
|
||||||
prtLock.lock();
|
|
||||||
try {
|
|
||||||
if (party != null) {
|
|
||||||
mpc.setMapId(to.getId());
|
|
||||||
sendPacket(PacketCreator.updateParty(client.getChannel(), party, PartyOperation.SILENT_UPDATE, null));
|
|
||||||
updatePartyMemberHPInternal();
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
prtLock.unlock();
|
|
||||||
}
|
|
||||||
if (Character.this.getParty() != null) {
|
|
||||||
Character.this.getParty().setEnemy(k);
|
|
||||||
}
|
|
||||||
silentPartyUpdateInternal(getParty()); // EIM script calls inside
|
|
||||||
} else {
|
|
||||||
log.warn("Chr {} got stuck when moving to map {}", getName(), map.getId());
|
log.warn("Chr {} got stuck when moving to map {}", getName(), map.getId());
|
||||||
client.disconnect(true, false); // thanks BHB for noticing a player storage stuck case here
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
map = to;
|
||||||
|
setPosition(pos);
|
||||||
|
map.addPlayer(this);
|
||||||
|
visitMap(map);
|
||||||
|
|
||||||
|
prtLock.lock();
|
||||||
|
try {
|
||||||
|
if (party != null) {
|
||||||
|
mpc.setMapId(to.getId());
|
||||||
|
sendPacket(PacketCreator.updateParty(client.getChannel(), party, PartyOperation.SILENT_UPDATE, null));
|
||||||
|
updatePartyMemberHPInternal();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
prtLock.unlock();
|
||||||
|
}
|
||||||
|
if (Character.this.getParty() != null) {
|
||||||
|
Character.this.getParty().setEnemy(k);
|
||||||
|
}
|
||||||
|
silentPartyUpdateInternal(getParty()); // EIM script calls inside
|
||||||
|
|
||||||
notifyMapTransferToPartner(map.getId());
|
notifyMapTransferToPartner(map.getId());
|
||||||
|
|
||||||
//alas, new map has been specified when a warping was being processed...
|
//alas, new map has been specified when a warping was being processed...
|
||||||
@@ -8175,20 +8174,14 @@ public class Character extends AbstractCharacterObject {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: all callers should use CharacterSaver instead.
|
|
||||||
// It's supposed to act as a proxy to these 2 methods (as a first step towards taking full ownership of character saving)
|
|
||||||
public void saveCharToDB() {
|
|
||||||
saveCharToDB(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
//ItemFactory saveItems and monsterbook.saveCards are the most time consuming here.
|
//ItemFactory saveItems and monsterbook.saveCards are the most time consuming here.
|
||||||
public synchronized void saveCharToDB(boolean notAutosave) {
|
public synchronized void saveCharToDB() {
|
||||||
if (!loggedIn) {
|
if (!loggedIn) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Calendar c = Calendar.getInstance();
|
Calendar c = Calendar.getInstance();
|
||||||
log.debug("Attempting to {} chr {}", notAutosave ? "save" : "autosave", name);
|
log.debug("Saving chr {}", name);
|
||||||
|
|
||||||
Server.getInstance().updateCharacterEntry(this);
|
Server.getInstance().updateCharacterEntry(this);
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
package client;
|
package client;
|
||||||
|
|
||||||
import config.YamlConfig;
|
import config.YamlConfig;
|
||||||
import constants.id.MapId;
|
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||||
import io.netty.handler.timeout.IdleStateEvent;
|
import io.netty.handler.timeout.IdleStateEvent;
|
||||||
@@ -41,34 +40,24 @@ import net.server.coordinator.login.LoginBypassCoordinator;
|
|||||||
import net.server.coordinator.session.Hwid;
|
import net.server.coordinator.session.Hwid;
|
||||||
import net.server.coordinator.session.SessionCoordinator;
|
import net.server.coordinator.session.SessionCoordinator;
|
||||||
import net.server.coordinator.session.SessionCoordinator.AntiMulticlientResult;
|
import net.server.coordinator.session.SessionCoordinator.AntiMulticlientResult;
|
||||||
import net.server.guild.Guild;
|
|
||||||
import net.server.guild.GuildCharacter;
|
|
||||||
import net.server.guild.GuildPackets;
|
|
||||||
import net.server.world.MessengerCharacter;
|
|
||||||
import net.server.world.Party;
|
import net.server.world.Party;
|
||||||
import net.server.world.PartyCharacter;
|
|
||||||
import net.server.world.PartyOperation;
|
|
||||||
import net.server.world.World;
|
import net.server.world.World;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import scripting.AbstractPlayerInteraction;
|
import scripting.AbstractPlayerInteraction;
|
||||||
import scripting.event.EventInstanceManager;
|
|
||||||
import scripting.event.EventManager;
|
import scripting.event.EventManager;
|
||||||
import scripting.npc.NPCConversationManager;
|
import scripting.npc.NPCConversationManager;
|
||||||
import scripting.npc.NPCScriptManager;
|
import scripting.npc.NPCScriptManager;
|
||||||
import scripting.quest.QuestActionManager;
|
import scripting.quest.QuestActionManager;
|
||||||
import scripting.quest.QuestScriptManager;
|
import scripting.quest.QuestScriptManager;
|
||||||
import server.ThreadManager;
|
|
||||||
import server.TimerManager;
|
import server.TimerManager;
|
||||||
import server.life.Monster;
|
import server.life.Monster;
|
||||||
import server.maps.MapleMap;
|
|
||||||
import tools.BCrypt;
|
import tools.BCrypt;
|
||||||
import tools.DatabaseConnection;
|
import tools.DatabaseConnection;
|
||||||
import tools.HexTool;
|
import tools.HexTool;
|
||||||
import tools.PacketCreator;
|
import tools.PacketCreator;
|
||||||
|
|
||||||
import javax.script.ScriptEngine;
|
import javax.script.ScriptEngine;
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
@@ -212,7 +201,8 @@ public class Client extends ChannelInboundHandlerAdapter {
|
|||||||
MonitoredChrLogger.logPacketIfMonitored(this, opcode, packet.getBytes());
|
MonitoredChrLogger.logPacketIfMonitored(this, opcode, packet.getBytes());
|
||||||
handler.handlePacket(packet, this);
|
handler.handlePacket(packet, this);
|
||||||
} catch (GameViolationException gve) {
|
} catch (GameViolationException gve) {
|
||||||
throw new DisconnectException(this, gve.getMessage());
|
log.warn("Game violation (disconnecting): {}", gve.getMessage());
|
||||||
|
throw new DisconnectException(this, true);
|
||||||
} catch (final Throwable t) {
|
} catch (final Throwable t) {
|
||||||
final String chrInfo = player != null ? player.getName() + " on map " + player.getMapId() : "?";
|
final String chrInfo = player != null ? player.getName() + " on map " + player.getMapId() : "?";
|
||||||
log.warn("Error in packet handler {}. Chr {}, account {}. Packet: {}", handler.getClass().getSimpleName(),
|
log.warn("Error in packet handler {}. Chr {}, account {}. Packet: {}", handler.getClass().getSimpleName(),
|
||||||
@@ -232,15 +222,13 @@ public class Client extends ChannelInboundHandlerAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
log.warn("Exception caught by {}", player, cause);
|
log.warn("Exception caught by {}", player, cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cause instanceof InvalidPacketHeaderException) {
|
if (cause instanceof InvalidPacketHeaderException) {
|
||||||
SessionCoordinator.getInstance().closeSession(this, true);
|
SessionCoordinator.getInstance().closeSession(this, true);
|
||||||
} else if (cause instanceof IOException) {
|
|
||||||
closeMapleSession();
|
|
||||||
} else {
|
} else {
|
||||||
ctx.fireExceptionCaught(cause);
|
ctx.fireExceptionCaught(cause);
|
||||||
}
|
}
|
||||||
@@ -248,10 +236,6 @@ public class Client extends ChannelInboundHandlerAdapter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void channelInactive(ChannelHandlerContext ctx) {
|
public void channelInactive(ChannelHandlerContext ctx) {
|
||||||
closeMapleSession();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void closeMapleSession() {
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case LOGIN -> SessionCoordinator.getInstance().closeLoginSession(this);
|
case LOGIN -> SessionCoordinator.getInstance().closeLoginSession(this);
|
||||||
case CHANNEL -> SessionCoordinator.getInstance().closeSession(this, false);
|
case CHANNEL -> SessionCoordinator.getInstance().closeSession(this, false);
|
||||||
@@ -260,7 +244,7 @@ public class Client extends ChannelInboundHandlerAdapter {
|
|||||||
try {
|
try {
|
||||||
// client freeze issues on session transition states found thanks to yolinlin, Omo Oppa, Nozphex
|
// client freeze issues on session transition states found thanks to yolinlin, Omo Oppa, Nozphex
|
||||||
if (!inTransition) {
|
if (!inTransition) {
|
||||||
disconnect(false, false);
|
ctx.fireExceptionCaught(new DisconnectException(this, false));
|
||||||
}
|
}
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
log.warn("Account stuck", t);
|
log.warn("Account stuck", t);
|
||||||
@@ -693,11 +677,6 @@ public class Client extends ChannelInboundHandlerAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void updateLoginState(int newState) {
|
public void updateLoginState(int newState) {
|
||||||
// rules out possibility of multiple account entries
|
|
||||||
if (newState == LOGIN_LOGGEDIN) {
|
|
||||||
SessionCoordinator.getInstance().updateOnlineClient(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
try (Connection con = DatabaseConnection.getConnection();
|
try (Connection con = DatabaseConnection.getConnection();
|
||||||
PreparedStatement ps = con.prepareStatement("UPDATE accounts SET loggedin = ?, lastlogin = ? WHERE id = ?")) {
|
PreparedStatement ps = con.prepareStatement("UPDATE accounts SET loggedin = ?, lastlogin = ? WHERE id = ?")) {
|
||||||
// using sql currenttime here could potentially break the login, thanks Arnah for pointing this out
|
// using sql currenttime here could potentially break the login, thanks Arnah for pointing this out
|
||||||
@@ -770,85 +749,6 @@ public class Client extends ChannelInboundHandlerAdapter {
|
|||||||
return date.get(Calendar.YEAR) == birthday.get(Calendar.YEAR) && date.get(Calendar.MONTH) == birthday.get(Calendar.MONTH) && date.get(Calendar.DAY_OF_MONTH) == birthday.get(Calendar.DAY_OF_MONTH);
|
return date.get(Calendar.YEAR) == birthday.get(Calendar.YEAR) && date.get(Calendar.MONTH) == birthday.get(Calendar.MONTH) && date.get(Calendar.DAY_OF_MONTH) == birthday.get(Calendar.DAY_OF_MONTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removePartyPlayer(World wserv) {
|
|
||||||
MapleMap map = player.getMap();
|
|
||||||
final Party party = player.getParty();
|
|
||||||
final int idz = player.getId();
|
|
||||||
|
|
||||||
if (party != null) {
|
|
||||||
final PartyCharacter chrp = new PartyCharacter(player);
|
|
||||||
chrp.setOnline(false);
|
|
||||||
wserv.updateParty(party.getId(), PartyOperation.LOG_ONOFF, chrp);
|
|
||||||
if (party.getLeader().getId() == idz && map != null) {
|
|
||||||
PartyCharacter lchr = null;
|
|
||||||
for (PartyCharacter pchr : party.getMembers()) {
|
|
||||||
if (pchr != null && pchr.getId() != idz && (lchr == null || lchr.getLevel() <= pchr.getLevel()) && map.getCharacterById(pchr.getId()) != null) {
|
|
||||||
lchr = pchr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (lchr != null) {
|
|
||||||
wserv.updateParty(party.getId(), PartyOperation.CHANGE_LEADER, lchr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void removePlayer(World wserv, boolean serverTransition) {
|
|
||||||
try {
|
|
||||||
player.setDisconnectedFromChannelWorld();
|
|
||||||
player.notifyMapTransferToPartner(-1);
|
|
||||||
player.removeIncomingInvites();
|
|
||||||
player.cancelAllBuffs(true);
|
|
||||||
|
|
||||||
player.closePlayerInteractions();
|
|
||||||
player.closePartySearchInteractions();
|
|
||||||
|
|
||||||
if (!serverTransition) { // thanks MedicOP for detecting an issue with party leader change on changing channels
|
|
||||||
removePartyPlayer(wserv);
|
|
||||||
|
|
||||||
EventInstanceManager eim = player.getEventInstance();
|
|
||||||
if (eim != null) {
|
|
||||||
eim.playerDisconnected(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (player.getMonsterCarnival() != null) {
|
|
||||||
player.getMonsterCarnival().playerDisconnected(getPlayer().getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (player.getAriantColiseum() != null) {
|
|
||||||
player.getAriantColiseum().playerDisconnected(getPlayer());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (player.getMap() != null) {
|
|
||||||
int mapId = player.getMapId();
|
|
||||||
player.getMap().removePlayer(player);
|
|
||||||
if (MapId.isDojo(mapId)) {
|
|
||||||
this.getChannelServer().freeDojoSectionIfEmpty(mapId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (player.getMap().getHPDec() > 0) {
|
|
||||||
getWorldServer().removePlayerHpDecrease(player);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (final Throwable t) {
|
|
||||||
log.error("Account stuck", t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void disconnect(final boolean shutdown, final boolean cashshop) {
|
|
||||||
if (tryDisconnect()) {
|
|
||||||
ThreadManager.getInstance().newTask(() -> disconnectInternal(shutdown, cashshop));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void forceDisconnect() {
|
|
||||||
if (tryDisconnect()) {
|
|
||||||
disconnectInternal(true, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized boolean tryDisconnect() {
|
public synchronized boolean tryDisconnect() {
|
||||||
if (disconnecting) {
|
if (disconnecting) {
|
||||||
return false;
|
return false;
|
||||||
@@ -858,88 +758,6 @@ public class Client extends ChannelInboundHandlerAdapter {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void disconnectInternal(boolean shutdown, boolean cashshop) {//once per Client instance
|
|
||||||
if (player != null && player.isLoggedin() && player.getClient() != null) {
|
|
||||||
final int messengerid = player.getMessenger() == null ? 0 : player.getMessenger().getId();
|
|
||||||
final BuddyList bl = player.getBuddylist();
|
|
||||||
final MessengerCharacter messengerChr = new MessengerCharacter(player, 0);
|
|
||||||
final GuildCharacter guildChr = player.getMGC();
|
|
||||||
final Guild guild = player.getGuild();
|
|
||||||
|
|
||||||
player.cancelMagicDoor();
|
|
||||||
|
|
||||||
final World wserv = getWorldServer(); // obviously wserv is NOT null if this player was online on it
|
|
||||||
try {
|
|
||||||
removePlayer(wserv, this.serverTransition);
|
|
||||||
|
|
||||||
if (!(channel == -1 || shutdown)) {
|
|
||||||
if (!cashshop) {
|
|
||||||
if (!this.serverTransition) { // meaning not changing channels
|
|
||||||
if (messengerid > 0) {
|
|
||||||
wserv.leaveMessenger(messengerid, messengerChr);
|
|
||||||
}
|
|
||||||
|
|
||||||
player.forfeitExpirableQuests(); //This is for those quests that you have to stay logged in for a certain amount of time
|
|
||||||
|
|
||||||
if (guild != null) {
|
|
||||||
final Server server = Server.getInstance();
|
|
||||||
server.setGuildMemberOnline(player, false, player.getClient().getChannel());
|
|
||||||
player.sendPacket(GuildPackets.showGuildInfo(player));
|
|
||||||
}
|
|
||||||
if (bl != null) {
|
|
||||||
wserv.loggedOff(player.getName(), player.getId(), channel, player.getBuddylist().getBuddyIds());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!this.serverTransition) { // if dc inside of cash shop.
|
|
||||||
if (bl != null) {
|
|
||||||
wserv.loggedOff(player.getName(), player.getId(), channel, player.getBuddylist().getBuddyIds());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (final Exception e) {
|
|
||||||
log.error("Account stuck", e);
|
|
||||||
} finally {
|
|
||||||
if (!this.serverTransition) {
|
|
||||||
if (guildChr != null) {
|
|
||||||
guildChr.setCharacter(null);
|
|
||||||
}
|
|
||||||
wserv.removePlayer(player);
|
|
||||||
//getChannelServer().removePlayer(player); already being done
|
|
||||||
|
|
||||||
player.cancelAllDebuffs();
|
|
||||||
player.saveCharToDB();
|
|
||||||
|
|
||||||
player.logOff();
|
|
||||||
if (YamlConfig.config.server.INSTANT_NAME_CHANGE) {
|
|
||||||
player.doPendingNameChange();
|
|
||||||
}
|
|
||||||
clear();
|
|
||||||
} else {
|
|
||||||
getChannelServer().removePlayer(player);
|
|
||||||
|
|
||||||
player.cancelAllDebuffs();
|
|
||||||
player.saveCharToDB();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SessionCoordinator.getInstance().closeSession(this, false);
|
|
||||||
|
|
||||||
if (!serverTransition && isLoggedIn()) {
|
|
||||||
updateLoginState(Client.LOGIN_NOTLOGGEDIN);
|
|
||||||
|
|
||||||
clear();
|
|
||||||
} else {
|
|
||||||
if (!Server.getInstance().hasCharacteridInTransition(this)) {
|
|
||||||
updateLoginState(Client.LOGIN_NOTLOGGEDIN);
|
|
||||||
}
|
|
||||||
|
|
||||||
engines = null; // thanks Tochi for pointing out a NPE here
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
// player hard reference removal thanks to Steve (kaito1410)
|
// player hard reference removal thanks to Steve (kaito1410)
|
||||||
if (this.player != null) {
|
if (this.player != null) {
|
||||||
@@ -956,6 +774,12 @@ public class Client extends ChannelInboundHandlerAdapter {
|
|||||||
this.player = null;
|
this.player = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void clearEngines() {
|
||||||
|
if (engines != null) {
|
||||||
|
engines.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void setCharacterOnSessionTransitionState(int cid) {
|
public void setCharacterOnSessionTransitionState(int cid) {
|
||||||
this.updateLoginState(Client.LOGIN_SERVER_TRANSITION);
|
this.updateLoginState(Client.LOGIN_SERVER_TRANSITION);
|
||||||
this.inTransition = true;
|
this.inTransition = true;
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ public class DcCommand extends Command {
|
|||||||
victim = player.getMap().getCharacterByName(chrName);
|
victim = player.getMap().getCharacterByName(chrName);
|
||||||
if (victim != null) {
|
if (victim != null) {
|
||||||
try {//sometimes bugged because the map = null
|
try {//sometimes bugged because the map = null
|
||||||
ctx.transitionService().disconnect(victim.getClient(), true, false);
|
ctx.transitionService().disconnect(victim.getClient(), true);
|
||||||
player.getMap().removePlayer(victim);
|
player.getMap().removePlayer(victim);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@@ -62,6 +62,6 @@ public class DcCommand extends Command {
|
|||||||
if (player.gmLevel() < victim.gmLevel()) {
|
if (player.gmLevel() < victim.gmLevel()) {
|
||||||
victim = player;
|
victim = player;
|
||||||
}
|
}
|
||||||
ctx.transitionService().disconnect(victim.getClient(), false, false);
|
ctx.transitionService().disconnect(victim.getClient(), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ public class BanCommand extends Command {
|
|||||||
c.sendPacket(PacketCreator.getGMEffect(4, (byte) 0));
|
c.sendPacket(PacketCreator.getGMEffect(4, (byte) 0));
|
||||||
final Character rip = target;
|
final Character rip = target;
|
||||||
TimerManager.getInstance().schedule(
|
TimerManager.getInstance().schedule(
|
||||||
() -> ctx.transitionService().disconnect(rip.getClient(), false, false),
|
() -> ctx.transitionService().disconnect(rip.getClient(), false),
|
||||||
TimeUnit.SECONDS.toMillis(5)
|
TimeUnit.SECONDS.toMillis(5)
|
||||||
);
|
);
|
||||||
Server.getInstance().broadcastMessage(c.getWorld(), PacketCreator.serverNotice(6, "[RIP]: " + ign + " has been banned."));
|
Server.getInstance().broadcastMessage(c.getWorld(), PacketCreator.serverNotice(6, "[RIP]: " + ign + " has been banned."));
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ public class DCAllCommand extends Command {
|
|||||||
for (World world : Server.getInstance().getWorlds()) {
|
for (World world : Server.getInstance().getWorlds()) {
|
||||||
for (Character chr : world.getPlayerStorage().getAllCharacters()) {
|
for (Character chr : world.getPlayerStorage().getAllCharacters()) {
|
||||||
if (!chr.isGM()) {
|
if (!chr.isGM()) {
|
||||||
ctx.transitionService().disconnect(chr.getClient(), false, false);
|
ctx.transitionService().disconnect(chr.getClient(), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ public class CharacterSaver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void save(Character chr) {
|
public void save(Character chr) {
|
||||||
chr.saveCharToDB(false);
|
chr.saveCharToDB();
|
||||||
|
|
||||||
// Saving monster cards to both MySQL and Postgres for now
|
// Saving monster cards to both MySQL and Postgres for now
|
||||||
monsterCardDao.save(chr.getId(), chr.getMonsterBook().getCards());
|
monsterCardDao.save(chr.getId(), chr.getMonsterBook().getCards());
|
||||||
|
|||||||
@@ -4,13 +4,18 @@ import client.Client;
|
|||||||
|
|
||||||
public class DisconnectException extends RuntimeException {
|
public class DisconnectException extends RuntimeException {
|
||||||
private final Client client;
|
private final Client client;
|
||||||
|
private final boolean shutdown;
|
||||||
|
|
||||||
public DisconnectException(Client client, String message) {
|
public DisconnectException(Client client, boolean shutdown) {
|
||||||
super(message);
|
|
||||||
this.client = client;
|
this.client = client;
|
||||||
|
this.shutdown = shutdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Client getClient() {
|
public Client getClient() {
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isShutdown() {
|
||||||
|
return shutdown;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ public class DisconnectHandler extends ChannelInboundHandlerAdapter {
|
|||||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||||
if (cause instanceof DisconnectException de) {
|
if (cause instanceof DisconnectException de) {
|
||||||
var client = de.getClient();
|
var client = de.getClient();
|
||||||
transitionService.disconnect(client, true, false);
|
transitionService.disconnect(client, true);
|
||||||
} else {
|
} else {
|
||||||
ctx.fireExceptionCaught(cause);
|
ctx.fireExceptionCaught(cause);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1923,7 +1923,7 @@ public class Server {
|
|||||||
|
|
||||||
for (Client c : toDisconnect) { // thanks Lei for pointing a deadlock issue with srvLock
|
for (Client c : toDisconnect) { // thanks Lei for pointing a deadlock issue with srvLock
|
||||||
if (c.isLoggedIn()) {
|
if (c.isLoggedIn()) {
|
||||||
channelDependencies.transitionService().disconnect(c, false, false);
|
channelDependencies.transitionService().disconnect(c, false);
|
||||||
} else {
|
} else {
|
||||||
SessionCoordinator.getInstance().closeSession(c, true);
|
SessionCoordinator.getInstance().closeSession(c, true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ public final class AdminCommandHandler extends AbstractPacketHandler {
|
|||||||
private void sendPolice(Client c, String reason) {
|
private void sendPolice(Client c, String reason) {
|
||||||
c.sendPacket(PacketCreator.sendPolice(String.format("You have been blocked by the#b %s Police for %s.#k", "Cosmic", reason)));
|
c.sendPacket(PacketCreator.sendPolice(String.format("You have been blocked by the#b %s Police for %s.#k", "Cosmic", reason)));
|
||||||
c.getPlayer().setBanned();
|
c.getPlayer().setBanned();
|
||||||
TimerManager.getInstance().schedule(() -> transitionService.disconnect(c, false, false),
|
TimerManager.getInstance().schedule(() -> transitionService.disconnect(c, false),
|
||||||
TimeUnit.SECONDS.toMillis(6));
|
TimeUnit.SECONDS.toMillis(6));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,24 +109,6 @@ public class SessionCoordinator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Overwrites any existing online client for the account id, making sure to disconnect it as well.
|
|
||||||
*/
|
|
||||||
public void updateOnlineClient(Client client) {
|
|
||||||
if (client != null) {
|
|
||||||
int accountId = client.getAccID();
|
|
||||||
disconnectClientIfOnline(accountId);
|
|
||||||
onlineClients.put(accountId, client);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void disconnectClientIfOnline(int accountId) {
|
|
||||||
Client ingameClient = onlineClients.get(accountId);
|
|
||||||
if (ingameClient != null) { // thanks MedicOP for finding out a loss of loggedin account uniqueness when using the CMS "Unstuck" feature
|
|
||||||
ingameClient.forceDisconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean canStartLoginSession(Client client) {
|
public boolean canStartLoginSession(Client client) {
|
||||||
if (!YamlConfig.config.server.DETERRED_MULTICLIENT) {
|
if (!YamlConfig.config.server.DETERRED_MULTICLIENT) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ public class TimeoutTask extends BaseTask implements Runnable {
|
|||||||
for (Character chr : chars) {
|
for (Character chr : chars) {
|
||||||
if (time - chr.getClient().getLastPacket() > YamlConfig.config.server.TIMEOUT_DURATION) {
|
if (time - chr.getClient().getLastPacket() > YamlConfig.config.server.TIMEOUT_DURATION) {
|
||||||
log.info("Chr {} auto-disconnected due to inactivity", chr.getName());
|
log.info("Chr {} auto-disconnected due to inactivity", chr.getName());
|
||||||
transitionService.disconnect(chr.getClient(), true, chr.getCashShop().isOpened());
|
transitionService.disconnect(chr.getClient(), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public class BanService {
|
|||||||
chr.ban(reason);
|
chr.ban(reason);
|
||||||
|
|
||||||
chr.sendPacket(PacketCreator.sendPolice("You have been blocked by the#b %s Police for HACK reason.#k".formatted("Cosmic")));
|
chr.sendPacket(PacketCreator.sendPolice("You have been blocked by the#b %s Police for HACK reason.#k".formatted("Cosmic")));
|
||||||
TimerManager.getInstance().schedule(() -> transitionService.disconnect(chr.getClient(), false, false),
|
TimerManager.getInstance().schedule(() -> transitionService.disconnect(chr.getClient(), false),
|
||||||
TimeUnit.SECONDS.toMillis(5));
|
TimeUnit.SECONDS.toMillis(5));
|
||||||
|
|
||||||
var bannedName = Character.makeMapleReadable(chr.getName());
|
var bannedName = Character.makeMapleReadable(chr.getName());
|
||||||
|
|||||||
@@ -6,7 +6,9 @@ import client.inventory.InventoryType;
|
|||||||
import config.YamlConfig;
|
import config.YamlConfig;
|
||||||
import constants.id.MapId;
|
import constants.id.MapId;
|
||||||
import database.character.CharacterSaver;
|
import database.character.CharacterSaver;
|
||||||
|
import net.netty.LoginServer;
|
||||||
import net.server.Server;
|
import net.server.Server;
|
||||||
|
import net.server.coordinator.session.SessionCoordinator;
|
||||||
import net.server.guild.Guild;
|
import net.server.guild.Guild;
|
||||||
import net.server.guild.GuildCharacter;
|
import net.server.guild.GuildCharacter;
|
||||||
import net.server.guild.GuildPackets;
|
import net.server.guild.GuildPackets;
|
||||||
@@ -39,7 +41,7 @@ public class TransitionService {
|
|||||||
public void changeChannel(Client c, int channel) {
|
public void changeChannel(Client c, int channel) {
|
||||||
var chr = c.getPlayer();
|
var chr = c.getPlayer();
|
||||||
if (chr.isBanned()) {
|
if (chr.isBanned()) {
|
||||||
disconnect(c, false, false);
|
disconnect(c, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,21 +95,19 @@ public class TransitionService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: take code from Client#disconnect & forceDisconnect. Move it here.
|
public void disconnect(final Client c, final boolean shutdown) {
|
||||||
// It's not gonna be easy to move all instances of c.disconnect, but it has to be done.
|
|
||||||
public void disconnect(final Client c, final boolean shutdown, final boolean cashShop) {
|
|
||||||
if (c.tryDisconnect()) {
|
if (c.tryDisconnect()) {
|
||||||
ThreadManager.getInstance().newTask(() -> disconnectInternal(c, shutdown, cashShop));
|
ThreadManager.getInstance().newTask(() -> disconnectInternal(c, shutdown));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void forceDisconnect(Client c) {
|
public void forceDisconnect(Client c) {
|
||||||
if (c.tryDisconnect()) {
|
if (c.tryDisconnect()) {
|
||||||
disconnectInternal(c, true, false);
|
disconnectInternal(c, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void disconnectInternal(Client c, boolean shutdown, boolean cashShop) {
|
private void disconnectInternal(Client c, boolean shutdown) {
|
||||||
var chr = c.getPlayer();
|
var chr = c.getPlayer();
|
||||||
if (chr != null && chr.isLoggedin() && chr.getClient() != null) {
|
if (chr != null && chr.isLoggedin() && chr.getClient() != null) {
|
||||||
final int messengerid = chr.getMessenger() == null ? 0 : chr.getMessenger().getId();
|
final int messengerid = chr.getMessenger() == null ? 0 : chr.getMessenger().getId();
|
||||||
@@ -123,29 +123,21 @@ public class TransitionService {
|
|||||||
removePlayer(c, wserv, c.isInTransition());
|
removePlayer(c, wserv, c.isInTransition());
|
||||||
|
|
||||||
final int channel = c.getChannel();
|
final int channel = c.getChannel();
|
||||||
if (!(channel == -1 || shutdown)) {
|
if (!(channel == LoginServer.CHANNEL_ID || shutdown)) {
|
||||||
if (!cashShop) {
|
if (!c.isInTransition()) { // meaning not changing channels
|
||||||
if (!c.isInTransition()) { // meaning not changing channels
|
if (messengerid > 0) {
|
||||||
if (messengerid > 0) {
|
wserv.leaveMessenger(messengerid, messengerChr);
|
||||||
wserv.leaveMessenger(messengerid, messengerChr);
|
|
||||||
}
|
|
||||||
|
|
||||||
chr.forfeitExpirableQuests(); //This is for those quests that you have to stay logged in for a certain amount of time
|
|
||||||
|
|
||||||
if (guild != null) {
|
|
||||||
final Server server = Server.getInstance();
|
|
||||||
server.setGuildMemberOnline(chr, false, chr.getClient().getChannel());
|
|
||||||
chr.sendPacket(GuildPackets.showGuildInfo(chr));
|
|
||||||
}
|
|
||||||
if (bl != null) {
|
|
||||||
wserv.loggedOff(chr.getName(), chr.getId(), channel, chr.getBuddylist().getBuddyIds());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (!c.isInTransition()) { // if dc inside of cash shop.
|
chr.forfeitExpirableQuests(); //This is for those quests that you have to stay logged in for a certain amount of time
|
||||||
if (bl != null) {
|
|
||||||
wserv.loggedOff(chr.getName(), chr.getId(), channel, chr.getBuddylist().getBuddyIds());
|
if (guild != null) {
|
||||||
}
|
final Server server = Server.getInstance();
|
||||||
|
server.setGuildMemberOnline(chr, false, chr.getClient().getChannel());
|
||||||
|
chr.sendPacket(GuildPackets.showGuildInfo(chr));
|
||||||
|
}
|
||||||
|
if (bl != null) {
|
||||||
|
wserv.loggedOff(chr.getName(), chr.getId(), channel, chr.getBuddylist().getBuddyIds());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,6 +167,20 @@ public class TransitionService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SessionCoordinator.getInstance().closeSession(c, false);
|
||||||
|
|
||||||
|
|
||||||
|
if (!c.isInTransition() && c.isLoggedIn()) {
|
||||||
|
c.updateLoginState(Client.LOGIN_NOTLOGGEDIN);
|
||||||
|
c.clear();
|
||||||
|
} else {
|
||||||
|
if (!Server.getInstance().hasCharacteridInTransition(c)) {
|
||||||
|
c.updateLoginState(Client.LOGIN_NOTLOGGEDIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
c.clearEngines();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removePlayer(Client c, World world, boolean serverTransition) {
|
private void removePlayer(Client c, World world, boolean serverTransition) {
|
||||||
|
|||||||
Reference in New Issue
Block a user