Direct almost all chr saving through CharacterSaver

Client#disconnectInternal remains.
Had to remove some configurable save points to keep it simple.
This commit is contained in:
P0nk
2023-08-04 16:05:10 +02:00
parent e52f646558
commit 4e39142fb3
18 changed files with 122 additions and 152 deletions

View File

@@ -242,7 +242,6 @@ server:
USE_STARTING_AP_4: false #Use early-GMS 4/4/4/4 starting stats. To overcome AP shortage, this gives 4AP/5AP at 1st/2nd job advancements. USE_STARTING_AP_4: false #Use early-GMS 4/4/4/4 starting stats. To overcome AP shortage, this gives 4AP/5AP at 1st/2nd job advancements.
USE_AUTOBAN: false #Commands the server to detect infractors automatically. USE_AUTOBAN: false #Commands the server to detect infractors automatically.
USE_AUTOBAN_LOG: true #Log autoban related messages. Still logs even with USE_AUTOBAN disabled. USE_AUTOBAN_LOG: true #Log autoban related messages. Still logs even with USE_AUTOBAN disabled.
USE_AUTOSAVE: true #Enables server autosaving feature (saves characters to DB each 1 hour).
USE_SERVER_AUTOASSIGNER: false #HeavenMS-builtin autoassigner, uses algorithm based on distributing AP accordingly with required secondary stat on equipments. USE_SERVER_AUTOASSIGNER: false #HeavenMS-builtin autoassigner, uses algorithm based on distributing AP accordingly with required secondary stat on equipments.
USE_REFRESH_RANK_MOVE: true USE_REFRESH_RANK_MOVE: true
USE_ENFORCE_ADMIN_ACCOUNT: false #Forces accounts having GM characters to be treated as a "GM account" by the client (localhost). Some of the GM account perks is the ability to FLY, but unable to TRADE. USE_ENFORCE_ADMIN_ACCOUNT: false #Forces accounts having GM characters to be treated as a "GM account" by the client (localhost). Some of the GM account perks is the ability to FLY, but unable to TRADE.
@@ -254,7 +253,6 @@ server:
USE_ENFORCE_ITEM_SUGGESTION: false #Forces the Owl of Minerva and the Cash Shop to always display the defined item array instead of those featured by the players. USE_ENFORCE_ITEM_SUGGESTION: false #Forces the Owl of Minerva and the Cash Shop to always display the defined item array instead of those featured by the players.
USE_ENFORCE_UNMERCHABLE_CASH: true #Forces players to not sell CASH items via merchants, drops of it disappears. USE_ENFORCE_UNMERCHABLE_CASH: true #Forces players to not sell CASH items via merchants, drops of it disappears.
USE_ENFORCE_UNMERCHABLE_PET: true #Forces players to not sell pets via merchants, drops of it disappears. (since non-named pets gets dirty name and other possible DB-related issues) USE_ENFORCE_UNMERCHABLE_PET: true #Forces players to not sell pets via merchants, drops of it disappears. (since non-named pets gets dirty name and other possible DB-related issues)
USE_ENFORCE_MERCHANT_SAVE: true #Forces automatic DB save on merchant owners, at every item movement on shop.
USE_ENFORCE_MDOOR_POSITION: false #Forces mystic door to be spawned near spawnpoints. USE_ENFORCE_MDOOR_POSITION: false #Forces mystic door to be spawned near spawnpoints.
USE_SPAWN_CLEAN_MDOOR: false #Makes mystic doors to be spawned without deploy animation. This clears disconnecting issues that may happen when trying to cancel doors a couple seconds after deployment. USE_SPAWN_CLEAN_MDOOR: false #Makes mystic doors to be spawned without deploy animation. This clears disconnecting issues that may happen when trying to cancel doors a couple seconds after deployment.
USE_SPAWN_LOOT_ON_ANIMATION: false #Makes loot appear some time after the mob has been killed (following the mob death animation, instead of instantly). USE_SPAWN_LOOT_ON_ANIMATION: false #Makes loot appear some time after the mob has been killed (following the mob death animation, instead of instantly).
@@ -371,7 +369,6 @@ server:
USE_FULL_HOLY_SYMBOL: false #Holy symbol doesn't require EXP sharers to work in full. USE_FULL_HOLY_SYMBOL: false #Holy symbol doesn't require EXP sharers to work in full.
#Character Configuration #Character Configuration
USE_ADD_SLOTS_BY_LEVEL: false #Slots are added each 20 levels.
USE_ADD_RATES_BY_LEVEL: false #Rates are added each 20 levels. USE_ADD_RATES_BY_LEVEL: false #Rates are added each 20 levels.
USE_STACK_COUPON_RATES: false #Multiple coupons effects builds up together. USE_STACK_COUPON_RATES: false #Multiple coupons effects builds up together.
USE_PERFECT_PITCH: false #For lvl 30 or above, each lvlup grants player 1 perfect pitch. USE_PERFECT_PITCH: false #For lvl 30 or above, each lvlup grants player 1 perfect pitch.

View File

@@ -50,8 +50,6 @@ import net.server.guild.Alliance;
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;
import net.server.services.task.world.CharacterSaveService;
import net.server.services.type.WorldServices;
import net.server.world.*; import net.server.world.*;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -6449,15 +6447,6 @@ public class Character extends AbstractCharacterObject {
} }
if (level % 20 == 0) { if (level % 20 == 0) {
if (YamlConfig.config.server.USE_ADD_SLOTS_BY_LEVEL == true) {
if (!isGM()) {
for (byte i = 1; i < 5; i++) {
gainSlots(i, 4, true);
}
this.yellowMessage("You reached level " + level + ". Congratulations! As a token of your success, your inventory has been expanded a little bit.");
}
}
if (YamlConfig.config.server.USE_ADD_RATES_BY_LEVEL == true) { //For the rate upgrade if (YamlConfig.config.server.USE_ADD_RATES_BY_LEVEL == true) { //For the rate upgrade
revertLastPlayerRates(); revertLastPlayerRates();
setPlayerRates(); setPlayerRates();
@@ -8240,21 +8229,11 @@ 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() { public void saveCharToDB() {
if (YamlConfig.config.server.USE_AUTOSAVE) {
Runnable r = new Runnable() {
@Override
public void run() {
saveCharToDB(true); saveCharToDB(true);
} }
};
CharacterSaveService service = (CharacterSaveService) getWorldServer().getServiceAccess(WorldServices.SAVE_CHARACTER);
service.registerSaveCharacter(this.getId(), r);
} else {
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(boolean notAutosave) {
@@ -9179,33 +9158,28 @@ public class Character extends AbstractCharacterObject {
return slots <= 96; return slots <= 96;
} }
public boolean gainSlots(int type, int slots) {
return gainSlots(type, slots, true);
}
public boolean gainSlots(int type, int slots, boolean update) { public boolean gainSlots(int type, int slots, boolean update) {
int newLimit = gainSlotsInternal(type, slots); Integer updatedLimit = gainSlotsInternal(type, slots);
if (newLimit != -1) { if (updatedLimit == null) {
this.saveCharToDB();
if (update) {
sendPacket(PacketCreator.updateInventorySlotLimit(type, newLimit));
}
return true;
} else {
return false; return false;
} }
if (update) {
sendPacket(PacketCreator.updateInventorySlotLimit(type, updatedLimit));
}
return true;
} }
private int gainSlotsInternal(int type, int slots) { private Integer gainSlotsInternal(int type, int slots) {
inventory[type].lockInventory(); inventory[type].lockInventory();
try { try {
if (canGainSlots(type, slots)) { if (!canGainSlots(type, slots)) {
return null;
}
int newLimit = inventory[type].getSlotLimit() + slots; int newLimit = inventory[type].getSlotLimit() + slots;
inventory[type].setSlotLimit(newLimit); inventory[type].setSlotLimit(newLimit);
return newLimit; return newLimit;
} else {
return -1;
}
} finally { } finally {
inventory[type].unlockInventory(); inventory[type].unlockInventory();
} }

View File

@@ -1,5 +1,6 @@
package client.command; package client.command;
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.ChannelService;
@@ -8,9 +9,9 @@ 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) { CharacterSaver characterSaver, ChannelService channelService) {
public CommandContext with(CommandsExecutor ce) { public CommandContext with(CommandsExecutor ce) {
return new CommandContext(ce, this.dropProvider, this.shopFactory, this.channelService); return new CommandContext(ce, this.dropProvider, this.shopFactory, this.characterSaver, this.channelService);
} }
} }

View File

@@ -41,7 +41,7 @@ public class SaveAllCommand extends Command {
Character player = c.getPlayer(); Character player = c.getPlayer();
for (World world : Server.getInstance().getWorlds()) { for (World world : Server.getInstance().getWorlds()) {
for (Character chr : world.getPlayerStorage().getAllCharacters()) { for (Character chr : world.getPlayerStorage().getAllCharacters()) {
chr.saveCharToDB(); ctx.characterSaver().save(chr);
} }
} }
String message = player.getName() + " used !saveall."; String message = player.getName() + " used !saveall.";

View File

@@ -55,7 +55,7 @@ public class WarpWorldCommand extends Command {
player.getMap().removePlayer(player);//LOL FORGOT THIS >< player.getMap().removePlayer(player);//LOL FORGOT THIS ><
player.setSessionTransitionState(); player.setSessionTransitionState();
player.setWorld(worldb); player.setWorld(worldb);
player.saveCharToDB();//To set the new world :O (true because else 2 player instances are created, one in both worlds) ctx.characterSaver().save(player);//To set the new world :O (true because else 2 player instances are created, one in both worlds)
c.sendPacket(PacketCreator.getChannelChange(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]))); c.sendPacket(PacketCreator.getChannelChange(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1])));
} catch (UnknownHostException | NumberFormatException ex) { } catch (UnknownHostException | NumberFormatException ex) {
ex.printStackTrace(); ex.printStackTrace();

View File

@@ -91,7 +91,6 @@ public class ServerConfig {
public boolean USE_STARTING_AP_4; public boolean USE_STARTING_AP_4;
public boolean USE_AUTOBAN; public boolean USE_AUTOBAN;
public boolean USE_AUTOBAN_LOG; public boolean USE_AUTOBAN_LOG;
public boolean USE_AUTOSAVE;
public boolean USE_SERVER_AUTOASSIGNER; public boolean USE_SERVER_AUTOASSIGNER;
public boolean USE_REFRESH_RANK_MOVE; public boolean USE_REFRESH_RANK_MOVE;
public boolean USE_ENFORCE_ADMIN_ACCOUNT; public boolean USE_ENFORCE_ADMIN_ACCOUNT;
@@ -103,7 +102,6 @@ public class ServerConfig {
public boolean USE_ENFORCE_ITEM_SUGGESTION; public boolean USE_ENFORCE_ITEM_SUGGESTION;
public boolean USE_ENFORCE_UNMERCHABLE_CASH; public boolean USE_ENFORCE_UNMERCHABLE_CASH;
public boolean USE_ENFORCE_UNMERCHABLE_PET; public boolean USE_ENFORCE_UNMERCHABLE_PET;
public boolean USE_ENFORCE_MERCHANT_SAVE;
public boolean USE_ENFORCE_MDOOR_POSITION; public boolean USE_ENFORCE_MDOOR_POSITION;
public boolean USE_SPAWN_CLEAN_MDOOR; public boolean USE_SPAWN_CLEAN_MDOOR;
public boolean USE_SPAWN_LOOT_ON_ANIMATION; public boolean USE_SPAWN_LOOT_ON_ANIMATION;
@@ -220,7 +218,6 @@ public class ServerConfig {
public boolean USE_FULL_HOLY_SYMBOL; public boolean USE_FULL_HOLY_SYMBOL;
//Character Configuration //Character Configuration
public boolean USE_ADD_SLOTS_BY_LEVEL;
public boolean USE_ADD_RATES_BY_LEVEL; public boolean USE_ADD_RATES_BY_LEVEL;
public boolean USE_STACK_COUPON_RATES; public boolean USE_STACK_COUPON_RATES;
public boolean USE_PERFECT_PITCH; public boolean USE_PERFECT_PITCH;

View File

@@ -0,0 +1,39 @@
package database.character;
import client.Character;
import client.Client;
import client.MonsterBook;
import database.monsterbook.MonsterCardDao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.SQLException;
import java.util.Optional;
public class CharacterLoader {
private static final Logger log = LoggerFactory.getLogger(CharacterLoader.class);
private final MonsterCardDao monsterCardDao;
public CharacterLoader(MonsterCardDao monsterCardDao) {
this.monsterCardDao = monsterCardDao;
}
public Optional<Character> loadForChannel(int chrId, Client client) {
var monsterBook = loadMonsterBook(chrId);
final Character chr;
try {
chr = Character.loadCharFromDB(chrId, client, true, monsterBook);
} catch (SQLException e) {
log.warn("Failed to load character (id {})", chrId, e);
return Optional.empty();
}
return Optional.ofNullable(chr);
}
private MonsterBook loadMonsterBook(int chrId) {
var monsterCards = monsterCardDao.load(chrId);
return new MonsterBook(monsterCards);
}
}

View File

@@ -3,6 +3,7 @@ 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.CharacterLoader;
import database.character.CharacterSaver; import database.character.CharacterSaver;
import database.drop.DropProvider; import database.drop.DropProvider;
import server.shop.ShopFactory; import server.shop.ShopFactory;
@@ -15,12 +16,13 @@ import java.util.Objects;
* @author Ponk * @author Ponk
*/ */
public record ChannelDependencies( public record ChannelDependencies(
CharacterSaver characterSaver, NoteService noteService, FredrickProcessor fredrickProcessor, CharacterLoader characterLoader, CharacterSaver characterSaver, NoteService noteService,
MakerProcessor makerProcessor, DropProvider dropProvider, CommandsExecutor commandsExecutor, FredrickProcessor fredrickProcessor, MakerProcessor makerProcessor, DropProvider dropProvider,
ShopFactory shopFactory, ChannelService channelService CommandsExecutor commandsExecutor, ShopFactory shopFactory, ChannelService channelService
) { ) {
public ChannelDependencies { public ChannelDependencies {
Objects.requireNonNull(characterLoader);
Objects.requireNonNull(characterSaver); Objects.requireNonNull(characterSaver);
Objects.requireNonNull(noteService); Objects.requireNonNull(noteService);
Objects.requireNonNull(fredrickProcessor); Objects.requireNonNull(fredrickProcessor);

View File

@@ -152,7 +152,8 @@ public final class PacketProcessor {
registerHandler(RecvOpcode.ITEM_SORT, new InventoryMergeHandler()); registerHandler(RecvOpcode.ITEM_SORT, new InventoryMergeHandler());
registerHandler(RecvOpcode.ITEM_MOVE, new ItemMoveHandler()); registerHandler(RecvOpcode.ITEM_MOVE, new ItemMoveHandler());
registerHandler(RecvOpcode.MESO_DROP, new MesoDropHandler()); registerHandler(RecvOpcode.MESO_DROP, new MesoDropHandler());
registerHandler(RecvOpcode.PLAYER_LOGGEDIN, new PlayerLoggedinHandler(channelDeps.noteService())); registerHandler(RecvOpcode.PLAYER_LOGGEDIN, new PlayerLoggedinHandler(channelDeps.characterLoader(),
channelDeps.noteService()));
registerHandler(RecvOpcode.CHANGE_MAP, new ChangeMapHandler()); registerHandler(RecvOpcode.CHANGE_MAP, new ChangeMapHandler());
registerHandler(RecvOpcode.MOVE_LIFE, new MoveLifeHandler()); registerHandler(RecvOpcode.MOVE_LIFE, new MoveLifeHandler());
registerHandler(RecvOpcode.CLOSE_RANGE_ATTACK, new CloseRangeDamageHandler(channelDeps.dropProvider())); registerHandler(RecvOpcode.CLOSE_RANGE_ATTACK, new CloseRangeDamageHandler(channelDeps.dropProvider()));
@@ -174,7 +175,7 @@ public final class PacketProcessor {
registerHandler(RecvOpcode.USE_INNER_PORTAL, new InnerPortalHandler()); registerHandler(RecvOpcode.USE_INNER_PORTAL, new InnerPortalHandler());
registerHandler(RecvOpcode.CANCEL_BUFF, new CancelBuffHandler()); registerHandler(RecvOpcode.CANCEL_BUFF, new CancelBuffHandler());
registerHandler(RecvOpcode.CANCEL_ITEM_EFFECT, new CancelItemEffectHandler()); registerHandler(RecvOpcode.CANCEL_ITEM_EFFECT, new CancelItemEffectHandler());
registerHandler(RecvOpcode.PLAYER_INTERACTION, new PlayerInteractionHandler()); registerHandler(RecvOpcode.PLAYER_INTERACTION, new PlayerInteractionHandler(channelDeps.characterSaver()));
registerHandler(RecvOpcode.RPS_ACTION, new RPSActionHandler()); registerHandler(RecvOpcode.RPS_ACTION, new RPSActionHandler());
registerHandler(RecvOpcode.DISTRIBUTE_AP, new DistributeAPHandler()); registerHandler(RecvOpcode.DISTRIBUTE_AP, new DistributeAPHandler());
registerHandler(RecvOpcode.DISTRIBUTE_SP, new DistributeSPHandler()); registerHandler(RecvOpcode.DISTRIBUTE_SP, new DistributeSPHandler());
@@ -186,8 +187,8 @@ public final class PacketProcessor {
registerHandler(RecvOpcode.DENY_PARTY_REQUEST, new DenyPartyRequestHandler()); registerHandler(RecvOpcode.DENY_PARTY_REQUEST, new DenyPartyRequestHandler());
registerHandler(RecvOpcode.MULTI_CHAT, new MultiChatHandler()); registerHandler(RecvOpcode.MULTI_CHAT, new MultiChatHandler());
registerHandler(RecvOpcode.USE_DOOR, new DoorHandler()); registerHandler(RecvOpcode.USE_DOOR, new DoorHandler());
registerHandler(RecvOpcode.ENTER_MTS, new EnterMTSHandler()); registerHandler(RecvOpcode.ENTER_MTS, new EnterMTSHandler(channelDeps.characterSaver()));
registerHandler(RecvOpcode.ENTER_CASHSHOP, new EnterCashShopHandler()); registerHandler(RecvOpcode.ENTER_CASHSHOP, new EnterCashShopHandler(channelDeps.characterSaver()));
registerHandler(RecvOpcode.DAMAGE_SUMMON, new DamageSummonHandler()); registerHandler(RecvOpcode.DAMAGE_SUMMON, new DamageSummonHandler());
registerHandler(RecvOpcode.MOVE_SUMMON, new MoveSummonHandler()); registerHandler(RecvOpcode.MOVE_SUMMON, new MoveSummonHandler());
registerHandler(RecvOpcode.SUMMON_ATTACK, new SummonDamageHandler(channelDeps.dropProvider())); registerHandler(RecvOpcode.SUMMON_ATTACK, new SummonDamageHandler(channelDeps.dropProvider()));
@@ -277,7 +278,7 @@ public final class PacketProcessor {
registerHandler(RecvOpcode.FREDRICK_ACTION, new FredrickHandler(channelDeps.fredrickProcessor())); registerHandler(RecvOpcode.FREDRICK_ACTION, new FredrickHandler(channelDeps.fredrickProcessor()));
registerHandler(RecvOpcode.MONSTER_CARNIVAL, new MonsterCarnivalHandler()); registerHandler(RecvOpcode.MONSTER_CARNIVAL, new MonsterCarnivalHandler());
registerHandler(RecvOpcode.REMOTE_STORE, new RemoteStoreHandler()); registerHandler(RecvOpcode.REMOTE_STORE, new RemoteStoreHandler());
registerHandler(RecvOpcode.WEDDING_ACTION, new WeddingHandler()); registerHandler(RecvOpcode.WEDDING_ACTION, new WeddingHandler(channelDeps.characterSaver()));
registerHandler(RecvOpcode.WEDDING_TALK, new WeddingTalkHandler()); registerHandler(RecvOpcode.WEDDING_TALK, new WeddingTalkHandler());
registerHandler(RecvOpcode.WEDDING_TALK_MORE, new WeddingTalkMoreHandler()); registerHandler(RecvOpcode.WEDDING_TALK_MORE, new WeddingTalkMoreHandler());
registerHandler(RecvOpcode.WATER_OF_LIFE, new UseWaterOfLifeHandler()); registerHandler(RecvOpcode.WATER_OF_LIFE, new UseWaterOfLifeHandler());

View File

@@ -43,6 +43,7 @@ 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.CharacterLoader;
import database.character.CharacterSaver; import database.character.CharacterSaver;
import database.drop.DropDao; import database.drop.DropDao;
import database.drop.DropProvider; import database.drop.DropProvider;
@@ -979,6 +980,7 @@ public class Server {
private ChannelDependencies registerChannelDependencies(PgDatabaseConnection connection) { private ChannelDependencies registerChannelDependencies(PgDatabaseConnection connection) {
MonsterCardDao monsterCardDao = new MonsterCardDao(connection); MonsterCardDao monsterCardDao = new MonsterCardDao(connection);
CharacterLoader characterLoader = new CharacterLoader(monsterCardDao);
CharacterSaver characterSaver = new CharacterSaver(monsterCardDao); CharacterSaver characterSaver = new CharacterSaver(monsterCardDao);
ChannelService channelService = new ChannelService(characterSaver); ChannelService channelService = new ChannelService(characterSaver);
NoteService noteService = new NoteService(new NoteDao(connection)); NoteService noteService = new NoteService(new NoteDao(connection));
@@ -987,9 +989,9 @@ public class Server {
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); characterSaver, channelService);
CommandsExecutor commandsExecutor = new CommandsExecutor(commandContext); CommandsExecutor commandsExecutor = new CommandsExecutor(commandContext);
ChannelDependencies channelDependencies = new ChannelDependencies(characterSaver, noteService, ChannelDependencies channelDependencies = new ChannelDependencies(characterLoader, characterSaver, noteService,
fredrickProcessor, makerProcessor, dropProvider, commandsExecutor, shopFactory, channelService); fredrickProcessor, makerProcessor, dropProvider, commandsExecutor, shopFactory, channelService);
PacketProcessor.registerGameHandlerDependencies(channelDependencies); PacketProcessor.registerGameHandlerDependencies(channelDependencies);

View File

@@ -23,6 +23,7 @@ package net.server.channel.handlers;
import client.Character; import client.Character;
import client.Client; import client.Client;
import database.character.CharacterSaver;
import net.AbstractPacketHandler; import net.AbstractPacketHandler;
import net.packet.InPacket; import net.packet.InPacket;
import net.server.Server; import net.server.Server;
@@ -33,6 +34,12 @@ import tools.PacketCreator;
* @author Flav * @author Flav
*/ */
public class EnterCashShopHandler extends AbstractPacketHandler { public class EnterCashShopHandler extends AbstractPacketHandler {
private final CharacterSaver chrSaver;
public EnterCashShopHandler(CharacterSaver chrSaver) {
this.chrSaver = chrSaver;
}
@Override @Override
public void handlePacket(InPacket p, Client c) { public void handlePacket(InPacket p, Client c) {
try { try {
@@ -87,7 +94,7 @@ public class EnterCashShopHandler extends AbstractPacketHandler {
c.getChannelServer().removePlayer(mc); c.getChannelServer().removePlayer(mc);
mc.getMap().removePlayer(mc); mc.getMap().removePlayer(mc);
mc.getCashShop().open(true); mc.getCashShop().open(true);
mc.saveCharToDB(); chrSaver.save(mc);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }

View File

@@ -27,6 +27,7 @@ import client.inventory.Equip;
import client.inventory.Item; import client.inventory.Item;
import client.processor.action.BuybackProcessor; import client.processor.action.BuybackProcessor;
import config.YamlConfig; import config.YamlConfig;
import database.character.CharacterSaver;
import net.AbstractPacketHandler; import net.AbstractPacketHandler;
import net.packet.InPacket; import net.packet.InPacket;
import net.server.Server; import net.server.Server;
@@ -45,6 +46,12 @@ import java.util.List;
public final class EnterMTSHandler extends AbstractPacketHandler { public final class EnterMTSHandler extends AbstractPacketHandler {
private final CharacterSaver chrSaver;
public EnterMTSHandler(CharacterSaver chrSaver) {
this.chrSaver = chrSaver;
}
@Override @Override
public final void handlePacket(InPacket p, Client c) { public final void handlePacket(InPacket p, Client c) {
Character chr = c.getPlayer(); Character chr = c.getPlayer();
@@ -105,7 +112,7 @@ public final class EnterMTSHandler extends AbstractPacketHandler {
chr.forfeitExpirableQuests(); chr.forfeitExpirableQuests();
chr.cancelQuestExpirationTask(); chr.cancelQuestExpirationTask();
chr.saveCharToDB(); chrSaver.save(chr);
c.getChannelServer().removePlayer(chr); c.getChannelServer().removePlayer(chr);
chr.getMap().removePlayer(c.getPlayer()); chr.getMap().removePlayer(c.getPlayer());

View File

@@ -33,6 +33,7 @@ import config.YamlConfig;
import constants.game.GameConstants; import constants.game.GameConstants;
import constants.id.ItemId; import constants.id.ItemId;
import constants.inventory.ItemConstants; import constants.inventory.ItemConstants;
import database.character.CharacterSaver;
import net.AbstractPacketHandler; import net.AbstractPacketHandler;
import net.packet.InPacket; import net.packet.InPacket;
import org.slf4j.Logger; import org.slf4j.Logger;
@@ -53,6 +54,11 @@ import java.util.Arrays;
*/ */
public final class PlayerInteractionHandler extends AbstractPacketHandler { public final class PlayerInteractionHandler extends AbstractPacketHandler {
private static final Logger log = LoggerFactory.getLogger(PlayerInteractionHandler.class); private static final Logger log = LoggerFactory.getLogger(PlayerInteractionHandler.class);
private final CharacterSaver chrSaver;
public PlayerInteractionHandler(CharacterSaver chrSaver) {
this.chrSaver = chrSaver;
}
public enum Action { public enum Action {
CREATE(0), CREATE(0),
@@ -644,10 +650,6 @@ public final class PlayerInteractionHandler extends AbstractPacketHandler {
c.sendPacket(PacketCreator.updateHiredMerchant(merchant, chr)); c.sendPacket(PacketCreator.updateHiredMerchant(merchant, chr));
if (YamlConfig.config.server.USE_ENFORCE_MERCHANT_SAVE) {
chr.saveCharToDB(false);
}
try { try {
merchant.saveItems(false); // thanks Masterrulax for realizing yet another dupe with merchants/Fredrick merchant.saveItems(false); // thanks Masterrulax for realizing yet another dupe with merchants/Fredrick
} catch (SQLException ex) { } catch (SQLException ex) {
@@ -771,7 +773,7 @@ public final class PlayerInteractionHandler extends AbstractPacketHandler {
return; return;
} }
merchant.takeItemBack(slot, chr); merchant.takeItemBack(slot, chr, chrSaver);
} }
} else if (mode == Action.CLOSE_MERCHANT.getCode()) { } else if (mode == Action.CLOSE_MERCHANT.getCode()) {
if (isTradeOpen(chr)) { if (isTradeOpen(chr)) {

View File

@@ -27,6 +27,7 @@ import client.inventory.*;
import client.keybind.KeyBinding; import client.keybind.KeyBinding;
import config.YamlConfig; import config.YamlConfig;
import constants.game.GameConstants; import constants.game.GameConstants;
import database.character.CharacterLoader;
import net.AbstractPacketHandler; import net.AbstractPacketHandler;
import net.packet.InPacket; import net.packet.InPacket;
import net.server.PlayerBuffValueHolder; import net.server.PlayerBuffValueHolder;
@@ -64,9 +65,11 @@ public final class PlayerLoggedinHandler extends AbstractPacketHandler {
private static final Logger log = LoggerFactory.getLogger(PlayerLoggedinHandler.class); private static final Logger log = LoggerFactory.getLogger(PlayerLoggedinHandler.class);
private static final Set<Integer> attemptingLoginAccounts = new HashSet<>(); private static final Set<Integer> attemptingLoginAccounts = new HashSet<>();
private final CharacterLoader chrLoader;
private final NoteService noteService; private final NoteService noteService;
public PlayerLoggedinHandler(NoteService noteService) { public PlayerLoggedinHandler(CharacterLoader chrLoader, NoteService noteService) {
this.chrLoader = chrLoader;
this.noteService = noteService; this.noteService = noteService;
} }
@@ -94,7 +97,7 @@ public final class PlayerLoggedinHandler extends AbstractPacketHandler {
@Override @Override
public final void handlePacket(InPacket p, Client c) { public final void handlePacket(InPacket p, Client c) {
final int cid = p.readInt(); // TODO: investigate if this is the "client id" supplied in PacketCreator#getServerIP() final int chrId = p.readInt();
final Server server = Server.getInstance(); final Server server = Server.getInstance();
if (!c.tryacquireClient()) { if (!c.tryacquireClient()) {
@@ -120,7 +123,7 @@ public final class PlayerLoggedinHandler extends AbstractPacketHandler {
} }
} }
Character player = wserv.getPlayerStorage().getCharacterById(cid); Character player = wserv.getPlayerStorage().getCharacterById(chrId);
final Hwid hwid; final Hwid hwid;
if (player == null) { if (player == null) {
@@ -135,21 +138,18 @@ public final class PlayerLoggedinHandler extends AbstractPacketHandler {
c.setHwid(hwid); c.setHwid(hwid);
if (!server.validateCharacteridInTransition(c, cid)) { if (!server.validateCharacteridInTransition(c, chrId)) {
c.disconnect(true, false); c.disconnect(true, false);
return; return;
} }
boolean newcomer = false; boolean newcomer = false;
if (player == null) { if (player == null) {
try { Optional<Character> loadedChr = chrLoader.loadForChannel(chrId, c);
player = Character.loadCharFromDB(cid, c, true); if (loadedChr.isPresent()) {
player = loadedChr.get();
newcomer = true; newcomer = true;
} catch (SQLException e) { } else {
e.printStackTrace();
}
if (player == null) { //If you are still getting null here then please just uninstall the game >.>, we dont need you fucking with the logs
c.disconnect(true, false); c.disconnect(true, false);
return; return;
} }
@@ -212,13 +212,13 @@ public final class PlayerLoggedinHandler extends AbstractPacketHandler {
wserv.addPlayer(player); wserv.addPlayer(player);
player.setEnteredChannelWorld(); player.setEnteredChannelWorld();
List<PlayerBuffValueHolder> buffs = server.getPlayerBuffStorage().getBuffsFromStorage(cid); List<PlayerBuffValueHolder> buffs = server.getPlayerBuffStorage().getBuffsFromStorage(chrId);
if (buffs != null) { if (buffs != null) {
List<Pair<Long, PlayerBuffValueHolder>> timedBuffs = getLocalStartTimes(buffs); List<Pair<Long, PlayerBuffValueHolder>> timedBuffs = getLocalStartTimes(buffs);
player.silentGiveBuffs(timedBuffs); player.silentGiveBuffs(timedBuffs);
} }
Map<Disease, Pair<Long, MobSkill>> diseases = server.getPlayerBuffStorage().getDiseasesFromStorage(cid); Map<Disease, Pair<Long, MobSkill>> diseases = server.getPlayerBuffStorage().getDiseasesFromStorage(chrId);
if (diseases != null) { if (diseases != null) {
player.silentApplyDiseases(diseases); player.silentApplyDiseases(diseases);
} }
@@ -415,7 +415,7 @@ public final class PlayerLoggedinHandler extends AbstractPacketHandler {
} }
if (newcomer) { if (newcomer) {
EventInstanceManager eim = EventRecallCoordinator.getInstance().recallEventInstance(cid); EventInstanceManager eim = EventRecallCoordinator.getInstance().recallEventInstance(chrId);
if (eim != null) { if (eim != null) {
eim.registerPlayer(player); eim.registerPlayer(player);
} }

View File

@@ -16,6 +16,7 @@ import client.inventory.manipulator.InventoryManipulator;
import client.inventory.manipulator.KarmaManipulator; import client.inventory.manipulator.KarmaManipulator;
import config.YamlConfig; import config.YamlConfig;
import constants.inventory.ItemConstants; import constants.inventory.ItemConstants;
import database.character.CharacterSaver;
import net.AbstractPacketHandler; import net.AbstractPacketHandler;
import net.packet.InPacket; import net.packet.InPacket;
import org.slf4j.Logger; import org.slf4j.Logger;
@@ -32,6 +33,11 @@ import java.util.List;
*/ */
public final class WeddingHandler extends AbstractPacketHandler { public final class WeddingHandler extends AbstractPacketHandler {
private static final Logger log = LoggerFactory.getLogger(WeddingHandler.class); private static final Logger log = LoggerFactory.getLogger(WeddingHandler.class);
private final CharacterSaver chrSaver;
public WeddingHandler(CharacterSaver chrSaver) {
this.chrSaver = chrSaver;
}
@Override @Override
public void handlePacket(InPacket p, Client c) { public void handlePacket(InPacket p, Client c) {
@@ -87,9 +93,6 @@ public final class WeddingHandler extends AbstractPacketHandler {
} }
if (newItem != null) { if (newItem != null) {
if (YamlConfig.config.server.USE_ENFORCE_MERCHANT_SAVE) {
chr.saveCharToDB(false);
}
marriage.saveGiftItemsToDb(c, groomWishlist, cid); marriage.saveGiftItemsToDb(c, groomWishlist, cid);
} }
} else { } else {

View File

@@ -1,49 +0,0 @@
/*
This file is part of the HeavenMS MapleStory Server
Copyleft (L) 2016 - 2019 RonanLana
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation version 3 as published by
the Free Software Foundation. You may not use, modify or distribute
this program under any other version of the GNU Affero General Public
License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.server.task;
import client.Character;
import config.YamlConfig;
import net.server.PlayerStorage;
import net.server.world.World;
/**
* @author Ronan
*/
public class CharacterAutosaverTask extends BaseTask implements Runnable { // thanks Alex09 (Alex-0000) for noticing these runnable classes are tasks, "workers" runs them
@Override
public void run() {
if (!YamlConfig.config.server.USE_AUTOSAVE) {
return;
}
PlayerStorage ps = wserv.getPlayerStorage();
for (Character chr : ps.getAllCharacters()) {
if (chr != null && chr.isLoggedin()) {
chr.saveCharToDB(false);
}
}
}
public CharacterAutosaverTask(World world) {
super(world);
}
}

View File

@@ -196,7 +196,6 @@ public class World {
mountsSchedule = tman.register(new MountTirednessTask(this), MINUTES.toMillis(1), MINUTES.toMillis(1)); mountsSchedule = tman.register(new MountTirednessTask(this), MINUTES.toMillis(1), MINUTES.toMillis(1));
merchantSchedule = tman.register(new HiredMerchantTask(this), 10 * MINUTES.toMillis(1), 10 * MINUTES.toMillis(1)); merchantSchedule = tman.register(new HiredMerchantTask(this), 10 * MINUTES.toMillis(1), 10 * MINUTES.toMillis(1));
timedMapObjectsSchedule = tman.register(new TimedMapObjectTask(this), MINUTES.toMillis(1), MINUTES.toMillis(1)); timedMapObjectsSchedule = tman.register(new TimedMapObjectTask(this), MINUTES.toMillis(1), MINUTES.toMillis(1));
charactersSchedule = tman.register(new CharacterAutosaverTask(this), HOURS.toMillis(1), HOURS.toMillis(1));
marriagesSchedule = tman.register(new WeddingReservationTask(this), MINUTES.toMillis(YamlConfig.config.server.WEDDING_RESERVATION_INTERVAL), MINUTES.toMillis(YamlConfig.config.server.WEDDING_RESERVATION_INTERVAL)); marriagesSchedule = tman.register(new WeddingReservationTask(this), MINUTES.toMillis(YamlConfig.config.server.WEDDING_RESERVATION_INTERVAL), MINUTES.toMillis(YamlConfig.config.server.WEDDING_RESERVATION_INTERVAL));
mapOwnershipSchedule = tman.register(new MapOwnershipTask(this), SECONDS.toMillis(20), SECONDS.toMillis(20)); mapOwnershipSchedule = tman.register(new MapOwnershipTask(this), SECONDS.toMillis(20), SECONDS.toMillis(20));
fishingSchedule = tman.register(new FishingTask(this), SECONDS.toMillis(10), SECONDS.toMillis(10)); fishingSchedule = tman.register(new FishingTask(this), SECONDS.toMillis(10), SECONDS.toMillis(10));
@@ -2124,11 +2123,6 @@ public class World {
timedMapObjectsSchedule = null; timedMapObjectsSchedule = null;
} }
if (charactersSchedule != null) {
charactersSchedule.cancel(false);
charactersSchedule = null;
}
if (marriagesSchedule != null) { if (marriagesSchedule != null) {
marriagesSchedule.cancel(false); marriagesSchedule.cancel(false);
marriagesSchedule = null; marriagesSchedule = null;

View File

@@ -31,6 +31,7 @@ import client.inventory.manipulator.InventoryManipulator;
import client.inventory.manipulator.KarmaManipulator; import client.inventory.manipulator.KarmaManipulator;
import client.processor.npc.FredrickProcessor; import client.processor.npc.FredrickProcessor;
import config.YamlConfig; import config.YamlConfig;
import database.character.CharacterSaver;
import net.packet.Packet; import net.packet.Packet;
import net.server.Server; import net.server.Server;
import server.ItemInformationProvider; import server.ItemInformationProvider;
@@ -232,7 +233,7 @@ public class HiredMerchant extends AbstractMapObject {
} }
} }
public void takeItemBack(int slot, Character chr) { public void takeItemBack(int slot, Character chr, CharacterSaver chrSaver) {
synchronized (items) { synchronized (items) {
PlayerShopItem shopItem = items.get(slot); PlayerShopItem shopItem = items.get(slot);
if (shopItem.isExist()) { if (shopItem.isExist()) {
@@ -252,10 +253,6 @@ public class HiredMerchant extends AbstractMapObject {
removeFromSlot(slot); removeFromSlot(slot);
chr.sendPacket(PacketCreator.updateHiredMerchant(this, chr)); chr.sendPacket(PacketCreator.updateHiredMerchant(this, chr));
} }
if (YamlConfig.config.server.USE_ENFORCE_MERCHANT_SAVE) {
chr.saveCharToDB(false);
}
} }
} }
@@ -461,10 +458,6 @@ public class HiredMerchant extends AbstractMapObject {
} }
} }
if (YamlConfig.config.server.USE_ENFORCE_MERCHANT_SAVE) {
c.getPlayer().saveCharToDB(false);
}
synchronized (items) { synchronized (items) {
items.clear(); items.clear();
} }