Add ChannelService to handle cc'ing

This commit is contained in:
P0nk
2023-08-04 14:53:20 +02:00
parent f6aa8ceba6
commit 05b7ec77c8
11 changed files with 162 additions and 86 deletions

View File

@@ -21,7 +21,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package client; package client;
import client.inventory.InventoryType;
import config.YamlConfig; import config.YamlConfig;
import constants.game.GameConstants; import constants.game.GameConstants;
import constants.id.MapId; import constants.id.MapId;
@@ -59,9 +58,7 @@ import server.MapleLeafLogger;
import server.ThreadManager; import server.ThreadManager;
import server.TimerManager; import server.TimerManager;
import server.life.Monster; import server.life.Monster;
import server.maps.FieldLimit;
import server.maps.MapleMap; import server.maps.MapleMap;
import server.maps.MiniDungeonInfo;
import tools.BCrypt; import tools.BCrypt;
import tools.DatabaseConnection; import tools.DatabaseConnection;
import tools.HexTool; import tools.HexTool;
@@ -69,7 +66,6 @@ import tools.PacketCreator;
import javax.script.ScriptEngine; import javax.script.ScriptEngine;
import java.io.IOException; import java.io.IOException;
import java.net.InetAddress;
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;
@@ -974,10 +970,9 @@ public class Client extends ChannelInboundHandlerAdapter {
private void disconnectInternal(boolean shutdown, boolean cashshop) {//once per Client instance private void disconnectInternal(boolean shutdown, boolean cashshop) {//once per Client instance
if (player != null && player.isLoggedin() && player.getClient() != null) { if (player != null && player.isLoggedin() && player.getClient() != null) {
final int messengerid = player.getMessenger() == null ? 0 : player.getMessenger().getId(); final int messengerid = player.getMessenger() == null ? 0 : player.getMessenger().getId();
//final int fid = player.getFamilyId();
final BuddyList bl = player.getBuddylist(); final BuddyList bl = player.getBuddylist();
final MessengerCharacter chrm = new MessengerCharacter(player, 0); final MessengerCharacter messengerChr = new MessengerCharacter(player, 0);
final GuildCharacter chrg = player.getMGC(); final GuildCharacter guildChr = player.getMGC();
final Guild guild = player.getGuild(); final Guild guild = player.getGuild();
player.cancelMagicDoor(); player.cancelMagicDoor();
@@ -990,14 +985,8 @@ public class Client extends ChannelInboundHandlerAdapter {
if (!cashshop) { if (!cashshop) {
if (!this.serverTransition) { // meaning not changing channels if (!this.serverTransition) { // meaning not changing channels
if (messengerid > 0) { if (messengerid > 0) {
wserv.leaveMessenger(messengerid, chrm); wserv.leaveMessenger(messengerid, messengerChr);
} }
/*
if (fid > 0) {
final Family family = worlda.getFamily(fid);
family.
}
*/
player.forfeitExpirableQuests(); //This is for those quests that you have to stay logged in for a certain amount of time player.forfeitExpirableQuests(); //This is for those quests that you have to stay logged in for a certain amount of time
@@ -1022,8 +1011,8 @@ public class Client extends ChannelInboundHandlerAdapter {
log.error("Account stuck", e); log.error("Account stuck", e);
} finally { } finally {
if (!this.serverTransition) { if (!this.serverTransition) {
if (chrg != null) { if (guildChr != null) {
chrg.setCharacter(null); guildChr.setCharacter(null);
} }
wserv.removePlayer(player); wserv.removePlayer(player);
//getChannelServer().removePlayer(player); already being done //getChannelServer().removePlayer(player); already being done
@@ -1462,61 +1451,6 @@ public class Client extends ChannelInboundHandlerAdapter {
sendPacket(PacketCreator.enableActions()); sendPacket(PacketCreator.enableActions());
} }
public void changeChannel(int channel) {
Server server = Server.getInstance();
if (player.isBanned()) {
disconnect(false, false);
return;
}
if (!player.isAlive() || FieldLimit.CANNOTMIGRATE.check(player.getMap().getFieldLimit())) {
sendPacket(PacketCreator.enableActions());
return;
} else if (MiniDungeonInfo.isDungeonMap(player.getMapId())) {
sendPacket(PacketCreator.serverNotice(5, "Changing channels or entering Cash Shop or MTS are disabled when inside a Mini-Dungeon."));
sendPacket(PacketCreator.enableActions());
return;
}
String[] socket = Server.getInstance().getInetSocket(this, getWorld(), channel);
if (socket == null) {
sendPacket(PacketCreator.serverNotice(1, "Channel " + channel + " is currently disabled. Try another channel."));
sendPacket(PacketCreator.enableActions());
return;
}
player.closePlayerInteractions();
player.closePartySearchInteractions();
player.unregisterChairBuff();
server.getPlayerBuffStorage().addBuffsToStorage(player.getId(), player.getAllBuffs());
server.getPlayerBuffStorage().addDiseasesToStorage(player.getId(), player.getAllDiseases());
player.setDisconnectedFromChannelWorld();
player.notifyMapTransferToPartner(-1);
player.removeIncomingInvites();
player.cancelAllBuffs(true);
player.cancelAllDebuffs();
player.cancelBuffExpireTask();
player.cancelDiseaseExpireTask();
player.cancelSkillCooldownTask();
player.cancelQuestExpirationTask();
//Cancelling magicdoor? Nope
//Cancelling mounts? Noty
player.getInventory(InventoryType.EQUIPPED).checked(false); //test
player.getMap().removePlayer(player);
player.clearBanishPlayerData();
player.getClient().getChannelServer().removePlayer(player);
player.saveCharToDB();
player.setSessionTransitionState();
try {
sendPacket(PacketCreator.getChannelChange(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1])));
} catch (IOException e) {
e.printStackTrace();
}
}
public long getSessionId() { public long getSessionId() {
return this.sessionId; return this.sessionId;
} }
@@ -1585,4 +1519,4 @@ public class Client extends ChannelInboundHandlerAdapter {
public void setLanguage(int lingua) { public void setLanguage(int lingua) {
this.lang = lingua; this.lang = lingua;
} }
} }

View File

@@ -2,13 +2,15 @@ package client.command;
import database.drop.DropProvider; import database.drop.DropProvider;
import server.shop.ShopFactory; import server.shop.ShopFactory;
import service.ChannelService;
/** /**
* @author Ponk * @author Ponk
*/ */
public record CommandContext(CommandsExecutor commandsExecutor, DropProvider dropProvider, ShopFactory shopFactory) { public record CommandContext(CommandsExecutor commandsExecutor, DropProvider dropProvider, ShopFactory shopFactory,
ChannelService channelService) {
public CommandContext with(CommandsExecutor ce) { public CommandContext with(CommandsExecutor ce) {
return new CommandContext(ce, this.dropProvider, this.shopFactory); return new CommandContext(ce, this.dropProvider, this.shopFactory, this.channelService);
} }
} }

View File

@@ -63,7 +63,7 @@ public class SummonCommand extends Command {
if (player.getClient().getChannel() != victim.getClient().getChannel()) {//And then change channel if needed. if (player.getClient().getChannel() != victim.getClient().getChannel()) {//And then change channel if needed.
victim.dropMessage("Changing channel, please wait a moment."); victim.dropMessage("Changing channel, please wait a moment.");
victim.getClient().changeChannel(player.getClient().getChannel()); ctx.channelService().changeChannel(victim.getClient(), player.getClient().getChannel());
} }
try { try {

View File

@@ -5,6 +5,7 @@ import database.drop.MonsterDropRowMapper;
import database.maker.MakerIngredientRowMapper; import database.maker.MakerIngredientRowMapper;
import database.maker.MakerReagentRowMapper; import database.maker.MakerReagentRowMapper;
import database.maker.MakerRecipeRowMapper; import database.maker.MakerRecipeRowMapper;
import database.monsterbook.MonsterCardRowMapper;
import database.note.NoteRowMapper; import database.note.NoteRowMapper;
import database.shop.ShopItemRowMapper; import database.shop.ShopItemRowMapper;
import database.shop.ShopRowMapper; import database.shop.ShopRowMapper;
@@ -32,7 +33,8 @@ public final class JdbiConfig {
new MonsterDropRowMapper(), new MonsterDropRowMapper(),
new GlobalMonsterDropRowMapper(), new GlobalMonsterDropRowMapper(),
new ShopRowMapper(), new ShopRowMapper(),
new ShopItemRowMapper() new ShopItemRowMapper(),
new MonsterCardRowMapper()
); );
} }
} }

View File

@@ -0,0 +1,20 @@
package database.character;
import client.Character;
import database.monsterbook.MonsterCardDao;
public class CharacterSaver {
private final MonsterCardDao monsterCardDao;
public CharacterSaver(MonsterCardDao monsterCardDao) {
this.monsterCardDao = monsterCardDao;
}
public void save(Character chr) {
chr.saveCharToDB(false);
// Saving monster cards to both MySQL and Postgres for now
monsterCardDao.save(chr.getId(), chr.getMonsterBook().getCards());
}
}

View File

@@ -4,6 +4,7 @@ import database.DaoException;
import database.PgDatabaseConnection; import database.PgDatabaseConnection;
import org.jdbi.v3.core.Handle; import org.jdbi.v3.core.Handle;
import org.jdbi.v3.core.JdbiException; import org.jdbi.v3.core.JdbiException;
import org.jdbi.v3.core.statement.PreparedBatch;
import java.util.List; import java.util.List;
@@ -24,7 +25,26 @@ public class MonsterCardDao {
.mapTo(MonsterCard.class) .mapTo(MonsterCard.class)
.list(); .list();
} catch (JdbiException e) { } catch (JdbiException e) {
throw new DaoException("Failed to find monster cards for chr id %d".formatted(chrId), e); throw new DaoException("Failed to find monster cards (chrId %d)".formatted(chrId), e);
}
}
public void save(int chrId, List<MonsterCard> cards) {
try (Handle handle = connection.getHandle()) {
PreparedBatch batch = handle.prepareBatch("""
INSERT INTO monster_card (chr_id, card_id, level)
VALUES (?, ?, ?)
ON CONFLICT (chr_id, card_id)
DO UPDATE SET level = excluded.level;""");
batch.bind(0, chrId);
cards.forEach(card -> {
batch.bind(1, card.cardId());
batch.bind(2, card.level());
batch.add();
});
batch.execute();
} catch (JdbiException e) {
throw new DaoException("Failed to save monster cards (chrId %d)".formatted(chrId), e);
} }
} }
} }

View File

@@ -3,8 +3,10 @@ package net;
import client.command.CommandsExecutor; import client.command.CommandsExecutor;
import client.processor.action.MakerProcessor; import client.processor.action.MakerProcessor;
import client.processor.npc.FredrickProcessor; import client.processor.npc.FredrickProcessor;
import database.character.CharacterSaver;
import database.drop.DropProvider; import database.drop.DropProvider;
import server.shop.ShopFactory; import server.shop.ShopFactory;
import service.ChannelService;
import service.NoteService; import service.NoteService;
import java.util.Objects; import java.util.Objects;
@@ -13,16 +15,19 @@ import java.util.Objects;
* @author Ponk * @author Ponk
*/ */
public record ChannelDependencies( public record ChannelDependencies(
NoteService noteService, FredrickProcessor fredrickProcessor, MakerProcessor makerProcessor, CharacterSaver characterSaver, NoteService noteService, FredrickProcessor fredrickProcessor,
DropProvider dropProvider, CommandsExecutor commandsExecutor, ShopFactory shopFactory MakerProcessor makerProcessor, DropProvider dropProvider, CommandsExecutor commandsExecutor,
ShopFactory shopFactory, ChannelService channelService
) { ) {
public ChannelDependencies { public ChannelDependencies {
Objects.requireNonNull(characterSaver);
Objects.requireNonNull(noteService); Objects.requireNonNull(noteService);
Objects.requireNonNull(fredrickProcessor); Objects.requireNonNull(fredrickProcessor);
Objects.requireNonNull(makerProcessor); Objects.requireNonNull(makerProcessor);
Objects.requireNonNull(dropProvider); Objects.requireNonNull(dropProvider);
Objects.requireNonNull(commandsExecutor); Objects.requireNonNull(commandsExecutor);
Objects.requireNonNull(shopFactory); Objects.requireNonNull(shopFactory);
Objects.requireNonNull(channelService);
} }
} }

View File

@@ -140,7 +140,7 @@ public final class PacketProcessor {
registerHandler(RecvOpcode.NAME_TRANSFER, new TransferNameHandler()); registerHandler(RecvOpcode.NAME_TRANSFER, new TransferNameHandler());
registerHandler(RecvOpcode.CHECK_CHAR_NAME, new TransferNameResultHandler()); registerHandler(RecvOpcode.CHECK_CHAR_NAME, new TransferNameResultHandler());
registerHandler(RecvOpcode.WORLD_TRANSFER, new TransferWorldHandler()); registerHandler(RecvOpcode.WORLD_TRANSFER, new TransferWorldHandler());
registerHandler(RecvOpcode.CHANGE_CHANNEL, new ChangeChannelHandler()); registerHandler(RecvOpcode.CHANGE_CHANNEL, new ChangeChannelHandler(channelDeps.channelService()));
registerHandler(RecvOpcode.STRANGE_DATA, LoginRequiringNoOpHandler.getInstance()); registerHandler(RecvOpcode.STRANGE_DATA, LoginRequiringNoOpHandler.getInstance());
registerHandler(RecvOpcode.GENERAL_CHAT, new GeneralChatHandler(channelDeps.commandsExecutor())); registerHandler(RecvOpcode.GENERAL_CHAT, new GeneralChatHandler(channelDeps.commandsExecutor()));
registerHandler(RecvOpcode.WHISPER, new WhisperHandler()); registerHandler(RecvOpcode.WHISPER, new WhisperHandler());
@@ -160,7 +160,8 @@ public final class PacketProcessor {
registerHandler(RecvOpcode.MAGIC_ATTACK, new MagicDamageHandler(channelDeps.dropProvider())); registerHandler(RecvOpcode.MAGIC_ATTACK, new MagicDamageHandler(channelDeps.dropProvider()));
registerHandler(RecvOpcode.TAKE_DAMAGE, new TakeDamageHandler()); registerHandler(RecvOpcode.TAKE_DAMAGE, new TakeDamageHandler());
registerHandler(RecvOpcode.MOVE_PLAYER, new MovePlayerHandler()); registerHandler(RecvOpcode.MOVE_PLAYER, new MovePlayerHandler());
registerHandler(RecvOpcode.USE_CASH_ITEM, new UseCashItemHandler(channelDeps.noteService(), channelDeps.shopFactory())); registerHandler(RecvOpcode.USE_CASH_ITEM, new UseCashItemHandler(channelDeps.noteService(),
channelDeps.shopFactory()));
registerHandler(RecvOpcode.USE_ITEM, new UseItemHandler()); registerHandler(RecvOpcode.USE_ITEM, new UseItemHandler());
registerHandler(RecvOpcode.USE_RETURN_SCROLL, new UseItemHandler()); registerHandler(RecvOpcode.USE_RETURN_SCROLL, new UseItemHandler());
registerHandler(RecvOpcode.USE_UPGRADE_SCROLL, new ScrollHandler()); registerHandler(RecvOpcode.USE_UPGRADE_SCROLL, new ScrollHandler());

View File

@@ -43,11 +43,13 @@ import constants.net.OpcodeConstants;
import constants.net.ServerConstants; import constants.net.ServerConstants;
import database.PgDatabaseConfig; import database.PgDatabaseConfig;
import database.PgDatabaseConnection; import database.PgDatabaseConnection;
import database.character.CharacterSaver;
import database.drop.DropDao; import database.drop.DropDao;
import database.drop.DropProvider; import database.drop.DropProvider;
import database.maker.MakerDao; import database.maker.MakerDao;
import database.maker.MakerInfoProvider; import database.maker.MakerInfoProvider;
import database.migration.FlywayRunner; import database.migration.FlywayRunner;
import database.monsterbook.MonsterCardDao;
import database.note.NoteDao; import database.note.NoteDao;
import database.shop.ShopDao; import database.shop.ShopDao;
import net.ChannelDependencies; import net.ChannelDependencies;
@@ -73,6 +75,7 @@ import server.expeditions.ExpeditionBossLog;
import server.life.PlayerNPCFactory; import server.life.PlayerNPCFactory;
import server.quest.Quest; import server.quest.Quest;
import server.shop.ShopFactory; import server.shop.ShopFactory;
import service.ChannelService;
import service.NoteService; import service.NoteService;
import tools.DatabaseConnection; import tools.DatabaseConnection;
import tools.Pair; import tools.Pair;
@@ -975,15 +978,19 @@ public class Server {
} }
private ChannelDependencies registerChannelDependencies(PgDatabaseConnection connection) { private ChannelDependencies registerChannelDependencies(PgDatabaseConnection connection) {
MonsterCardDao monsterCardDao = new MonsterCardDao(connection);
CharacterSaver characterSaver = new CharacterSaver(monsterCardDao);
ChannelService channelService = new ChannelService(characterSaver);
NoteService noteService = new NoteService(new NoteDao(connection)); NoteService noteService = new NoteService(new NoteDao(connection));
MakerProcessor makerProcessor = new MakerProcessor(new MakerInfoProvider(new MakerDao(connection))); MakerProcessor makerProcessor = new MakerProcessor(new MakerInfoProvider(new MakerDao(connection)));
FredrickProcessor fredrickProcessor = new FredrickProcessor(noteService); FredrickProcessor fredrickProcessor = new FredrickProcessor(noteService);
DropProvider dropProvider = new DropProvider(new DropDao(connection)); DropProvider dropProvider = new DropProvider(new DropDao(connection));
ShopFactory shopFactory = new ShopFactory(new ShopDao(connection)); ShopFactory shopFactory = new ShopFactory(new ShopDao(connection));
CommandContext commandContext = new CommandContext(null, dropProvider, shopFactory); CommandContext commandContext = new CommandContext(null, dropProvider, shopFactory,
channelService);
CommandsExecutor commandsExecutor = new CommandsExecutor(commandContext); CommandsExecutor commandsExecutor = new CommandsExecutor(commandContext);
ChannelDependencies channelDependencies = new ChannelDependencies(noteService, fredrickProcessor, ChannelDependencies channelDependencies = new ChannelDependencies(characterSaver, noteService,
makerProcessor, dropProvider, commandsExecutor, shopFactory); fredrickProcessor, makerProcessor, dropProvider, commandsExecutor, shopFactory, channelService);
PacketProcessor.registerGameHandlerDependencies(channelDependencies); PacketProcessor.registerGameHandlerDependencies(channelDependencies);

View File

@@ -26,11 +26,17 @@ import client.autoban.AutobanFactory;
import net.AbstractPacketHandler; import net.AbstractPacketHandler;
import net.packet.InPacket; import net.packet.InPacket;
import net.server.Server; import net.server.Server;
import service.ChannelService;
/** /**
* @author Matze * @author Matze
*/ */
public final class ChangeChannelHandler extends AbstractPacketHandler { public final class ChangeChannelHandler extends AbstractPacketHandler {
private final ChannelService channelService;
public ChangeChannelHandler(ChannelService channelService) {
this.channelService = channelService;
}
@Override @Override
public final void handlePacket(InPacket p, Client c) { public final void handlePacket(InPacket p, Client c) {
@@ -45,6 +51,6 @@ public final class ChangeChannelHandler extends AbstractPacketHandler {
return; return;
} }
c.changeChannel(channel); channelService.changeChannel(c, channel);
} }
} }

View File

@@ -0,0 +1,79 @@
package service;
import client.Client;
import client.inventory.InventoryType;
import database.character.CharacterSaver;
import net.server.Server;
import server.maps.FieldLimit;
import server.maps.MiniDungeonInfo;
import tools.PacketCreator;
import java.io.IOException;
import java.net.InetAddress;
public class ChannelService {
private final Server server = Server.getInstance();
private final CharacterSaver chrSaver;
public ChannelService(CharacterSaver characterSaver) {
this.chrSaver = characterSaver;
}
public void changeChannel(Client c, int channel) {
var chr = c.getPlayer();
if (chr.isBanned()) {
c.disconnect(false, false);
return;
}
if (!chr.isAlive() || FieldLimit.CANNOTMIGRATE.check(chr.getMap().getFieldLimit())) {
c.sendPacket(PacketCreator.enableActions());
return;
}
if (MiniDungeonInfo.isDungeonMap(chr.getMapId())) {
c.sendPacket(PacketCreator.serverNotice(5, "Changing channels or entering Cash Shop or MTS are disabled when inside a Mini-Dungeon."));
c.sendPacket(PacketCreator.enableActions());
return;
}
String[] socket = Server.getInstance().getInetSocket(c, c.getWorld(), channel);
if (socket == null) {
c.sendPacket(PacketCreator.serverNotice(1, "Channel " + channel + " is currently disabled. Try another channel."));
c.sendPacket(PacketCreator.enableActions());
return;
}
chr.closePlayerInteractions();
chr.closePartySearchInteractions();
chr.unregisterChairBuff();
server.getPlayerBuffStorage().addBuffsToStorage(chr.getId(), chr.getAllBuffs());
server.getPlayerBuffStorage().addDiseasesToStorage(chr.getId(), chr.getAllDiseases());
chr.setDisconnectedFromChannelWorld();
chr.notifyMapTransferToPartner(-1);
chr.removeIncomingInvites();
chr.cancelAllBuffs(true);
chr.cancelAllDebuffs();
chr.cancelBuffExpireTask();
chr.cancelDiseaseExpireTask();
chr.cancelSkillCooldownTask();
chr.cancelQuestExpirationTask();
//Cancelling magicdoor? Nope
//Cancelling mounts? Noty
chr.getInventory(InventoryType.EQUIPPED).checked(false); //test
chr.getMap().removePlayer(chr);
chr.clearBanishPlayerData();
c.getChannelServer().removePlayer(chr);
chrSaver.save(chr);
chr.setSessionTransitionState();
try {
c.sendPacket(PacketCreator.getChannelChange(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1])));
} catch (IOException e) {
e.printStackTrace();
}
}
}