Stat update & Mob skill animation & Yellow EXP patch + Packet logging
Solved a deadlock case within character stat locks that would sometimes tangle up during stat update dispatch operations. Fixed skill animation being unproperly casted when a mob tries to use a skill even though it couldn't possibly use from its current skillset. Fixed a bug with EXP gain (on where the solo player is on a party) where the EXP would appear in yellow even after soloing a mob. Added packet logging. Happy Easter, folks!
This commit is contained in:
@@ -1796,6 +1796,13 @@ Corrigido loot de party não funcionando adequadamente após updates recentes.
|
|||||||
Implementado loot de party agora atualizando também loots de jogadores ao entrar numa party (pronta permissão de coleta de loots de outros membros da party).
|
Implementado loot de party agora atualizando também loots de jogadores ao entrar numa party (pronta permissão de coleta de loots de outros membros da party).
|
||||||
Corrigido cooldown de skills de mob não atuando adequadamente.
|
Corrigido cooldown de skills de mob não atuando adequadamente.
|
||||||
|
|
||||||
|
08 - 09 Abril 2019,
|
||||||
|
Resolvido problema de deadlock envolvendo acesso a valores de stats de jogadores e diversas operações de despacho de update de stats.
|
||||||
|
Corrigido mob skills que não se encontram disponíveis sendo passados para o cliente para serem usados. Resultado disso era efeito visual de skill sendo mostrado ao usuário, habilidade sem ser aplicada em sequência.
|
||||||
|
|
||||||
|
12 Abril 2019,
|
||||||
|
Corrigido ganho visual do EXP de party ocasionalmente mostrando EXP em amarelo ao jogador em party solo.
|
||||||
|
|
||||||
15 Abril 2019,
|
15 Abril 2019,
|
||||||
Iniciado operação de introdução da AriantPQ no fonte, a partir do pull request feito pelo Dragohe4rt.
|
Iniciado operação de introdução da AriantPQ no fonte, a partir do pull request feito pelo Dragohe4rt.
|
||||||
Ajustado Dimensional Door, agora permitindo jogadores a entrar no saguão de entrada da AriantPQ.
|
Ajustado Dimensional Door, agora permitindo jogadores a entrar no saguão de entrada da AriantPQ.
|
||||||
@@ -1807,4 +1814,7 @@ Adicionado mecânica de número de jogadores requerido pelo líder de um lobby n
|
|||||||
Corrigido jogadores podendo criar/entrar em party dentro de instâncias da AriantPQ.
|
Corrigido jogadores podendo criar/entrar em party dentro de instâncias da AriantPQ.
|
||||||
Ajustado instância da AriantPQ para perdurar após o fim das batalhas (acesso a King's room ainda faz parte da instância, para adquirir os valores dos resultados do evento).
|
Ajustado instância da AriantPQ para perdurar após o fim das batalhas (acesso a King's room ainda faz parte da instância, para adquirir os valores dos resultados do evento).
|
||||||
Ajustado drops de mobs, agora sendo buscado na DB.
|
Ajustado drops de mobs, agora sendo buscado na DB.
|
||||||
Ajustado diversas mecânicas da AriantPQ, tais como update visual da pontuação de jogadores (ao dropar itens, ganhar itens, acessar mapa de evento), pontos de batalha persistindo na DB, etc.
|
Ajustado diversas mecânicas da AriantPQ, tais como update visual da pontuação de jogadores (ao dropar itens, ganhar itens, acessar mapa de evento), pontos de batalha persistindo na DB, etc.
|
||||||
|
|
||||||
|
21 Abril 2019,
|
||||||
|
Adicionado debug de packets descrito pelo Atoot.
|
||||||
@@ -32,12 +32,14 @@ import net.server.audit.locks.MonitoredLockType;
|
|||||||
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
|
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
|
||||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||||
import server.maps.AbstractAnimatedMapleMapObject;
|
import server.maps.AbstractAnimatedMapleMapObject;
|
||||||
|
import server.maps.MapleMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author RonanLana
|
* @author RonanLana
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMapleMapObject {
|
public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMapleMapObject {
|
||||||
|
protected MapleMap map;
|
||||||
protected int str, dex, luk, int_, hp, maxhp, mp, maxmp;
|
protected int str, dex, luk, int_, hp, maxhp, mp, maxmp;
|
||||||
protected int hpMpApUsed, remainingAp;
|
protected int hpMpApUsed, remainingAp;
|
||||||
protected int[] remainingSp = new int[10];
|
protected int[] remainingSp = new int[10];
|
||||||
@@ -65,6 +67,14 @@ public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMaple
|
|||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setMap(MapleMap map) {
|
||||||
|
this.map = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MapleMap getMap() {
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
public int getStr() {
|
public int getStr() {
|
||||||
statRlock.lock();
|
statRlock.lock();
|
||||||
try {
|
try {
|
||||||
@@ -202,16 +212,37 @@ public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMaple
|
|||||||
this.hpMpApUsed = mpApUsed;
|
this.hpMpApUsed = mpApUsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void dispatchHpChanged(int oldHp) {
|
private void dispatchHpChanged(final int oldHp) {
|
||||||
listener.onHpChanged(oldHp);
|
Runnable r = new Runnable() { // thanks BHB (BHB88) for detecting a deadlock case within player stats.
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
listener.onHpChanged(oldHp);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
map.registerCharacterStatUpdate(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void dispatchHpmpPoolUpdated() {
|
private void dispatchHpmpPoolUpdated() {
|
||||||
listener.onHpmpPoolUpdate();
|
Runnable r = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
listener.onHpmpPoolUpdate();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
map.registerCharacterStatUpdate(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void dispatchStatPoolUpdateAnnounced() {
|
private void dispatchStatPoolUpdateAnnounced() {
|
||||||
listener.onAnnounceStatPoolUpdate();
|
Runnable r = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
listener.onAnnounceStatPoolUpdate();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
map.registerCharacterStatUpdate(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setHp(int newHp) {
|
protected void setHp(int newHp) {
|
||||||
|
|||||||
@@ -229,7 +229,6 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
|||||||
private MaplePartyCharacter mpc = null;
|
private MaplePartyCharacter mpc = null;
|
||||||
private MapleInventory[] inventory;
|
private MapleInventory[] inventory;
|
||||||
private MapleJob job = MapleJob.BEGINNER;
|
private MapleJob job = MapleJob.BEGINNER;
|
||||||
private MapleMap map;
|
|
||||||
private MapleMessenger messenger = null;
|
private MapleMessenger messenger = null;
|
||||||
private MapleMiniGame miniGame;
|
private MapleMiniGame miniGame;
|
||||||
private MapleMount maplemount;
|
private MapleMount maplemount;
|
||||||
@@ -4847,10 +4846,6 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public MapleMap getMap() {
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getMapId() {
|
public int getMapId() {
|
||||||
if (map != null) {
|
if (map != null) {
|
||||||
return map.getId();
|
return map.getId();
|
||||||
@@ -8713,10 +8708,6 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
|||||||
public void setMap(int PmapId) {
|
public void setMap(int PmapId) {
|
||||||
this.mapid = PmapId;
|
this.mapid = PmapId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMap(MapleMap newmap) {
|
|
||||||
this.map = newmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMessenger(MapleMessenger messenger) {
|
public void setMessenger(MapleMessenger messenger) {
|
||||||
this.messenger = messenger;
|
this.messenger = messenger;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ package constants;
|
|||||||
|
|
||||||
public class CharsetConstants {
|
public class CharsetConstants {
|
||||||
|
|
||||||
public static MapleLanguageType MAPLE_TYPE = MapleLanguageType.LANGUAGE_PT_BR;
|
public static MapleLanguageType MAPLE_TYPE = MapleLanguageType.LANGUAGE_US;
|
||||||
|
|
||||||
public enum MapleLanguageType {
|
public enum MapleLanguageType {
|
||||||
LANGUAGE_PT_BR(1, "ISO-8859-1"),
|
LANGUAGE_PT_BR(1, "ISO-8859-1"),
|
||||||
|
|||||||
45
src/constants/OpcodeConstants.java
Normal file
45
src/constants/OpcodeConstants.java
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
|
||||||
|
Copyleft (L) 2016 - 2018 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 constants;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import net.opcodes.RecvOpcode;
|
||||||
|
import net.opcodes.SendOpcode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ronan
|
||||||
|
*/
|
||||||
|
public class OpcodeConstants {
|
||||||
|
public static Map<Integer, String> sendOpcodeNames = new HashMap<>();
|
||||||
|
public static Map<Integer, String> recvOpcodeNames = new HashMap<>();
|
||||||
|
|
||||||
|
public static void generateOpcodeNames() {
|
||||||
|
for (SendOpcode op : SendOpcode.values()) {
|
||||||
|
sendOpcodeNames.put(op.getValue(), op.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (RecvOpcode op : RecvOpcode.values()) {
|
||||||
|
recvOpcodeNames.put(op.getValue(), op.name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -62,6 +62,7 @@ public class ServerConstants {
|
|||||||
public static final boolean USE_DEBUG_SHOW_INFO_EQPEXP = false; //Prints on the cmd all equip exp gain info.
|
public static final boolean USE_DEBUG_SHOW_INFO_EQPEXP = false; //Prints on the cmd all equip exp gain info.
|
||||||
public static boolean USE_DEBUG_SHOW_RCVD_PACKET = false; //Prints on the cmd all received packet ids.
|
public static boolean USE_DEBUG_SHOW_RCVD_PACKET = false; //Prints on the cmd all received packet ids.
|
||||||
public static boolean USE_DEBUG_SHOW_RCVD_MVLIFE = false; //Prints on the cmd all received move life content.
|
public static boolean USE_DEBUG_SHOW_RCVD_MVLIFE = false; //Prints on the cmd all received move life content.
|
||||||
|
public static final boolean USE_DEBUG_SHOW_PACKET = false;
|
||||||
public static boolean USE_SUPPLY_RATE_COUPONS = true; //Allows rate coupons to be sold through the Cash Shop.
|
public static boolean USE_SUPPLY_RATE_COUPONS = true; //Allows rate coupons to be sold through the Cash Shop.
|
||||||
|
|
||||||
public static final boolean USE_MAXRANGE = true; //Will send and receive packets from all events on a map, rather than those of only view range.
|
public static final boolean USE_MAXRANGE = true; //Will send and receive packets from all events on a map, rather than those of only view range.
|
||||||
|
|||||||
@@ -21,13 +21,20 @@
|
|||||||
*/
|
*/
|
||||||
package net.mina;
|
package net.mina;
|
||||||
|
|
||||||
|
import constants.ServerConstants;
|
||||||
import client.MapleClient;
|
import client.MapleClient;
|
||||||
|
import constants.OpcodeConstants;
|
||||||
import net.server.coordinator.MapleSessionCoordinator;
|
import net.server.coordinator.MapleSessionCoordinator;
|
||||||
import org.apache.mina.core.buffer.IoBuffer;
|
import org.apache.mina.core.buffer.IoBuffer;
|
||||||
import org.apache.mina.core.session.IoSession;
|
import org.apache.mina.core.session.IoSession;
|
||||||
import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
|
import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
|
||||||
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
|
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
|
||||||
|
import tools.HexTool;
|
||||||
import tools.MapleAESOFB;
|
import tools.MapleAESOFB;
|
||||||
|
import tools.data.input.ByteArrayByteStream;
|
||||||
|
import tools.data.input.GenericLittleEndianAccessor;
|
||||||
|
import net.opcodes.RecvOpcode;
|
||||||
|
import tools.FilePrinter;
|
||||||
|
|
||||||
public class MaplePacketDecoder extends CumulativeProtocolDecoder {
|
public class MaplePacketDecoder extends CumulativeProtocolDecoder {
|
||||||
private static final String DECODER_STATE_KEY = MaplePacketDecoder.class.getName() + ".STATE";
|
private static final String DECODER_STATE_KEY = MaplePacketDecoder.class.getName() + ".STATE";
|
||||||
@@ -68,8 +75,32 @@ public class MaplePacketDecoder extends CumulativeProtocolDecoder {
|
|||||||
rcvdCrypto.crypt(decryptedPacket);
|
rcvdCrypto.crypt(decryptedPacket);
|
||||||
MapleCustomEncryption.decryptData(decryptedPacket);
|
MapleCustomEncryption.decryptData(decryptedPacket);
|
||||||
out.write(decryptedPacket);
|
out.write(decryptedPacket);
|
||||||
|
if (ServerConstants.USE_DEBUG_SHOW_PACKET){ // packet traffic log: Atoot's idea, applied using auto-identation thanks to lrenex
|
||||||
|
int packetLen = decryptedPacket.length;
|
||||||
|
int pHeader = readFirstShort(decryptedPacket);
|
||||||
|
String pHeaderStr = Integer.toHexString(pHeader).toUpperCase();
|
||||||
|
String op = lookupSend(pHeader);
|
||||||
|
String Send = "ClientSend:" + op + " [" + pHeaderStr + "] (" + packetLen + ")\r\n";
|
||||||
|
if (packetLen <= 3000) {
|
||||||
|
String SendTo = Send + HexTool.toString(decryptedPacket) + "\r\n" + HexTool.toStringFromAscii(decryptedPacket);
|
||||||
|
System.out.println(SendTo);
|
||||||
|
if (op == null) {
|
||||||
|
System.out.println("UnknownPacket:" + SendTo);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
FilePrinter.print(FilePrinter.PACKET_STREAM + MapleSessionCoordinator.getSessionRemoteAddress(session) + ".txt", HexTool.toString(new byte[]{decryptedPacket[0], decryptedPacket[1]}) + "...");
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String lookupSend(int val) {
|
||||||
|
return OpcodeConstants.recvOpcodeNames.get(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int readFirstShort(byte[] arr) {
|
||||||
|
return new GenericLittleEndianAccessor(new ByteArrayByteStream(arr)).readShort();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,12 +21,20 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
*/
|
*/
|
||||||
package net.mina;
|
package net.mina;
|
||||||
|
|
||||||
|
import constants.ServerConstants;
|
||||||
import client.MapleClient;
|
import client.MapleClient;
|
||||||
|
import constants.OpcodeConstants;
|
||||||
|
import net.opcodes.SendOpcode;
|
||||||
|
import net.server.coordinator.MapleSessionCoordinator;
|
||||||
import org.apache.mina.core.buffer.IoBuffer;
|
import org.apache.mina.core.buffer.IoBuffer;
|
||||||
import org.apache.mina.core.session.IoSession;
|
import org.apache.mina.core.session.IoSession;
|
||||||
import org.apache.mina.filter.codec.ProtocolEncoder;
|
import org.apache.mina.filter.codec.ProtocolEncoder;
|
||||||
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
|
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
|
||||||
import tools.MapleAESOFB;
|
import tools.MapleAESOFB;
|
||||||
|
import tools.HexTool;
|
||||||
|
import tools.data.input.ByteArrayByteStream;
|
||||||
|
import tools.data.input.GenericLittleEndianAccessor;
|
||||||
|
import tools.FilePrinter;
|
||||||
|
|
||||||
public class MaplePacketEncoder implements ProtocolEncoder {
|
public class MaplePacketEncoder implements ProtocolEncoder {
|
||||||
|
|
||||||
@@ -39,6 +47,23 @@ public class MaplePacketEncoder implements ProtocolEncoder {
|
|||||||
try {
|
try {
|
||||||
final MapleAESOFB send_crypto = client.getSendCrypto();
|
final MapleAESOFB send_crypto = client.getSendCrypto();
|
||||||
final byte[] input = (byte[]) message;
|
final byte[] input = (byte[]) message;
|
||||||
|
if (ServerConstants.USE_DEBUG_SHOW_PACKET) {
|
||||||
|
int packetLen = input.length;
|
||||||
|
int pHeader = readFirstShort(input);
|
||||||
|
String pHeaderStr = Integer.toHexString(pHeader).toUpperCase();
|
||||||
|
String op = lookupRecv(pHeader);
|
||||||
|
String Recv = "ServerSend:" + op + " [" + pHeaderStr + "] (" + packetLen + ")\r\n";
|
||||||
|
if (packetLen <= 50000) {
|
||||||
|
String RecvTo = Recv + HexTool.toString(input) + "\r\n" + HexTool.toStringFromAscii(input);
|
||||||
|
System.out.println(RecvTo);
|
||||||
|
if (op == null) {
|
||||||
|
System.out.println("UnknownPacket:" + RecvTo);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
FilePrinter.print(FilePrinter.PACKET_STREAM + MapleSessionCoordinator.getSessionRemoteAddress(session) + ".txt", HexTool.toString(new byte[]{input[0], input[1]}) + " ...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final byte[] unencrypted = new byte[input.length];
|
final byte[] unencrypted = new byte[input.length];
|
||||||
System.arraycopy(input, 0, unencrypted, 0, input.length);
|
System.arraycopy(input, 0, unencrypted, 0, input.length);
|
||||||
final byte[] ret = new byte[unencrypted.length + 4];
|
final byte[] ret = new byte[unencrypted.length + 4];
|
||||||
@@ -59,6 +84,14 @@ public class MaplePacketEncoder implements ProtocolEncoder {
|
|||||||
out.write(IoBuffer.wrap(((byte[]) message)));
|
out.write(IoBuffer.wrap(((byte[]) message)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String lookupRecv(int val) {
|
||||||
|
return OpcodeConstants.sendOpcodeNames.get(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int readFirstShort(byte[] arr) {
|
||||||
|
return new GenericLittleEndianAccessor(new ByteArrayByteStream(arr)).readShort();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dispose(IoSession session) throws Exception {}
|
public void dispose(IoSession session) throws Exception {}
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ import client.inventory.manipulator.MapleCashidGenerator;
|
|||||||
import client.newyear.NewYearCardRecord;
|
import client.newyear.NewYearCardRecord;
|
||||||
import constants.ItemConstants;
|
import constants.ItemConstants;
|
||||||
import constants.GameConstants;
|
import constants.GameConstants;
|
||||||
|
import constants.OpcodeConstants;
|
||||||
import constants.ServerConstants;
|
import constants.ServerConstants;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import net.server.coordinator.MapleSessionCoordinator;
|
import net.server.coordinator.MapleSessionCoordinator;
|
||||||
@@ -969,6 +970,7 @@ public class Server {
|
|||||||
online = true;
|
online = true;
|
||||||
|
|
||||||
MapleSkillbookInformationProvider.getInstance();
|
MapleSkillbookInformationProvider.getInstance();
|
||||||
|
OpcodeConstants.generateOpcodeNames();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String args[]) {
|
public static void main(String args[]) {
|
||||||
|
|||||||
@@ -126,7 +126,9 @@ public final class MoveLifeHandler extends AbstractMovementPacketHandler {
|
|||||||
nextSkillLevel = skillToUse.getRight();
|
nextSkillLevel = skillToUse.getRight();
|
||||||
nextUse = MobSkillFactory.getMobSkill(nextSkillId, nextSkillLevel);
|
nextUse = MobSkillFactory.getMobSkill(nextSkillId, nextSkillLevel);
|
||||||
|
|
||||||
if (!(nextUse != null && nextUse.getHP() >= (int) (((float) monster.getHp() / monster.getMaxHp()) * 100) && mobMp >= nextUse.getMpCon())) {
|
if (!(nextUse != null && monster.canUseSkill(nextUse) && nextUse.getHP() >= (int) (((float) monster.getHp() / monster.getMaxHp()) * 100) && mobMp >= nextUse.getMpCon())) {
|
||||||
|
// thanks OishiiKawaiiDesu for noticing mobs trying to cast skills they are not supposed to be able
|
||||||
|
|
||||||
nextSkillId = 0;
|
nextSkillId = 0;
|
||||||
nextSkillLevel = 0;
|
nextSkillLevel = 0;
|
||||||
nextUse = null;
|
nextUse = null;
|
||||||
|
|||||||
@@ -541,12 +541,14 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
avgExpReward += exp;
|
avgExpReward += exp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// thanks Simon for finding an issue with solo party player gaining yellow EXP when soloing mobs
|
||||||
|
float realAvgExpReward = avgExpReward;
|
||||||
avgExpReward -= exp2; // clear out the 20% raw exp from last hitting
|
avgExpReward -= exp2; // clear out the 20% raw exp from last hitting
|
||||||
avgExpReward /= personalExpReward.size();
|
avgExpReward /= personalExpReward.size();
|
||||||
|
|
||||||
float varExpReward = 0.0f;
|
float varExpReward = 0.0f;
|
||||||
for (Float exp : personalExpReward.values()) {
|
for (Float exp : personalExpReward.values()) {
|
||||||
varExpReward += Math.pow(exp - avgExpReward, 2);
|
varExpReward += Math.pow(exp - realAvgExpReward, 2);
|
||||||
}
|
}
|
||||||
varExpReward /= personalExpReward.size();
|
varExpReward /= personalExpReward.size();
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ public class FilePrinter {
|
|||||||
EXPLOITS = "game/exploits/",
|
EXPLOITS = "game/exploits/",
|
||||||
STORAGE = "game/storage/",
|
STORAGE = "game/storage/",
|
||||||
PACKET_LOGS = "game/packetlogs/",
|
PACKET_LOGS = "game/packetlogs/",
|
||||||
|
PACKET_STREAM = "game/packetstream/",
|
||||||
FREDRICK = "game/npcs/fredrick/",
|
FREDRICK = "game/npcs/fredrick/",
|
||||||
NPC_UNCODED = "game/npcs/UncodedNPCs.txt",
|
NPC_UNCODED = "game/npcs/UncodedNPCs.txt",
|
||||||
QUEST_UNCODED = "game/quests/UncodedQuests.txt",
|
QUEST_UNCODED = "game/quests/UncodedQuests.txt",
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
package tools;
|
package tools;
|
||||||
|
|
||||||
|
import constants.CharsetConstants;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
|
||||||
public class HexTool {
|
public class HexTool {
|
||||||
@@ -84,4 +85,23 @@ public class HexTool {
|
|||||||
}
|
}
|
||||||
return baos.toByteArray();
|
return baos.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final String toStringFromAscii(final byte[] bytes) {
|
||||||
|
byte[] ret = new byte[bytes.length];
|
||||||
|
for (int x = 0; x < bytes.length; x++) {
|
||||||
|
if (bytes[x] < 32 && bytes[x] >= 0) {
|
||||||
|
ret[x] = '.';
|
||||||
|
} else {
|
||||||
|
int chr = ((short) bytes[x]) & 0xFF;
|
||||||
|
ret[x] = (byte) chr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String encode = CharsetConstants.MAPLE_TYPE.getAscii();
|
||||||
|
try {
|
||||||
|
String str = new String(ret, encode);
|
||||||
|
return str;
|
||||||
|
} catch (Exception e) {}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user