Stat pool & Skills on change field Patch + Elemental Charge broadcast

Patched account storages not getting cached properly at login time.
Reviewed item acquisition at the Cash Shop happening before point transaction.
EXP toggle flag now also works on equipment gains.
Factored several skills (Energy Charge, Wind Walk, Dash) not updating properly other players when changing maps.
Refactored stat pool system, which wasn't working properly on limit scenarios.
Fixed "untradeable at wear"equipments losing flags upon equipping.
Reviewed Inventory Sort, now sorting projectiles at descending order on damage.
Implemented support for visibility of effects on weapons imbued with Charge skill (e.g. Paladin's Holy Charge) for other players.
This commit is contained in:
ronancpl
2019-12-07 03:05:26 -03:00
parent 06b43d9e07
commit 8afbff9db9
23 changed files with 356 additions and 237 deletions

View File

@@ -894,33 +894,8 @@ public class Server {
//MaplePet.clearMissingPetsFromDb(); // thanks Optimist for noticing this taking too long to run
MapleCashidGenerator.loadExistentCashIdsFromDb();
IoBuffer.setUseDirectBuffer(false);
IoBuffer.setAllocator(new SimpleBufferAllocator());
acceptor = new NioSocketAcceptor();
acceptor.getFilterChain().addLast("codec", (IoFilter) new ProtocolCodecFilter(new MapleCodecFactory()));
ThreadManager.getInstance().start();
TimerManager tMan = TimerManager.getInstance();
tMan.start();
tMan.register(tMan.purge(), YamlConfig.config.server.PURGING_INTERVAL);//Purging ftw...
disconnectIdlesOnLoginTask();
long timeLeft = getTimeLeftForNextHour();
tMan.register(new CharacterDiseaseTask(), YamlConfig.config.server.UPDATE_INTERVAL, YamlConfig.config.server.UPDATE_INTERVAL);
tMan.register(new ReleaseLockTask(), 2 * 60 * 1000, 2 * 60 * 1000);
tMan.register(new CouponTask(), YamlConfig.config.server.COUPON_INTERVAL, timeLeft);
tMan.register(new RankingCommandTask(), 5 * 60 * 1000, 5 * 60 * 1000);
tMan.register(new RankingLoginTask(), YamlConfig.config.server.RANKING_INTERVAL, timeLeft);
tMan.register(new LoginCoordinatorTask(), 60 * 60 * 1000, timeLeft);
tMan.register(new EventRecallCoordinatorTask(), 60 * 60 * 1000, timeLeft);
tMan.register(new LoginStorageTask(), 2 * 60 * 1000, 2 * 60 * 1000);
tMan.register(new DueyFredrickTask(), 60 * 60 * 1000, timeLeft);
tMan.register(new InvitationTask(), 30 * 1000, 30 * 1000);
tMan.register(new RespawnTask(), YamlConfig.config.server.RESPAWN_INTERVAL, YamlConfig.config.server.RESPAWN_INTERVAL);
timeLeft = getTimeLeftForNextDay();
MapleExpeditionBossLog.resetBossLogTable();
tMan.register(new BossLogTask(), 24 * 60 * 60 * 1000, timeLeft);
initializeTimelyTasks(); // aggregated method for timely tasks thanks to lxconan
long timeToTake = System.currentTimeMillis();
SkillFactory.loadAllSkills();
@@ -965,6 +940,10 @@ public class Server {
System.out.println();
IoBuffer.setUseDirectBuffer(false); // join IO operations performed by lxconan
IoBuffer.setAllocator(new SimpleBufferAllocator());
acceptor = new NioSocketAcceptor();
acceptor.getFilterChain().addLast("codec", (IoFilter) new ProtocolCodecFilter(new MapleCodecFactory()));
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 30);
acceptor.setHandler(new MapleServerHandler());
try {
@@ -986,6 +965,30 @@ public class Server {
ch.reloadEventScriptManager();
}
}
private void initializeTimelyTasks() {
TimerManager tMan = TimerManager.getInstance();
tMan.start();
tMan.register(tMan.purge(), YamlConfig.config.server.PURGING_INTERVAL);//Purging ftw...
disconnectIdlesOnLoginTask();
long timeLeft = getTimeLeftForNextHour();
tMan.register(new CharacterDiseaseTask(), YamlConfig.config.server.UPDATE_INTERVAL, YamlConfig.config.server.UPDATE_INTERVAL);
tMan.register(new ReleaseLockTask(), 2 * 60 * 1000, 2 * 60 * 1000);
tMan.register(new CouponTask(), YamlConfig.config.server.COUPON_INTERVAL, timeLeft);
tMan.register(new RankingCommandTask(), 5 * 60 * 1000, 5 * 60 * 1000);
tMan.register(new RankingLoginTask(), YamlConfig.config.server.RANKING_INTERVAL, timeLeft);
tMan.register(new LoginCoordinatorTask(), 60 * 60 * 1000, timeLeft);
tMan.register(new EventRecallCoordinatorTask(), 60 * 60 * 1000, timeLeft);
tMan.register(new LoginStorageTask(), 2 * 60 * 1000, 2 * 60 * 1000);
tMan.register(new DueyFredrickTask(), 60 * 60 * 1000, timeLeft);
tMan.register(new InvitationTask(), 30 * 1000, 30 * 1000);
tMan.register(new RespawnTask(), YamlConfig.config.server.RESPAWN_INTERVAL, YamlConfig.config.server.RESPAWN_INTERVAL);
timeLeft = getTimeLeftForNextDay();
MapleExpeditionBossLog.resetBossLogTable();
tMan.register(new BossLogTask(), 24 * 60 * 60 * 1000, timeLeft);
}
public static void main(String args[]) {
System.setProperty("wzpath", "wz");
@@ -1755,7 +1758,7 @@ public class Server {
for (Integer worldid : accWorlds) {
if (worldid < worldList.size()) {
World wserv = worldList.get(worldid);
wserv.registerAccountStorage(accountId);
wserv.loadAccountStorage(accountId);
}
}
}

View File

@@ -0,0 +1,24 @@
package net.server.audit.locks.empty;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public abstract class AbstractEmptyLock {
protected static String printThreadStack(StackTraceElement[] list) {
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); // DRY-code opportunity performed by jtumidanski
dateFormat.setTimeZone(TimeZone.getDefault());
String df = dateFormat.format(new Date());
String s = "\r\n" + df + "\r\n";
for(int i = 0; i < list.length; i++) {
s += (" " + list[i].toString() + "\r\n");
}
s += "----------------------------\r\n\r\n";
return s;
}
}

View File

@@ -19,11 +19,6 @@
*/
package net.server.audit.locks.empty;
import constants.net.ServerConstants;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.MonitoredReadLock;
import tools.FilePrinter;
@@ -32,27 +27,13 @@ import tools.FilePrinter;
*
* @author RonanLana
*/
public class EmptyReadLock implements MonitoredReadLock {
public class EmptyReadLock extends AbstractEmptyLock implements MonitoredReadLock {
private final MonitoredLockType id;
public EmptyReadLock(MonitoredLockType type) {
this.id = type;
}
private static String printThreadStack(StackTraceElement[] list) {
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getDefault());
String df = dateFormat.format(new Date());
String s = "\r\n" + df + "\r\n";
for(int i = 0; i < list.length; i++) {
s += (" " + list[i].toString() + "\r\n");
}
s += "----------------------------\r\n\r\n";
return s;
}
@Override
public void lock() {
FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace()));

View File

@@ -19,11 +19,6 @@
*/
package net.server.audit.locks.empty;
import constants.net.ServerConstants;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.MonitoredReentrantLock;
import tools.FilePrinter;
@@ -32,27 +27,13 @@ import tools.FilePrinter;
*
* @author RonanLana
*/
public class EmptyReentrantLock implements MonitoredReentrantLock {
public class EmptyReentrantLock extends AbstractEmptyLock implements MonitoredReentrantLock {
private final MonitoredLockType id;
public EmptyReentrantLock(MonitoredLockType type) {
this.id = type;
}
private static String printThreadStack(StackTraceElement[] list) {
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getDefault());
String df = dateFormat.format(new Date());
String s = "\r\n" + df + "\r\n";
for(int i = 0; i < list.length; i++) {
s += (" " + list[i].toString() + "\r\n");
}
s += "----------------------------\r\n\r\n";
return s;
}
@Override
public void lock() {
FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace()));

View File

@@ -19,11 +19,6 @@
*/
package net.server.audit.locks.empty;
import constants.net.ServerConstants;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.MonitoredWriteLock;
import tools.FilePrinter;
@@ -32,27 +27,13 @@ import tools.FilePrinter;
*
* @author RonanLana
*/
public class EmptyWriteLock implements MonitoredWriteLock {
public class EmptyWriteLock extends AbstractEmptyLock implements MonitoredWriteLock {
private final MonitoredLockType id;
public EmptyWriteLock(MonitoredLockType type) {
this.id = type;
}
private static String printThreadStack(StackTraceElement[] list) {
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getDefault());
String df = dateFormat.format(new Date());
String s = "\r\n" + df + "\r\n";
for(int i = 0; i < list.length; i++) {
s += (" " + list[i].toString() + "\r\n");
}
s += "----------------------------\r\n\r\n";
return s;
}
@Override
public void lock() {
FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace()));

View File

@@ -86,16 +86,18 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
}
Item item = cItem.toItem();
cs.gainCash(useNX, cItem, chr.getWorld()); // thanks Rohenn for noticing cash operations after item acquisition
cs.addToInventory(item);
c.announce(MaplePacketCreator.showBoughtCashItem(item, c.getAccID()));
} else { // Package
cs.gainCash(useNX, cItem, chr.getWorld());
List<Item> cashPackage = CashItemFactory.getPackage(cItem.getItemId());
for (Item item : cashPackage) {
cs.addToInventory(item);
}
c.announce(MaplePacketCreator.showBoughtCashPackage(cashPackage, c.getAccID()));
}
cs.gainCash(useNX, cItem, chr.getWorld());
c.announce(MaplePacketCreator.showCash(chr));
} else if (action == 0x04) {//TODO check for gender
int birthday = slea.readInt();
@@ -116,9 +118,9 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
c.announce(MaplePacketCreator.showCashShopMessage((byte) 0xA8));
return;
}
cs.gainCash(4, cItem, chr.getWorld());
cs.gift(Integer.parseInt(recipient.get("id")), chr.getName(), message, cItem.getSN());
c.announce(MaplePacketCreator.showGiftSucceed(recipient.get("name"), cItem));
cs.gainCash(4, cItem, chr.getWorld());
c.announce(MaplePacketCreator.showCash(chr));
try {
chr.sendNote(recipient.get("name"), chr.getName() + " has sent you a gift! Go check out the Cash Shop.", (byte) 0); //fame or not
@@ -147,10 +149,17 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
c.enableCSActions();
return;
}
if (chr.gainSlots(type, 4, false)) {
int qty = 4;
if (!chr.canGainSlots(type, qty)) {
c.enableCSActions();
return;
}
cs.gainCash(cash, -4000);
if (chr.gainSlots(type, qty, false)) {
c.announce(MaplePacketCreator.showBoughtInventorySlots(type, chr.getSlots(type)));
cs.gainCash(cash, -4000);
c.announce(MaplePacketCreator.showCash(chr));
} else {
FilePrinter.printError(FilePrinter.CASHITEM_BOUGHT, "Could not add " + qty + " slots of type " + type + " for player " + MapleCharacter.makeMapleReadable(chr.getName()));
}
} else {
CashItem cItem = CashItemFactory.getItem(slea.readInt());
@@ -159,10 +168,17 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
c.enableCSActions();
return;
}
if (chr.gainSlots(type, 8, false)) {
int qty = 8;
if (!chr.canGainSlots(type, qty)) {
c.enableCSActions();
return;
}
cs.gainCash(cash, cItem, chr.getWorld());
if (chr.gainSlots(type, qty, false)) {
c.announce(MaplePacketCreator.showBoughtInventorySlots(type, chr.getSlots(type)));
cs.gainCash(cash, cItem, chr.getWorld());
c.announce(MaplePacketCreator.showCash(chr));
} else {
FilePrinter.printError(FilePrinter.CASHITEM_BOUGHT, "Could not add " + qty + " slots of type " + type + " for player " + MapleCharacter.makeMapleReadable(chr.getName()));
}
}
} else if (action == 0x07) { // Increase Storage Slots
@@ -174,13 +190,20 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
c.enableCSActions();
return;
}
if (chr.getStorage().gainSlots(4)) {
FilePrinter.print(FilePrinter.STORAGE + c.getAccountName() + ".txt", c.getPlayer().getName() + " bought 4 slots to their account storage.");
int qty = 4;
if (!chr.getStorage().canGainSlots(qty)) {
c.enableCSActions();
return;
}
cs.gainCash(cash, -4000);
if (chr.getStorage().gainSlots(qty)) {
FilePrinter.print(FilePrinter.STORAGE + c.getAccountName() + ".txt", c.getPlayer().getName() + " bought " + qty + " slots to their account storage.");
chr.setUsedStorage();
c.announce(MaplePacketCreator.showBoughtStorageSlots(chr.getStorage().getSlots()));
cs.gainCash(cash, -4000);
c.announce(MaplePacketCreator.showCash(chr));
} else {
FilePrinter.printError(FilePrinter.CASHITEM_BOUGHT, "Could not add " + qty + " slots to " + MapleCharacter.makeMapleReadable(chr.getName()) + "'s account.");
}
} else {
CashItem cItem = CashItemFactory.getItem(slea.readInt());
@@ -189,13 +212,20 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
c.enableCSActions();
return;
}
if (chr.getStorage().gainSlots(8)) { // thanks ABaldParrot & Thora for detecting storage issues here
FilePrinter.print(FilePrinter.STORAGE + c.getAccountName() + ".txt", c.getPlayer().getName() + " bought 8 slots to their account storage.");
int qty = 8;
if (!chr.getStorage().canGainSlots(qty)) {
c.enableCSActions();
return;
}
cs.gainCash(cash, cItem, chr.getWorld());
if (chr.getStorage().gainSlots(qty)) { // thanks ABaldParrot & Thora for detecting storage issues here
FilePrinter.print(FilePrinter.STORAGE + c.getAccountName() + ".txt", c.getPlayer().getName() + " bought " + qty + " slots to their account storage.");
chr.setUsedStorage();
c.announce(MaplePacketCreator.showBoughtStorageSlots(chr.getStorage().getSlots()));
cs.gainCash(cash, cItem, chr.getWorld());
c.announce(MaplePacketCreator.showCash(chr));
} else {
FilePrinter.printError(FilePrinter.CASHITEM_BOUGHT, "Could not add " + qty + " slots to " + MapleCharacter.makeMapleReadable(chr.getName()) + "'s account.");
}
}
} else if (action == 0x08) { // Increase Character Slots
@@ -207,13 +237,17 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
c.enableCSActions();
return;
}
if (!c.canGainCharacterSlot()) {
chr.dropMessage(1, "You have already used up all 12 extra character slots.");
c.enableCSActions();
return;
}
cs.gainCash(cash, cItem, chr.getWorld());
if (c.gainCharacterSlot()) {
c.announce(MaplePacketCreator.showBoughtCharacterSlot(c.getCharacterSlots()));
cs.gainCash(cash, cItem, chr.getWorld());
c.announce(MaplePacketCreator.showCash(chr));
} else {
chr.dropMessage(1, "You have already used up all 12 extra character slots.");
FilePrinter.printError(FilePrinter.CASHITEM_BOUGHT, "Could not add a character slot to " + MapleCharacter.makeMapleReadable(chr.getName()) + "'s account.");
c.enableCSActions();
return;
}
@@ -287,8 +321,8 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
eqp.setRingId(rings.getLeft());
cs.addToInventory(eqp);
c.announce(MaplePacketCreator.showBoughtCashItem(eqp, c.getAccID()));
cs.gift(partner.getId(), chr.getName(), text, eqp.getSN(), rings.getRight());
cs.gainCash(toCharge, itemRing, chr.getWorld());
cs.gift(partner.getId(), chr.getName(), text, eqp.getSN(), rings.getRight());
chr.addCrushRing(MapleRing.loadFromDb(rings.getLeft()));
try {
chr.sendNote(partner.getName(), text, (byte) 1);
@@ -353,8 +387,8 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
eqp.setRingId(rings.getLeft());
cs.addToInventory(eqp);
c.announce(MaplePacketCreator.showBoughtCashRing(eqp, partner.getName(), c.getAccID()));
cs.gift(partner.getId(), chr.getName(), text, eqp.getSN(), rings.getRight());
cs.gainCash(payment, -itemRing.getPrice());
cs.gift(partner.getId(), chr.getName(), text, eqp.getSN(), rings.getRight());
chr.addFriendshipRing(MapleRing.loadFromDb(rings.getLeft()));
try {
chr.sendNote(partner.getName(), text, (byte) 1);
@@ -391,8 +425,8 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
if(chr.registerNameChange(newName)) { //success
Item item = cItem.toItem();
c.announce(MaplePacketCreator.showNameChangeSuccess(item, c.getAccID()));
cs.addToInventory(item);
cs.gainCash(4, cItem, chr.getWorld());
cs.addToInventory(item);
} else {
c.announce(MaplePacketCreator.showCashShopMessage((byte)0));
}
@@ -421,8 +455,8 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
} else if(chr.registerWorldTransfer(newWorldSelection)) {
Item item = cItem.toItem();
c.announce(MaplePacketCreator.showWorldTransferSuccess(item, c.getAccID()));
cs.addToInventory(item);
cs.gainCash(4, cItem, chr.getWorld());
cs.addToInventory(item);
} else {
c.announce(MaplePacketCreator.showCashShopMessage((byte)0));
}

View File

@@ -35,7 +35,6 @@ import client.inventory.Equip;
import client.inventory.MapleInventory;
import client.inventory.MapleInventoryType;
import client.inventory.ModifyInventory;
import constants.net.ServerConstants;
import server.MapleItemInformationProvider;
import net.server.Server;
@@ -73,7 +72,11 @@ class PairedQuicksort {
} while (i <= j);
}
private void PartitionByItemIdReverse(int Esq, int Dir, ArrayList<Item> A) {
private int getWatkForProjectile(Item item) {
return ii.getWatkForProjectile(item.getItemId());
}
private void PartitionByProjectileAtk(int Esq, int Dir, ArrayList<Item> A) {
Item x, w;
i = Esq;
@@ -81,8 +84,9 @@ class PairedQuicksort {
x = A.get((i + j) / 2);
do {
while (x.getItemId() < A.get(i).getItemId()) i++;
while (x.getItemId() > A.get(j).getItemId()) j--;
int watk = getWatkForProjectile(x);
while (watk < getWatkForProjectile(A.get(i))) i++;
while (watk > getWatkForProjectile(A.get(j))) j--;
if (i <= j) {
w = A.get(i);
@@ -228,7 +232,7 @@ class PairedQuicksort {
public void reverseSortSublist(ArrayList<Item> A, int[] range) {
if (range != null) {
PartitionByItemIdReverse(range[0], range[1], A);
PartitionByProjectileAtk(range[0], range[1], A);
}
}

View File

@@ -244,7 +244,7 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
eq.setExpiration(currentServerTime() + (period * 60 * 60 * 24 * 1000));
}
remove(c, position, itemId);
// double-remove found thanks to BHB
} else if (itemId == 5060002) { // Incubator
byte inventory2 = (byte) slea.readInt();
short slot2 = (short) slea.readInt();

View File

@@ -467,7 +467,13 @@ public class World {
}
}
public void registerAccountStorage(Integer accountId) {
public void loadAccountStorage(Integer accountId) {
if (getAccountStorage(accountId) == null) {
registerAccountStorage(accountId);
}
}
private void registerAccountStorage(Integer accountId) {
MapleStorage storage = MapleStorage.loadOrCreateFromDB(accountId, this.id);
accountCharsLock.lock();
try {
@@ -572,7 +578,7 @@ public class World {
if(cserv != null) {
if(!cserv.removePlayer(chr)) {
// oy the player is not where it should be, find this mf
// oy the player is not where they should be, find this mf
for(Channel ch : getChannels()) {
if(ch.removePlayer(chr)) {