Move "steal item" logic to DropProvider
This commit is contained in:
@@ -2,10 +2,12 @@ package database.drop;
|
|||||||
|
|
||||||
import com.github.benmanes.caffeine.cache.Cache;
|
import com.github.benmanes.caffeine.cache.Cache;
|
||||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||||
|
import server.ItemInformationProvider;
|
||||||
import server.life.MonsterDropEntry;
|
import server.life.MonsterDropEntry;
|
||||||
import server.life.MonsterGlobalDropEntry;
|
import server.life.MonsterGlobalDropEntry;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
public class DropProvider {
|
public class DropProvider {
|
||||||
private final DropDao dropDao;
|
private final DropDao dropDao;
|
||||||
@@ -19,8 +21,12 @@ public class DropProvider {
|
|||||||
this.dropDao = dropDao;
|
this.dropDao = dropDao;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<MonsterDrop> getMonsterDrops(int monsterId) {
|
||||||
|
return monsterDropCache.get(monsterId, dropDao::getMonsterDrops);
|
||||||
|
}
|
||||||
|
|
||||||
public List<MonsterDropEntry> getMonsterDropEntries(int monsterId) {
|
public List<MonsterDropEntry> getMonsterDropEntries(int monsterId) {
|
||||||
return monsterDropCache.get(monsterId, dropDao::getMonsterDrops).stream()
|
return getMonsterDrops(monsterId).stream()
|
||||||
.map(this::mapToDropEntry)
|
.map(this::mapToDropEntry)
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
@@ -52,4 +58,37 @@ public class DropProvider {
|
|||||||
return new MonsterGlobalDropEntry(globalDrop.itemId(), globalDrop.chance(), globalDrop.continent(),
|
return new MonsterGlobalDropEntry(globalDrop.itemId(), globalDrop.chance(), globalDrop.continent(),
|
||||||
globalDrop.minQuantity(), globalDrop.maxQuantity(), questId);
|
globalDrop.minQuantity(), globalDrop.maxQuantity(), questId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The chance of an item to be stolen is calculated like this: (item chance) / (sum of all item chances)
|
||||||
|
* It works just like "lottery scheduling", but with droppable items instead of OS processes.
|
||||||
|
*/
|
||||||
|
public Optional<MonsterDropEntry> getRandomStealDrop(int monsterId) {
|
||||||
|
List<MonsterDrop> relevantDrops = getMonsterDrops(monsterId).stream()
|
||||||
|
.filter(this::isNonQuestItem)
|
||||||
|
.toList();
|
||||||
|
if (relevantDrops.isEmpty()) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
final long totalChance = relevantDrops.stream()
|
||||||
|
.mapToLong(MonsterDrop::chance)
|
||||||
|
.sum();
|
||||||
|
final long winningTicket = (long) Math.floor(Math.random() * totalChance);
|
||||||
|
|
||||||
|
long remainingChance = totalChance;
|
||||||
|
for (MonsterDrop drop : relevantDrops) {
|
||||||
|
remainingChance -= drop.chance();
|
||||||
|
if (winningTicket >= remainingChance) {
|
||||||
|
return Optional.of(mapToDropEntry(drop));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isNonQuestItem(MonsterDrop drop) {
|
||||||
|
ItemInformationProvider ii = ItemInformationProvider.getInstance();
|
||||||
|
return !ii.isQuestItem(drop.itemId()) && !ii.isPartyQuestItem(drop.itemId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,17 +2,20 @@ package net;
|
|||||||
|
|
||||||
import client.processor.action.MakerProcessor;
|
import client.processor.action.MakerProcessor;
|
||||||
import client.processor.npc.FredrickProcessor;
|
import client.processor.npc.FredrickProcessor;
|
||||||
|
import database.drop.DropProvider;
|
||||||
import service.NoteService;
|
import service.NoteService;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public record ChannelDependencies(
|
public record ChannelDependencies(
|
||||||
NoteService noteService, FredrickProcessor fredrickProcessor, MakerProcessor makerProcessor
|
NoteService noteService, FredrickProcessor fredrickProcessor, MakerProcessor makerProcessor,
|
||||||
|
DropProvider dropProvider
|
||||||
) {
|
) {
|
||||||
|
|
||||||
public ChannelDependencies {
|
public ChannelDependencies {
|
||||||
Objects.requireNonNull(noteService);
|
Objects.requireNonNull(noteService);
|
||||||
Objects.requireNonNull(fredrickProcessor);
|
Objects.requireNonNull(fredrickProcessor);
|
||||||
Objects.requireNonNull(makerProcessor);
|
Objects.requireNonNull(makerProcessor);
|
||||||
|
Objects.requireNonNull(dropProvider);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -155,9 +155,9 @@ public final class PacketProcessor {
|
|||||||
registerHandler(RecvOpcode.PLAYER_LOGGEDIN, new PlayerLoggedinHandler(channelDeps.noteService()));
|
registerHandler(RecvOpcode.PLAYER_LOGGEDIN, new PlayerLoggedinHandler(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());
|
registerHandler(RecvOpcode.CLOSE_RANGE_ATTACK, new CloseRangeDamageHandler(channelDeps.dropProvider()));
|
||||||
registerHandler(RecvOpcode.RANGED_ATTACK, new RangedAttackHandler());
|
registerHandler(RecvOpcode.RANGED_ATTACK, new RangedAttackHandler(channelDeps.dropProvider()));
|
||||||
registerHandler(RecvOpcode.MAGIC_ATTACK, new MagicDamageHandler());
|
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()));
|
registerHandler(RecvOpcode.USE_CASH_ITEM, new UseCashItemHandler(channelDeps.noteService()));
|
||||||
@@ -189,7 +189,7 @@ public final class PacketProcessor {
|
|||||||
registerHandler(RecvOpcode.ENTER_CASHSHOP, new EnterCashShopHandler());
|
registerHandler(RecvOpcode.ENTER_CASHSHOP, new EnterCashShopHandler());
|
||||||
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());
|
registerHandler(RecvOpcode.SUMMON_ATTACK, new SummonDamageHandler(channelDeps.dropProvider()));
|
||||||
registerHandler(RecvOpcode.BUDDYLIST_MODIFY, new BuddylistModifyHandler());
|
registerHandler(RecvOpcode.BUDDYLIST_MODIFY, new BuddylistModifyHandler());
|
||||||
registerHandler(RecvOpcode.USE_ITEMEFFECT, new UseItemEffectHandler());
|
registerHandler(RecvOpcode.USE_ITEMEFFECT, new UseItemEffectHandler());
|
||||||
registerHandler(RecvOpcode.USE_CHAIR, new UseChairHandler());
|
registerHandler(RecvOpcode.USE_CHAIR, new UseChairHandler());
|
||||||
@@ -225,7 +225,7 @@ public final class PacketProcessor {
|
|||||||
registerHandler(RecvOpcode.PET_EXCLUDE_ITEMS, new PetExcludeItemsHandler());
|
registerHandler(RecvOpcode.PET_EXCLUDE_ITEMS, new PetExcludeItemsHandler());
|
||||||
registerHandler(RecvOpcode.OWL_ACTION, new UseOwlOfMinervaHandler());
|
registerHandler(RecvOpcode.OWL_ACTION, new UseOwlOfMinervaHandler());
|
||||||
registerHandler(RecvOpcode.OWL_WARP, new OwlWarpHandler());
|
registerHandler(RecvOpcode.OWL_WARP, new OwlWarpHandler());
|
||||||
registerHandler(RecvOpcode.TOUCH_MONSTER_ATTACK, new TouchMonsterDamageHandler());
|
registerHandler(RecvOpcode.TOUCH_MONSTER_ATTACK, new TouchMonsterDamageHandler(channelDeps.dropProvider()));
|
||||||
registerHandler(RecvOpcode.TROCK_ADD_MAP, new TrockAddMapHandler());
|
registerHandler(RecvOpcode.TROCK_ADD_MAP, new TrockAddMapHandler());
|
||||||
registerHandler(RecvOpcode.HIRED_MERCHANT_REQUEST, new HiredMerchantRequest());
|
registerHandler(RecvOpcode.HIRED_MERCHANT_REQUEST, new HiredMerchantRequest());
|
||||||
registerHandler(RecvOpcode.MOB_BANISH_PLAYER, new MobBanishPlayerHandler());
|
registerHandler(RecvOpcode.MOB_BANISH_PLAYER, new MobBanishPlayerHandler());
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ 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.drop.DropDao;
|
||||||
|
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;
|
||||||
@@ -974,8 +976,9 @@ public class Server {
|
|||||||
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));
|
||||||
ChannelDependencies channelDependencies = new ChannelDependencies(noteService, fredrickProcessor,
|
ChannelDependencies channelDependencies = new ChannelDependencies(noteService, fredrickProcessor,
|
||||||
makerProcessor);
|
makerProcessor, dropProvider);
|
||||||
|
|
||||||
PacketProcessor.registerGameHandlerDependencies(channelDependencies);
|
PacketProcessor.registerGameHandlerDependencies(channelDependencies);
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import constants.id.ItemId;
|
|||||||
import constants.id.MapId;
|
import constants.id.MapId;
|
||||||
import constants.id.MobId;
|
import constants.id.MobId;
|
||||||
import constants.skills.*;
|
import constants.skills.*;
|
||||||
|
import database.drop.DropProvider;
|
||||||
import net.AbstractPacketHandler;
|
import net.AbstractPacketHandler;
|
||||||
import net.packet.InPacket;
|
import net.packet.InPacket;
|
||||||
import net.server.PlayerBuffValueHolder;
|
import net.server.PlayerBuffValueHolder;
|
||||||
@@ -54,6 +55,11 @@ import static java.util.concurrent.TimeUnit.MINUTES;
|
|||||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||||
|
|
||||||
public abstract class AbstractDealDamageHandler extends AbstractPacketHandler {
|
public abstract class AbstractDealDamageHandler extends AbstractPacketHandler {
|
||||||
|
private final DropProvider dropProvider;
|
||||||
|
|
||||||
|
public AbstractDealDamageHandler(DropProvider dropProvider) {
|
||||||
|
this.dropProvider = dropProvider;
|
||||||
|
}
|
||||||
|
|
||||||
public static class AttackInfo {
|
public static class AttackInfo {
|
||||||
|
|
||||||
@@ -284,25 +290,14 @@ public abstract class AbstractDealDamageHandler extends AbstractPacketHandler {
|
|||||||
player.addHP(Math.min(monster.getMaxHp(), Math.min((int) ((double) totDamage * (double) SkillFactory.getSkill(attack.skill).getEffect(player.getSkillLevel(SkillFactory.getSkill(attack.skill))).getX() / 100.0), player.getCurrentMaxHp() / 2)));
|
player.addHP(Math.min(monster.getMaxHp(), Math.min((int) ((double) totDamage * (double) SkillFactory.getSkill(attack.skill).getEffect(player.getSkillLevel(SkillFactory.getSkill(attack.skill))).getX() / 100.0), player.getCurrentMaxHp() / 2)));
|
||||||
} else if (attack.skill == Bandit.STEAL) {
|
} else if (attack.skill == Bandit.STEAL) {
|
||||||
Skill steal = SkillFactory.getSkill(Bandit.STEAL);
|
Skill steal = SkillFactory.getSkill(Bandit.STEAL);
|
||||||
if (monster.getStolen().size() < 1) { // One steal per mob <3
|
if (monster.getStolen().isEmpty()) { // One steal per mob <3
|
||||||
if (steal.getEffect(player.getSkillLevel(steal)).makeChanceResult()) {
|
if (steal.getEffect(player.getSkillLevel(steal)).makeChanceResult()) {
|
||||||
monster.addStolen(0);
|
monster.addStolen(0);
|
||||||
|
|
||||||
MonsterInformationProvider mi = MonsterInformationProvider.getInstance();
|
Optional<MonsterDropEntry> stolenItem = dropProvider.getRandomStealDrop(monster.getId());
|
||||||
List<Integer> dropPool = mi.retrieveDropPool(monster.getId());
|
if (stolenItem.isPresent()) {
|
||||||
if (!dropPool.isEmpty()) {
|
map.dropItemsFromMonster(Collections.singletonList(stolenItem.get()), player, monster);
|
||||||
int rndPool = (int) Math.floor(Math.random() * dropPool.get(dropPool.size() - 1));
|
monster.addStolen(stolenItem.get().itemId);
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
while (rndPool >= dropPool.get(i)) {
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<MonsterDropEntry> toSteal = new ArrayList<>();
|
|
||||||
toSteal.add(mi.retrieveDrop(monster.getId()).get(i));
|
|
||||||
|
|
||||||
map.dropItemsFromMonster(toSteal, player, monster);
|
|
||||||
monster.addStolen(toSteal.get(0).itemId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import config.YamlConfig;
|
|||||||
import constants.game.GameConstants;
|
import constants.game.GameConstants;
|
||||||
import constants.id.MapId;
|
import constants.id.MapId;
|
||||||
import constants.skills.*;
|
import constants.skills.*;
|
||||||
|
import database.drop.DropProvider;
|
||||||
import net.packet.InPacket;
|
import net.packet.InPacket;
|
||||||
import server.StatEffect;
|
import server.StatEffect;
|
||||||
import tools.PacketCreator;
|
import tools.PacketCreator;
|
||||||
@@ -40,6 +41,10 @@ import static java.util.concurrent.TimeUnit.SECONDS;
|
|||||||
|
|
||||||
public final class CloseRangeDamageHandler extends AbstractDealDamageHandler {
|
public final class CloseRangeDamageHandler extends AbstractDealDamageHandler {
|
||||||
|
|
||||||
|
public CloseRangeDamageHandler(DropProvider dropProvider) {
|
||||||
|
super(dropProvider);
|
||||||
|
}
|
||||||
|
|
||||||
@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();
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import constants.skills.Bishop;
|
|||||||
import constants.skills.Evan;
|
import constants.skills.Evan;
|
||||||
import constants.skills.FPArchMage;
|
import constants.skills.FPArchMage;
|
||||||
import constants.skills.ILArchMage;
|
import constants.skills.ILArchMage;
|
||||||
|
import database.drop.DropProvider;
|
||||||
import net.packet.InPacket;
|
import net.packet.InPacket;
|
||||||
import net.packet.Packet;
|
import net.packet.Packet;
|
||||||
import server.StatEffect;
|
import server.StatEffect;
|
||||||
@@ -37,6 +38,10 @@ import tools.PacketCreator;
|
|||||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||||
|
|
||||||
public final class MagicDamageHandler extends AbstractDealDamageHandler {
|
public final class MagicDamageHandler extends AbstractDealDamageHandler {
|
||||||
|
|
||||||
|
public MagicDamageHandler(DropProvider dropProvider) {
|
||||||
|
super(dropProvider);
|
||||||
|
}
|
||||||
@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();
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import constants.id.ItemId;
|
|||||||
import constants.id.MapId;
|
import constants.id.MapId;
|
||||||
import constants.inventory.ItemConstants;
|
import constants.inventory.ItemConstants;
|
||||||
import constants.skills.*;
|
import constants.skills.*;
|
||||||
|
import database.drop.DropProvider;
|
||||||
import net.packet.InPacket;
|
import net.packet.InPacket;
|
||||||
import net.packet.Packet;
|
import net.packet.Packet;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -48,6 +49,10 @@ import static java.util.concurrent.TimeUnit.SECONDS;
|
|||||||
public final class RangedAttackHandler extends AbstractDealDamageHandler {
|
public final class RangedAttackHandler extends AbstractDealDamageHandler {
|
||||||
private static final Logger log = LoggerFactory.getLogger(RangedAttackHandler.class);
|
private static final Logger log = LoggerFactory.getLogger(RangedAttackHandler.class);
|
||||||
|
|
||||||
|
public RangedAttackHandler(DropProvider dropProvider) {
|
||||||
|
super(dropProvider);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handlePacket(InPacket p, Client c) {
|
public void handlePacket(InPacket p, Client c) {
|
||||||
Character chr = c.getPlayer();
|
Character chr = c.getPlayer();
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import client.inventory.Item;
|
|||||||
import client.inventory.WeaponType;
|
import client.inventory.WeaponType;
|
||||||
import client.status.MonsterStatusEffect;
|
import client.status.MonsterStatusEffect;
|
||||||
import constants.skills.Outlaw;
|
import constants.skills.Outlaw;
|
||||||
|
import database.drop.DropProvider;
|
||||||
import net.packet.InPacket;
|
import net.packet.InPacket;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -47,6 +48,10 @@ import java.util.List;
|
|||||||
public final class SummonDamageHandler extends AbstractDealDamageHandler {
|
public final class SummonDamageHandler extends AbstractDealDamageHandler {
|
||||||
private static final Logger log = LoggerFactory.getLogger(SummonDamageHandler.class);
|
private static final Logger log = LoggerFactory.getLogger(SummonDamageHandler.class);
|
||||||
|
|
||||||
|
public SummonDamageHandler(DropProvider dropProvider) {
|
||||||
|
super(dropProvider);
|
||||||
|
}
|
||||||
|
|
||||||
public final class SummonAttackEntry {
|
public final class SummonAttackEntry {
|
||||||
|
|
||||||
private final int monsterOid;
|
private final int monsterOid;
|
||||||
|
|||||||
@@ -24,9 +24,15 @@ package net.server.channel.handlers;
|
|||||||
import client.BuffStat;
|
import client.BuffStat;
|
||||||
import client.Character;
|
import client.Character;
|
||||||
import client.Client;
|
import client.Client;
|
||||||
|
import database.drop.DropProvider;
|
||||||
import net.packet.InPacket;
|
import net.packet.InPacket;
|
||||||
|
|
||||||
public final class TouchMonsterDamageHandler extends AbstractDealDamageHandler {
|
public final class TouchMonsterDamageHandler extends AbstractDealDamageHandler {
|
||||||
|
|
||||||
|
public TouchMonsterDamageHandler(DropProvider dropProvider) {
|
||||||
|
super(dropProvider);
|
||||||
|
}
|
||||||
|
|
||||||
@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();
|
||||||
|
|||||||
@@ -104,4 +104,6 @@ class DropProviderTest {
|
|||||||
verify(dropDao, times(1)).getGlobalMonsterDrops();
|
verify(dropDao, times(1)).getGlobalMonsterDrops();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: add tests for getRandomStealDrop() once ItemInformationProvider is able to be mocked.
|
||||||
|
// Currently, it does database calls (and a bunch of other stuff) in the constructor, which is problematic.
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user