From e30700de66a6c3ce46189c43ae04e04526b2f0a5 Mon Sep 17 00:00:00 2001 From: P0nk Date: Sat, 17 Aug 2024 21:27:43 +0200 Subject: [PATCH] Fix drop delay from summon attack --- .../channel/handlers/SummonDamageHandler.java | 72 ++++++++----------- src/main/java/tools/PacketCreator.java | 12 ++-- 2 files changed, 37 insertions(+), 47 deletions(-) diff --git a/src/main/java/net/server/channel/handlers/SummonDamageHandler.java b/src/main/java/net/server/channel/handlers/SummonDamageHandler.java index 82045ac142..b22e473b75 100644 --- a/src/main/java/net/server/channel/handlers/SummonDamageHandler.java +++ b/src/main/java/net/server/channel/handlers/SummonDamageHandler.java @@ -41,31 +41,14 @@ import server.life.MonsterInformationProvider; import server.maps.Summon; import tools.PacketCreator; +import java.awt.*; import java.util.ArrayList; import java.util.List; public final class SummonDamageHandler extends AbstractDealDamageHandler { private static final Logger log = LoggerFactory.getLogger(SummonDamageHandler.class); - public final class SummonAttackEntry { - - private final int monsterOid; - private final int damage; - - public SummonAttackEntry(int monsterOid, int damage) { - this.monsterOid = monsterOid; - this.damage = damage; - } - - public int getMonsterOid() { - return monsterOid; - } - - public int getDamage() { - return damage; - } - - } + public record SummonAttackTarget(int monsterOid, int damage, short delay) {} @Override public void handlePacket(InPacket p, Client c) { @@ -86,17 +69,21 @@ public final class SummonDamageHandler extends AbstractDealDamageHandler { Skill summonSkill = SkillFactory.getSkill(summon.getSkill()); StatEffect summonEffect = summonSkill.getEffect(summon.getSkillLevel()); p.skip(4); - List allDamage = new ArrayList<>(); + List targets = new ArrayList<>(); byte direction = p.readByte(); int numAttacked = p.readByte(); p.skip(8); // I failed lol (mob x,y and summon x,y), Thanks Gerald for (int x = 0; x < numAttacked; x++) { int monsterOid = p.readInt(); // attacked oid - p.skip(18); // TODO: find "delay" among these 18 skipped bytes + p.skip(8); + Point curPos = p.readPos(); + Point nextPos = p.readPos(); + short delay = p.readShort(); int damage = p.readInt(); - allDamage.add(new SummonAttackEntry(monsterOid, damage)); + targets.add(new SummonAttackTarget(monsterOid, damage, delay)); } - player.getMap().broadcastMessage(player, PacketCreator.summonAttack(player.getId(), summon.getObjectId(), direction, allDamage), summon.getPosition()); + player.getMap().broadcastMessage(player, PacketCreator.summonAttack(player.getId(), summon.getObjectId(), + direction, targets), summon.getPosition()); if (player.getMap().isOwnershipRestricted(player)) { return; @@ -104,25 +91,28 @@ public final class SummonDamageHandler extends AbstractDealDamageHandler { boolean magic = summonEffect.getWatk() == 0; int maxDmg = calcMaxDamage(summonEffect, player, magic); // thanks Darter (YungMoozi) for reporting unchecked max dmg - for (SummonAttackEntry attackEntry : allDamage) { - int damage = attackEntry.getDamage(); - Monster target = player.getMap().getMonsterByOid(attackEntry.getMonsterOid()); - if (target != null) { - if (damage > maxDmg) { - AutobanFactory.DAMAGE_HACK.alert(c.getPlayer(), "Possible packet editing summon damage exploit."); - final String mobName = MonsterInformationProvider.getInstance().getMobNameFromId(target.getId()); - log.info("Possible exploit - chr {} used a summon of skillId {} to attack {} with damage {} (max: {})", - c.getPlayer().getName(), summon.getSkill(), mobName, damage, maxDmg); - damage = maxDmg; - } - - if (damage > 0 && summonEffect.getMonsterStati().size() > 0) { - if (summonEffect.makeChanceResult()) { - target.applyStatus(player, new MonsterStatusEffect(summonEffect.getMonsterStati(), summonSkill, null, false), summonEffect.isPoison(), 4000); - } - } - player.getMap().damageMonster(player, target, damage); + for (SummonAttackTarget target : targets) { + int damage = target.damage(); + Monster mob = player.getMap().getMonsterByOid(target.monsterOid()); + if (mob == null) { + continue; } + + if (damage > maxDmg) { + AutobanFactory.DAMAGE_HACK.alert(c.getPlayer(), "Possible packet editing summon damage exploit."); + final String mobName = MonsterInformationProvider.getInstance().getMobNameFromId(mob.getId()); + log.info("Possible exploit - chr {} used a summon of skillId {} to attack {} with damage {} (max: {})", + c.getPlayer().getName(), summon.getSkill(), mobName, damage, maxDmg); + damage = maxDmg; + } + + if (damage > 0 && summonEffect.getMonsterStati().size() > 0) { + if (summonEffect.makeChanceResult()) { + mob.applyStatus(player, new MonsterStatusEffect(summonEffect.getMonsterStati(), summonSkill, null, false), summonEffect.isPoison(), 4000); + } + } + player.getMap().damageMonster(player, mob, damage, target.delay()); + } if (summon.getSkill() == Outlaw.GAVIOTA) { // thanks Periwinks for noticing Gaviota not cancelling after grenade toss diff --git a/src/main/java/tools/PacketCreator.java b/src/main/java/tools/PacketCreator.java index 3b328fe1b0..c302cfdb29 100644 --- a/src/main/java/tools/PacketCreator.java +++ b/src/main/java/tools/PacketCreator.java @@ -70,7 +70,7 @@ import net.server.Server; import net.server.channel.Channel; import net.server.channel.handlers.AbstractDealDamageHandler.AttackTarget; import net.server.channel.handlers.PlayerInteractionHandler; -import net.server.channel.handlers.SummonDamageHandler.SummonAttackEntry; +import net.server.channel.handlers.SummonDamageHandler.SummonAttackTarget; import net.server.channel.handlers.WhisperHandler; import net.server.guild.Alliance; import net.server.guild.Guild; @@ -2305,18 +2305,18 @@ public class PacketCreator { return p; } - public static Packet summonAttack(int cid, int summonOid, byte direction, List allDamage) { + public static Packet summonAttack(int cid, int summonOid, byte direction, List targets) { OutPacket p = OutPacket.create(SendOpcode.SUMMON_ATTACK); //b2 00 29 f7 00 00 9a a3 04 00 c8 04 01 94 a3 04 00 06 ff 2b 00 p.writeInt(cid); p.writeInt(summonOid); p.writeByte(0); // char level p.writeByte(direction); - p.writeByte(allDamage.size()); - for (SummonAttackEntry attackEntry : allDamage) { - p.writeInt(attackEntry.getMonsterOid()); // oid + p.writeByte(targets.size()); + for (SummonAttackTarget target : targets) { + p.writeInt(target.monsterOid()); // oid p.writeByte(6); // who knows - p.writeInt(attackEntry.getDamage()); // damage + p.writeInt(target.damage()); // damage } return p;