Mystic Doors review + Togglable SrvMessage-BossHP + Map-Event patch

Reviewed Mystic Doors.
Fixed several issues showing up on Duey in uncommon scenarios.
Fixed a concurrency issue with XMLDomMapleData.
Scheduled forward the "lock disposal" action within the source. Now, it's expected that, after a set while, no method should require usage of a disposed lock and, during that while, a supposed "disposed lock" is still available to run (although no new processes is expected to require use of these locks).
Fixed concurrency issues with player's current event instance, generating several inconsistencies when swiftly registering/unregistering from events.
Implemented a mutually exclusive approach for server message - Boss HPbar.
Fixed item-making Kage requiring lv71~80 ETC instead of the expected 81~90.
Removed the possibility to buy cosmetic coupons with mesos through the NPCs.
Sleepywood JQ's no longer gives cash items when they finish the quest repeatedly.
Added Duey trucks in several maps lacking it. Added NPC Duey in New Leaf City.
Fixed scripted quests not calculating QUEST_RATE (if applied) when rewarding experience and meso.
This commit is contained in:
ronancpl
2018-08-07 23:37:24 -03:00
parent cc541f39d5
commit 4c25c07e28
173 changed files with 38064 additions and 37254 deletions
+216 -74
View File
@@ -261,7 +261,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
private Map<Integer, MapleSummon> summons = new LinkedHashMap<>();
private Map<Integer, MapleCoolDownValueHolder> coolDowns = new LinkedHashMap<>();
private EnumMap<MapleDisease, Pair<MapleDiseaseValueHolder, MobSkill>> diseases = new EnumMap<>(MapleDisease.class);
private Map<Integer, MapleDoor> doors = new LinkedHashMap<>();
private MapleDoor pdoor = null;
private Map<MapleQuest, Long> questExpirations = new LinkedHashMap<>();
private ScheduledFuture<?> dragonBloodSchedule;
private ScheduledFuture<?> hpDecreaseTask;
@@ -277,6 +277,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
private ScheduledFuture<?> pendantOfSpirit = null; //1122017
private Lock chrLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHARACTER_CHR, true);
private Lock effLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHARACTER_EFF, true);
private Lock evtLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHARACTER_EVT, true);
private Lock petLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHARACTER_PET, true); // for quest tasks as well
private Lock prtLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHARACTER_PRT);
private Map<Integer, Set<Integer>> excluded = new LinkedHashMap<>();
@@ -343,7 +344,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
quests = new LinkedHashMap<>();
setPosition(new Point(0, 0));
petLootCd = System.currentTimeMillis();
petLootCd = Server.getInstance().getCurrentTime();
}
private static MapleJob getJobStyleInternal(int jobid, byte opt) {
@@ -586,25 +587,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
return pts;
}
public void addDoor(Integer owner, MapleDoor door) {
chrLock.lock();
try {
doors.put(owner, door);
} finally {
chrLock.unlock();
}
}
public void removeDoor(Integer owner) {
chrLock.lock();
try {
doors.remove(owner);
} finally {
chrLock.unlock();
}
}
public void addFame(int famechange) {
this.fame += famechange;
}
@@ -889,13 +872,13 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
this.loggedIn = true;
c.setAccountName(this.client.getAccountName());//No null's for accountName
this.client = c;
this.map = c.getChannelServer().getMapFactory().getMap(getMapId());
MaplePortal portal = map.findClosestPlayerSpawnpoint(getPosition());
if (portal == null) {
portal = map.getPortal(0);
}
this.setPosition(portal.getPosition());
this.initialSpawnPoint = portal.getId();
this.map = c.getChannelServer().getMapFactory().getMap(getMapId());
}
public String getMedalText() {
@@ -1352,9 +1335,13 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
public void changeMap(MapleMap to) {
changeMap(to, to.getPortal(0));
changeMap(to, 0);
}
public void changeMap(MapleMap to, int portal) {
changeMap(to, to.getPortal(portal));
}
public void changeMap(final MapleMap target, final MaplePortal pto) {
canWarpCounter++;
@@ -1437,7 +1424,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
return lastVisited;
}
public void updateMapDropsUponPartyOperation(List<MapleCharacter> exPartyMembers) {
public void partyOperationUpdate(MapleParty party, List<MapleCharacter> exPartyMembers) {
List<WeakReference<MapleMap>> mapids;
petLock.lock();
@@ -1468,6 +1455,84 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
mapObj.updatePlayerItemDrops(partyId, id, partyMembers, partyLeaver);
}
}
updatePartyTownDoors(party, this, partyLeaver, partyMembers);
}
private static void addPartyPlayerDoor(MapleCharacter target) {
MapleDoor targetDoor = target.getPlayerDoor();
if(targetDoor != null) {
target.applyPartyDoor(targetDoor, true);
}
}
private static void removePartyPlayerDoor(MapleParty party, MapleCharacter target) {
target.removePartyDoor(party);
}
private static void updatePartyTownDoors(MapleParty party, MapleCharacter target, MapleCharacter partyLeaver, List<MapleCharacter> partyMembers) {
if(partyLeaver != null) {
removePartyPlayerDoor(party, target);
} else {
addPartyPlayerDoor(target);
}
Map<Integer, MapleDoor> partyDoors = null;
if(!partyMembers.isEmpty()) {
partyDoors = party.getDoors();
for(MapleCharacter pchr : partyMembers) {
MapleDoor door = partyDoors.get(pchr.getId());
if(door != null) {
door.updateDoorPortal(pchr);
}
}
for(MapleDoor door : partyDoors.values()) {
for(MapleCharacter pchar : partyMembers) {
door.getTownDoor().sendDestroyData(pchar.getClient(), true);
}
}
if(partyLeaver != null) {
Collection<MapleDoor> leaverDoors = partyLeaver.getDoors();
for(MapleDoor door : leaverDoors) {
for(MapleCharacter pchar : partyMembers) {
door.getTownDoor().sendDestroyData(pchar.getClient(), true);
}
}
}
List<Integer> histMembers = party.getMembersSortedByHistory();
for(Integer chrid : histMembers) {
MapleDoor door = partyDoors.get(chrid);
if(door != null) {
for(MapleCharacter pchar : partyMembers) {
door.getTownDoor().sendSpawnData(pchar.getClient());
}
}
}
}
if(partyLeaver != null) {
Collection<MapleDoor> leaverDoors = partyLeaver.getDoors();
if(partyDoors != null) {
for(MapleDoor door : partyDoors.values()) {
door.getTownDoor().sendDestroyData(partyLeaver.getClient(), true);
}
}
for(MapleDoor door : leaverDoors) {
door.getTownDoor().sendDestroyData(partyLeaver.getClient(), true);
}
for(MapleDoor door : leaverDoors) {
door.updateDoorPortal(partyLeaver);
door.getTownDoor().sendSpawnData(partyLeaver.getClient());
}
}
}
private Integer getVisitedMapIndex(MapleMap map) {
@@ -2238,10 +2303,12 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
public void dispel() {
List<MapleBuffStatValueHolder> mbsvhList = getAllStatups();
for (MapleBuffStatValueHolder mbsvh : mbsvhList) {
if (mbsvh.effect.isSkill()) {
cancelEffect(mbsvh.effect, false, mbsvh.startTime);
if(!(ServerConstants.USE_UNDISPEL_HOLY_SHIELD && this.isActiveBuffedValue(Bishop.HOLY_SHIELD))) {
List<MapleBuffStatValueHolder> mbsvhList = getAllStatups();
for (MapleBuffStatValueHolder mbsvh : mbsvhList) {
if (mbsvh.effect.isSkill()) {
cancelEffect(mbsvh.effect, false, mbsvh.startTime);
}
}
}
}
@@ -3376,14 +3443,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
if (effect.isMagicDoor()) {
MapleDoor destroyDoor;
chrLock.lock();
try {
destroyDoor = doors.remove(this.getId());
} finally {
chrLock.unlock();
}
MapleDoor destroyDoor = removePartyDoor(false);
if (destroyDoor != null) {
destroyDoor.getTarget().removeMapObject(destroyDoor.getAreaDoor());
@@ -3392,21 +3452,18 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
for (MapleCharacter chr : destroyDoor.getTarget().getCharacters()) {
destroyDoor.getAreaDoor().sendDestroyData(chr.getClient());
}
for (MapleCharacter chr : destroyDoor.getTown().getCharacters()) {
Collection<MapleCharacter> townChars = destroyDoor.getTown().getCharacters();
for (MapleCharacter chr : townChars) {
destroyDoor.getTownDoor().sendDestroyData(chr.getClient());
}
prtLock.lock();
try {
if (party != null) {
for (MaplePartyCharacter partyMembers : party.getMembers()) {
partyMembers.getPlayer().removeDoor(this.getId());
partyMembers.removeDoor(this.getId());
if(destroyDoor.getTownPortal().getId() == 0x80) {
for (MapleCharacter chr : townChars) {
MapleDoor door = chr.getMainTownDoor();
if(door != null) {
destroyDoor.getTownDoor().sendSpawnData(chr.getClient());
}
silentPartyUpdateInternal();
}
} finally {
prtLock.unlock();
}
}
} else if (effect.isMapChair()) {
@@ -3994,21 +4051,86 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
return dojoStage;
}
public Map<Integer, MapleDoor> getDoors() {
chrLock.lock();
public Collection<MapleDoor> getDoors() {
prtLock.lock();
try {
return Collections.unmodifiableMap(doors);
return (party != null ? Collections.unmodifiableCollection(party.getDoors().values()) : (pdoor != null ? Collections.singleton(pdoor) : new LinkedHashSet<MapleDoor>()));
} finally {
chrLock.unlock();
prtLock.unlock();
}
}
public MapleDoor getPlayerDoor() {
prtLock.lock();
try {
return pdoor;
} finally {
prtLock.unlock();
}
}
public MapleDoor getMainTownDoor() {
for (MapleDoor door : getDoors()) {
if (door.getTownPortal().getId() == 0x80) {
return door;
}
}
return null;
}
public void applyPartyDoor(MapleDoor door, boolean partyUpdate) {
prtLock.lock();
try {
if (!partyUpdate) {
pdoor = door;
}
if (party != null) {
party.addDoor(id, door);
silentPartyUpdateInternal();
}
} finally {
prtLock.unlock();
}
}
private MapleDoor removePartyDoor(boolean partyUpdate) {
MapleDoor ret = null;
prtLock.lock();
try {
if (party != null) {
party.removeDoor(id);
silentPartyUpdateInternal();
}
if (!partyUpdate) {
ret = pdoor;
pdoor = null;
}
} finally {
prtLock.unlock();
}
return ret;
}
private void removePartyDoor(MapleParty formerParty) { // player is no longer registered at this party
formerParty.removeDoor(id);
}
public int getEnergyBar() {
return energybar;
}
public EventInstanceManager getEventInstance() {
return eventInstance;
evtLock.lock();
try {
return eventInstance;
} finally {
evtLock.unlock();
}
}
public void resetExcluded(int petId) {
@@ -4499,23 +4621,14 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
public void resetPlayerAggro() {
if(client.getWorldServer().unregisterDisabledServerMessage(id)) {
client.announceServerMessage();
}
setTargetHpBarHash(0);
setTargetHpBarTime(0);
}
public int getDoorSlot() {
if(doorSlot == -1) {
prtLock.lock();
try {
doorSlot = (party == null) ? 0 : party.getPartyDoor(this.getId());
} finally {
prtLock.unlock();
}
}
return doorSlot;
}
public MapleMiniGame getMiniGame() {
return miniGame;
}
@@ -4750,7 +4863,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
merchant.saveItems(false);
} catch (SQLException ex) {
ex.printStackTrace();
System.out.println("Error while saving Hired Merchant items.");
FilePrinter.printError(FilePrinter.EXCEPTION_CAUGHT, "Error while saving " + name + "'s Hired Merchant items.");
}
}
}
@@ -5895,9 +6008,11 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
ret.jobRank = rs.getInt("jobRank");
ret.jobRankMove = rs.getInt("jobRankMove");
MapleInventory inv = ret.inventory[MapleInventoryType.EQUIPPED.ordinal()];
for (Item item : equipped) {
inv.addItemFromDB(item);
if(equipped != null) { // players can have no equipped items at all, ofc
MapleInventory inv = ret.inventory[MapleInventoryType.EQUIPPED.ordinal()];
for (Item item : equipped) {
inv.addItemFromDB(item);
}
}
} catch (SQLException sqle) {
sqle.printStackTrace();
@@ -6641,10 +6756,11 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
if (party != null) {
int channel = client.getChannel();
int mapId = getMapId();
World wserv = Server.getInstance().getWorld(world);
for (MaplePartyCharacter partychar : party.getMembers()) {
if (partychar.getMapId() == mapId && partychar.getChannel() == channel) {
MapleCharacter other = Server.getInstance().getWorld(world).getChannel(channel).getPlayerStorage().getCharacterByName(partychar.getName());
MapleCharacter other = wserv.getChannel(channel).getPlayerStorage().getCharacterById(partychar.getId());
if (other != null) {
client.announce(MaplePacketCreator.updatePartyMemberHP(other.getId(), other.getHp(), other.getMaxHpEquipped()));
}
@@ -7498,7 +7614,12 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
public void setEventInstance(EventInstanceManager eventInstance) {
this.eventInstance = eventInstance;
evtLock.lock();
try {
this.eventInstance = eventInstance;
} finally {
evtLock.unlock();
}
}
public void setExp(int amount) {
@@ -7806,7 +7927,22 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
e.printStackTrace();
}
}
public int getDoorSlot() {
if(doorSlot != -1) return doorSlot;
return fetchDoorSlot();
}
public int fetchDoorSlot() {
prtLock.lock();
try {
doorSlot = (party == null) ? 0 : party.getPartyDoor(this.getId());
return doorSlot;
} finally {
prtLock.unlock();
}
}
public void setParty(MapleParty p) {
prtLock.lock();
try {
@@ -8917,11 +9053,17 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
events = null;
party = null;
family = null;
client = null;
map = null;
Server.getInstance().getWorld(world).registerTimedMapObject(new Runnable() {
@Override
public void run() {
client = null; // clients still triggers handlers a few times after disconnecting
map = null;
}
}, 5 * 60 * 1000);
}
}
public void logOff() {
this.loggedIn = false;
}
+24 -4
View File
@@ -112,6 +112,7 @@ public class MapleClient {
private static final Lock loginLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT_LOGIN, true);
private int votePoints;
private int voteTime = -1;
private int visibleWorlds;
private long lastNpcClick;
private long sessionId;
@@ -1268,6 +1269,16 @@ public class MapleClient {
}
}
private void announceDisableServerMessage() {
if(!this.getWorldServer().registerDisabledServerMessage(player.getId())) {
announce(MaplePacketCreator.serverMessage(""));
}
}
public void announceServerMessage() {
announce(MaplePacketCreator.serverMessage(this.getChannelServer().getServerMessage()));
}
public synchronized void announceBossHpBar(MapleMonster mm, final int mobHash, final byte[] packet) {
long timeNow = System.currentTimeMillis();
int targetHash = player.getTargetHpBarHash();
@@ -1275,12 +1286,14 @@ public class MapleClient {
if(mobHash != targetHash) {
if(timeNow - player.getTargetHpBarTime() >= 5 * 1000) {
// is there a way to INTERRUPT this annoying thread running on the client that drops the boss bar after some time at every attack?
announceDisableServerMessage();
announce(packet);
player.setTargetHpBarHash(mobHash);
player.setTargetHpBarTime(timeNow);
}
} else {
announceDisableServerMessage();
announce(packet);
player.setTargetHpBarTime(timeNow);
@@ -1311,10 +1324,8 @@ public class MapleClient {
return;
}
String[] socket;
try {
socket = Server.getInstance().getIP(getWorld(), channel).split(":");
} catch (Exception e) {
String[] socket = Server.getInstance().getInetSocket(getWorld(), channel);
if(socket == null) {
announce(MaplePacketCreator.serverNotice(1, "Channel " + channel + " is currently disabled. Try another channel."));
announce(MaplePacketCreator.enableActions());
return;
@@ -1387,6 +1398,15 @@ public class MapleClient {
lastNpcClick = 0;
}
public int getVisibleWorlds(){
return visibleWorlds;
}
public void requestedServerlist(int worlds) {
visibleWorlds = worlds;
setClickedNPC();
}
public void closePlayerScriptInteractions() {
this.removeClickedNPC();
NPCScriptManager.getInstance().dispose(this);
+84 -47
View File
@@ -2755,7 +2755,7 @@ public class Commands {
}
public static boolean executeHeavenMsCommandLv6(Channel cserv, Server srv, MapleClient c, String[] sub) { //Admin
MapleCharacter player = c.getPlayer();
final MapleCharacter player = c.getPlayer();
MapleCharacter victim;
switch(sub[0]) {
@@ -2788,16 +2788,20 @@ public class Commands {
byte worldb = Byte.parseByte(sub[1]);
if (worldb <= (server.getWorldsSize() - 1)) {
try {
String[] socket = server.getIP(worldb, c.getChannel()).split(":");
c.getWorldServer().removePlayer(player);
player.getMap().removePlayer(player);//LOL FORGOT THIS ><
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
player.setWorld(worldb);
player.saveCharToDB();//To set the new world :O (true because else 2 player instances are created, one in both worlds)
c.announce(MaplePacketCreator.getChannelChange(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1])));
String[] socket = server.getInetSocket(worldb, c.getChannel());
if(socket != null) {
c.getWorldServer().removePlayer(player);
player.getMap().removePlayer(player);//LOL FORGOT THIS ><
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
player.setWorld(worldb);
player.saveCharToDB();//To set the new world :O (true because else 2 player instances are created, one in both worlds)
c.announce(MaplePacketCreator.getChannelChange(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1])));
} else {
player.message("Error when trying to change worlds, are you sure the world you are trying to warp to has the same amount of channels?");
}
} catch (UnknownHostException | NumberFormatException ex) {
ex.printStackTrace();
player.message("Error when trying to change worlds, are you sure the world you are trying to warp to has the same amount of channels?");
player.message("Unexpected error when changing worlds, are you sure the world you are trying to warp to has the same amount of channels?");
}
} else {
@@ -2863,37 +2867,51 @@ public class Commands {
break;
}
int worldid = Integer.parseInt(sub[1]);
final int worldid = Integer.parseInt(sub[1]);
int chid = Server.getInstance().addChannel(worldid);
if(chid >= 0) {
player.dropMessage(5, "NEW Channel " + chid + " successfully deployed on world " + worldid + ".");
} else {
if(chid == -3) {
player.dropMessage(5, "Invalid worldid detected. Channel creation aborted.");
} else if(chid == -2) {
player.dropMessage(5, "Reached channel limit on worldid " + worldid + ". Channel creation aborted.");
} else if(chid == -1) {
player.dropMessage(5, "Error detected when loading the 'world.ini' file. Channel creation aborted.");
} else {
player.dropMessage(5, "NEW Channel failed to be deployed. Check if the needed port is already in use or other limitations are taking place.");
new Thread(new Runnable() {
@Override
public void run() {
int chid = Server.getInstance().addChannel(worldid);
if(player.isLoggedinWorld()) {
if(chid >= 0) {
player.dropMessage(5, "NEW Channel " + chid + " successfully deployed on world " + worldid + ".");
} else {
if(chid == -3) {
player.dropMessage(5, "Invalid worldid detected. Channel creation aborted.");
} else if(chid == -2) {
player.dropMessage(5, "Reached channel limit on worldid " + worldid + ". Channel creation aborted.");
} else if(chid == -1) {
player.dropMessage(5, "Error detected when loading the 'world.ini' file. Channel creation aborted.");
} else {
player.dropMessage(5, "NEW Channel failed to be deployed. Check if the needed port is already in use or other limitations are taking place.");
}
}
}
}
}
}).start();
break;
case "addworld":
int wid = Server.getInstance().addWorld();
new Thread(new Runnable() {
@Override
public void run() {
int wid = Server.getInstance().addWorld();
if(wid >= 0) {
player.dropMessage(5, "NEW World " + wid + " successfully deployed.");
} else {
if(wid == -2) {
player.dropMessage(5, "Error detected when loading the 'world.ini' file. World creation aborted.");
} else {
player.dropMessage(5, "NEW World failed to be deployed. Check if needed ports are already in use or maximum world count has been reached.");
if(player.isLoggedinWorld()) {
if(wid >= 0) {
player.dropMessage(5, "NEW World " + wid + " successfully deployed.");
} else {
if(wid == -2) {
player.dropMessage(5, "Error detected when loading the 'world.ini' file. World creation aborted.");
} else {
player.dropMessage(5, "NEW World failed to be deployed. Check if needed ports are already in use or maximum world count has been reached.");
}
}
}
}
}
}).start();
break;
@@ -2903,31 +2921,50 @@ public class Commands {
break;
}
int worldId = Integer.parseInt(sub[1]);
if(Server.getInstance().removeChannel(worldId)) {
player.dropMessage(5, "Successfully removed a channel on World " + worldId + ". Current channel count: " + Server.getInstance().getWorld(worldId).getChannelsSize() + ".");
} else {
player.dropMessage(5, "Failed to remove last Channel on world " + worldId + ". Check if either that world exists or there are people currently playing there.");
}
final int worldId = Integer.parseInt(sub[1]);
new Thread(new Runnable() {
@Override
public void run() {
if(Server.getInstance().removeChannel(worldId)) {
if(player.isLoggedinWorld()) {
player.dropMessage(5, "Successfully removed a channel on World " + worldId + ". Current channel count: " + Server.getInstance().getWorld(worldId).getChannelsSize() + ".");
}
} else {
if(player.isLoggedinWorld()) {
player.dropMessage(5, "Failed to remove last Channel on world " + worldId + ". Check if either that world exists or there are people currently playing there.");
}
}
}
}).start();
break;
case "removeworld":
int rwid = Server.getInstance().getWorldsSize() - 1;
final int rwid = Server.getInstance().getWorldsSize() - 1;
if(rwid <= 0) {
player.dropMessage(5, "Unable to remove world 0.");
break;
}
if(Server.getInstance().removeWorld()) {
player.dropMessage(5, "Successfully removed a world. Current world count: " + Server.getInstance().getWorldsSize() + ".");
} else {
if(rwid < 0) {
player.dropMessage(5, "No registered worlds to remove.");
} else {
player.dropMessage(5, "Failed to remove world " + rwid + ". Check if there are people currently playing there.");
new Thread(new Runnable() {
@Override
public void run() {
if(Server.getInstance().removeWorld()) {
if(player.isLoggedinWorld()) {
player.dropMessage(5, "Successfully removed a world. Current world count: " + Server.getInstance().getWorldsSize() + ".");
}
} else {
if(player.isLoggedinWorld()) {
if(rwid < 0) {
player.dropMessage(5, "No registered worlds to remove.");
} else {
player.dropMessage(5, "Failed to remove world " + rwid + ". Check if there are people currently playing there.");
}
}
}
}
}
}).start();
break;
-1
View File
@@ -222,7 +222,6 @@ public class MaplePet extends Item {
}
owner.getMap().broadcastMessage(MaplePacketCreator.commandResponse(owner.getId(), slot, type, enjoyed));
if(owner.getMount() != null) owner.getMap().broadcastMessage(MaplePacketCreator.updateMount(owner.getId(), owner.getMount(), false));
saveToDb();
Item petz = owner.getInventory(MapleInventoryType.CASH).getItem(getPosition());
+48 -45
View File
@@ -355,63 +355,66 @@ public class DueyProcessor {
c.disconnect(true, false);
return;
}
int finalcost = mesos + fee;
boolean send = false;
if (c.getPlayer().getMeso() >= finalcost) {
int accid = getAccIdFromCNAME(recipient, true);
if (accid != -1) {
if (accid != c.getAccID()) {
send = true;
} else {
if (accid == c.getAccID()) {
c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_SAMEACC_ERROR.getCode()));
}
} else {
c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_NAME_DOES_NOT_EXIST.getCode()));
}
} else {
c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_NOT_ENOUGH_MESOS.getCode()));
}
MapleClient rClient = null;
int channel = c.getWorldServer().find(recipient);
if (channel > -1) {
Channel rcserv = c.getWorldServer().getChannel(channel);
rClient = rcserv.getPlayerStorage().getCharacterByName(recipient).getClient();
}
if (send) {
if (inventId > 0) {
MapleInventoryType inv = MapleInventoryType.getByType(inventId);
Item item = c.getPlayer().getInventory(inv).getItem(itemPos);
if (item != null && c.getPlayer().getItemQuantity(item.getItemId(), false) >= amount) {
c.getPlayer().gainMeso(-finalcost, false);
c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_SUCCESSFULLY_SENT.getCode()));
if (ItemConstants.isRechargeable(item.getItemId())) {
MapleInventoryManipulator.removeFromSlot(c, inv, itemPos, item.getQuantity(), true);
} else {
MapleInventoryManipulator.removeFromSlot(c, inv, itemPos, amount, true, false);
}
MapleKarmaManipulator.toggleKarmaFlagToUntradeable(item);
addItemToDB(item, amount, mesos - getFee(mesos), c.getPlayer().getName(), getAccIdFromCNAME(recipient, false));
} else {
if (item != null) {
c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_INCORRECT_REQUEST.getCode()));
}
return;
}
} else {
c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_NAME_DOES_NOT_EXIST.getCode()));
return;
}
} else {
c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_NOT_ENOUGH_MESOS.getCode()));
return;
}
MapleClient rClient = null;
int channel = c.getWorldServer().find(recipient);
if (channel > -1) {
Channel rcserv = c.getWorldServer().getChannel(channel);
if(rcserv != null) {
MapleCharacter rChr = rcserv.getPlayerStorage().getCharacterByName(recipient);
if(rChr != null) {
rClient = rChr.getClient();
}
}
}
if (inventId > 0) {
MapleInventoryType inv = MapleInventoryType.getByType(inventId);
Item item = c.getPlayer().getInventory(inv).getItem(itemPos);
if (item != null && c.getPlayer().getItemQuantity(item.getItemId(), false) >= amount) {
c.getPlayer().gainMeso(-finalcost, false);
c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_SUCCESSFULLY_SENT.getCode()));
c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_SUCCESSFULLY_SENT.getCode()));
addMesoToDB(mesos - getFee(mesos), c.getPlayer().getName(), getAccIdFromCNAME(recipient, false));
}
if (ItemConstants.isRechargeable(item.getItemId())) {
MapleInventoryManipulator.removeFromSlot(c, inv, itemPos, item.getQuantity(), true);
} else {
MapleInventoryManipulator.removeFromSlot(c, inv, itemPos, amount, true, false);
}
if (rClient != null && rClient.isLoggedIn() && !rClient.getPlayer().isAwayFromWorld()) {
showDueyNotification(rClient, rClient.getPlayer());
MapleKarmaManipulator.toggleKarmaFlagToUntradeable(item);
addItemToDB(item, amount, mesos - getFee(mesos), c.getPlayer().getName(), getAccIdFromCNAME(recipient, false));
} else {
if (item != null) {
c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_INCORRECT_REQUEST.getCode()));
}
return;
}
} else {
c.getPlayer().gainMeso(-finalcost, false);
c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_SUCCESSFULLY_SENT.getCode()));
addMesoToDB(mesos - getFee(mesos), c.getPlayer().getName(), getAccIdFromCNAME(recipient, false));
}
if (rClient != null && rClient.isLoggedIn() && !rClient.getPlayer().isAwayFromWorld()) {
showDueyNotification(rClient, rClient.getPlayer());
}
} finally {
c.unlockClient();
+2 -1
View File
@@ -72,6 +72,7 @@ public class ServerConstants {
public static final boolean USE_ENFORCE_UNMERCHABLE_CASH = true;//Forces players to not sell CASH items via merchants.
public static final boolean USE_ENFORCE_UNMERCHABLE_PET = true; //Forces players to not sell pets via merchants. (since non-named pets gets dirty name and other possible DB-related issues)
public static final boolean USE_ENFORCE_MDOOR_POSITION = false; //Forces mystic door to be spawned near spawnpoints.
public static final boolean 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).
public static final boolean USE_ERASE_PERMIT_ON_OPENSHOP = true;//Forces "shop permit" item to be consumed when player deploy his/her player shop.
public static final boolean USE_ERASE_UNTRADEABLE_DROP = true; //Forces flagged untradeable items to disappear when dropped.
public static final boolean USE_ERASE_PET_ON_EXPIRATION = false;//Forces pets to be removed from inventory when expire time comes, rather than converting it to a doll.
@@ -81,7 +82,6 @@ public class ServerConstants {
public static final boolean USE_OLD_GMS_STYLED_PQ_NPCS = true; //Enables PQ NPCs with similar behaviour to old GMS style, that skips info about the PQs and immediately tries to register the party in.
public static final boolean USE_ENABLE_SOLO_EXPEDITIONS = true; //Enables start expeditions with any number of players. This will also bypass all the Zakum prequest.
public static final boolean USE_ENABLE_FULL_RESPAWN = true; //At respawn task, always respawn missing mobs when they're available. Spawn count doesn't depend on how many players are currently there.
public static final boolean 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).
//Announcement Configuration
public static final boolean USE_ANNOUNCE_SHOPITEMSOLD = false; //Automatic message sent to owner when an item from the Player Shop or Hired Merchant is sold.
@@ -154,6 +154,7 @@ public class ServerConstants {
//Other Skills Configuration
public static final boolean USE_FAST_REUSE_HERO_WILL = true;//Greatly reduce cooldown on Hero's Will.
public static final boolean USE_ANTI_IMMUNITY_CRASH = true; //Crash skills additionally removes the mob's invincibility buffs.
public static final boolean USE_UNDISPEL_HOLY_SHIELD = true;//Holy shield buff also prevents players from suffering dispel from mobs.
//Character Configuration
public static final boolean USE_ADD_SLOTS_BY_LEVEL = true; //Slots are added each 20 levels.
+39 -10
View File
@@ -60,6 +60,7 @@ import net.server.guild.MapleGuildCharacter;
import net.server.worker.CharacterDiseaseWorker;
import net.server.worker.CouponWorker;
import net.server.worker.RankingWorker;
import net.server.worker.ReleaseLockWorker;
import net.server.world.World;
import org.apache.mina.core.buffer.IoBuffer;
@@ -206,7 +207,11 @@ public class Server {
public World getWorld(int id) {
wldRLock.lock();
try {
return worlds.get(id);
try {
return worlds.get(id);
} catch (IndexOutOfBoundsException e) {
return null;
}
} finally {
wldRLock.unlock();
}
@@ -231,21 +236,33 @@ public class Server {
}
public Channel getChannel(int world, int channel) {
return this.getWorld(world).getChannel(channel);
try {
return this.getWorld(world).getChannel(channel);
} catch(NullPointerException npe) {
return null;
}
}
public List<Channel> getChannelsFromWorld(int world) {
return this.getWorld(world).getChannels();
try {
return this.getWorld(world).getChannels();
} catch(NullPointerException npe) {
return new ArrayList<>(0);
}
}
public List<Channel> getAllChannels() {
List<Channel> channelz = new ArrayList<>();
for (World world : this.getWorlds()) {
for (Channel ch : world.getChannels()) {
channelz.add(ch);
try {
List<Channel> channelz = new ArrayList<>();
for (World world : this.getWorlds()) {
for (Channel ch : world.getChannels()) {
channelz.add(ch);
}
}
return channelz;
} catch(NullPointerException npe) {
return new ArrayList<>(0);
}
return channelz;
}
public Set<Integer> getOpenChannels(int world) {
@@ -257,7 +274,7 @@ public class Server {
}
}
public String getIP(int world, int channel) {
private String getIP(int world, int channel) {
wldRLock.lock();
try {
return channels.get(world).get(channel);
@@ -266,6 +283,15 @@ public class Server {
}
}
public String[] getInetSocket(int world, int channel) {
try {
return getIP(world, channel).split(":");
} catch (Exception e) {
return null;
}
}
private void dumpData() {
wldWLock.lock();
try {
@@ -643,6 +669,7 @@ public class Server {
long timeLeft = getTimeLeftForNextHour();
tMan.register(new CharacterDiseaseWorker(), ServerConstants.UPDATE_INTERVAL, ServerConstants.UPDATE_INTERVAL);
tMan.register(new ReleaseLockWorker(), 2 * 60 * 1000, 2 * 60 * 1000);
tMan.register(new CouponWorker(), ServerConstants.COUPON_INTERVAL, timeLeft);
tMan.register(new RankingWorker(), ServerConstants.RANKING_INTERVAL, timeLeft);
@@ -1149,8 +1176,10 @@ public class Server {
}
*/
public Pair<Pair<Integer, List<MapleCharacter>>, List<Pair<Integer, List<MapleCharacter>>>> loadAccountCharlist(Integer accountId) {
public Pair<Pair<Integer, List<MapleCharacter>>, List<Pair<Integer, List<MapleCharacter>>>> loadAccountCharlist(Integer accountId, int visibleWorlds) {
List<World> wlist = this.getWorlds();
if(wlist.size() > visibleWorlds) wlist = wlist.subList(0, visibleWorlds);
List<Pair<Integer, List<MapleCharacter>>> accChars = new ArrayList<>(wlist.size() + 1);
int chrTotal = 0;
List<MapleCharacter> lastwchars = null;
+75
View File
@@ -0,0 +1,75 @@
/*
This file is part of the HeavenMS MapleStory Server
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 net.server.audit;
import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
*
* @author Ronan
*/
public class LockCollector {
private static final LockCollector instance = new LockCollector();
private Map<Runnable, Integer> disposableLocks = new HashMap<>(200);
private final Lock lock = new ReentrantLock(true);
public static LockCollector getInstance() {
return instance;
}
public void registerDisposeAction(Runnable r) {
lock.lock();
try {
disposableLocks.put(r, 0);
} finally {
lock.unlock();
}
}
public void runLockCollector() {
List<Runnable> toDispose = new ArrayList<>();
lock.lock();
try {
for(Entry<Runnable, Integer> e : disposableLocks.entrySet()) {
Integer eVal = e.getValue();
if(eVal > 5) { // updates each 2min
toDispose.add(e.getKey());
} else {
disposableLocks.put(e.getKey(), ++eVal);
}
}
} finally {
lock.unlock();
}
for(Runnable r : toDispose) {
r.run();
}
}
}
+5 -5
View File
@@ -57,7 +57,7 @@ public class ThreadTracker {
private final Map<Long, AtomicInteger> lockCount = new HashMap<>();
private final Map<Long, MonitoredLockType> lockIds = new HashMap<>();
private final Map<Long, Long> lockThreads = new HashMap<>();
private final Map<Long, Byte> lockUpdate = new HashMap<>();
private final Map<Long, Integer> lockUpdate = new HashMap<>();
private final Map<MonitoredLockType, Map<Long, Integer>> locks = new HashMap<>();
ScheduledFuture<?> threadTrackerSchedule;
@@ -169,8 +169,8 @@ public class ThreadTracker {
toRemove.clear();
for(Entry<Long, Byte> it : lockUpdate.entrySet()) {
byte val = (byte)(it.getValue() + 1);
for(Entry<Long, Integer> it : lockUpdate.entrySet()) {
int val = it.getValue() + 1;
if(val < 60) {
lockUpdate.put(it.getKey(), val);
@@ -202,7 +202,7 @@ public class ThreadTracker {
lockCount.put(lockOid, c);
lockIds.put(lockOid, lockId);
lockThreads.put(lockOid, tid);
lockUpdate.put(lockOid, (byte) 0);
lockUpdate.put(lockOid, 0);
}
c.incrementAndGet();
@@ -233,7 +233,7 @@ public class ThreadTracker {
else {
AtomicInteger c = lockCount.get(lockOid);
c.decrementAndGet();
lockUpdate.put(lockOid, (byte) 0);
lockUpdate.put(lockOid, 0);
List<MonitoredLockType> list = threadTracker.get(tid);
for(int i = list.size() - 1; i >= 0; i--) {
@@ -30,6 +30,7 @@ public enum MonitoredLockType {
CHARACTER_EFF,
CHARACTER_PET,
CHARACTER_PRT,
CHARACTER_EVT,
CLIENT,
CLIENT_ENCODER,
CLIENT_LOGIN,
@@ -40,6 +41,7 @@ public enum MonitoredLockType {
SRVHANDLER_TEMP,
BUFF_STORAGE,
PLAYER_STORAGE,
PLAYER_DOOR,
SERVER,
SERVER_DISEASES,
SERVER_LOGIN,
@@ -59,7 +61,7 @@ public enum MonitoredLockType {
GUILD,
PARTY,
WORLD_PARTY,
WORLD_OWL,
WORLD_SRVMESSAGES,
WORLD_PETS,
WORLD_CHARS,
WORLD_CHANNELS,
@@ -159,11 +159,13 @@ public class TrackerReadLock extends ReentrantReadWriteLock.ReadLock implements
timeoutSchedule.cancel(false);
timeoutSchedule = null;
}
reentrantCount.set(Integer.MAX_VALUE);
} finally {
state.unlock();
}
//unlock();
return new EmptyReadLock();
return new EmptyReadLock(id);
}
}
@@ -46,7 +46,7 @@ public class TrackerReentrantLock extends ReentrantLock implements MonitoredReen
private final int hashcode;
private final Lock state = new ReentrantLock(true);
private final AtomicInteger reentrantCount = new AtomicInteger(0);
public TrackerReentrantLock(MonitoredLockType id) {
super();
this.id = id;
@@ -161,11 +161,13 @@ public class TrackerReentrantLock extends ReentrantLock implements MonitoredReen
timeoutSchedule.cancel(false);
timeoutSchedule = null;
}
reentrantCount.set(Integer.MAX_VALUE);
} finally {
state.unlock();
}
//unlock();
return new EmptyReentrantLock();
return new EmptyReentrantLock(id);
}
}
@@ -157,11 +157,13 @@ public class TrackerWriteLock extends ReentrantReadWriteLock.WriteLock implement
timeoutSchedule.cancel(false);
timeoutSchedule = null;
}
reentrantCount.set(Integer.MAX_VALUE);
} finally {
state.unlock();
}
//unlock();
return new EmptyWriteLock();
return new EmptyWriteLock(id);
}
}
@@ -19,26 +19,56 @@
*/
package net.server.audit.locks.empty;
import constants.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;
/**
*
* @author RonanLana
*/
public class EmptyReadLock 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.getTimeZone(ServerConstants.TIMEZONE));
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 += "----------------------------";
return s;
}
@Override
public void lock() {}
public void lock() {
FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace()));
}
@Override
public void unlock() {}
@Override
public boolean tryLock() {
FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured try-locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace()));
return false;
}
@Override
public MonitoredReadLock dispose() {
return null;
return this;
}
}
@@ -19,26 +19,56 @@
*/
package net.server.audit.locks.empty;
import constants.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;
/**
*
* @author RonanLana
*/
public class EmptyReentrantLock 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.getTimeZone(ServerConstants.TIMEZONE));
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 += "----------------------------";
return s;
}
@Override
public void lock() {}
public void lock() {
FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace()));
}
@Override
public void unlock() {}
@Override
public boolean tryLock() {
FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured try-locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace()));
return false;
}
@Override
public MonitoredReentrantLock dispose() {
return null;
return this;
}
}
@@ -19,26 +19,56 @@
*/
package net.server.audit.locks.empty;
import constants.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;
/**
*
* @author RonanLana
*/
public class EmptyWriteLock 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.getTimeZone(ServerConstants.TIMEZONE));
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 += "----------------------------";
return s;
}
@Override
public void lock() {}
public void lock() {
FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace()));
}
@Override
public void unlock() {}
@Override
public boolean tryLock() {
FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured try-locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace()));
return false;
}
@Override
public MonitoredWriteLock dispose() {
return null;
return this;
}
}
+23 -2
View File
@@ -37,6 +37,7 @@ import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
import net.server.audit.LockCollector;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.MonitoredReentrantLock;
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
@@ -266,7 +267,22 @@ public final class Channel {
channelSchedulers[i].dispose();
channelSchedulers[i] = null;
}
}
disposeLocks();
}
private void disposeLocks() {
LockCollector.getInstance().registerDisposeAction(new Runnable() {
@Override
public void run() {
emptyLocks();
}
});
}
private void emptyLocks() {
for(int i = 0; i < 4; i++) {
faceLock[i] = faceLock[i].dispose();
}
@@ -300,6 +316,10 @@ public final class Channel {
players.addPlayer(chr);
chr.announce(MaplePacketCreator.serverMessage(serverMessage));
}
public String getServerMessage() {
return serverMessage;
}
public PlayerStorage getPlayerStorage() {
return players;
@@ -443,6 +463,7 @@ public final class Channel {
public void setServerMessage(String message) {
this.serverMessage = message;
broadcastPacket(MaplePacketCreator.serverMessage(message));
Server.getInstance().getWorld(world).resetDisabledServerMessages();
}
private static String [] getEvents(){
@@ -540,7 +561,7 @@ public final class Channel {
resetDojo(dojoMapId, 0);
}
private void resetDojo(int dojoMapId, int thisStg) {
public void resetDojo(int dojoMapId, int thisStg) {
int slot = getDojoSlot(dojoMapId);
this.dojoStage[slot] = thisStg;
@@ -21,13 +21,11 @@
*/
package net.server.channel.handlers;
import java.util.Calendar;
import client.MapleCharacter;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
import server.maps.MapleDoorObject;
import server.maps.MapleMapObject;
import tools.FilePrinter;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
@@ -43,10 +41,6 @@ public final class DoorHandler extends AbstractMaplePacketHandler {
MapleCharacter chr = c.getPlayer();
if (chr.isChangingMaps() || chr.isBanned()) {
if(chr.isChangingMaps()) {
FilePrinter.printError(FilePrinter.PORTAL_STUCK + chr.getName() + ".txt", "Player " + chr.getName() + " got stuck when changing maps (using Mystic Door). Timestamp: " + Calendar.getInstance().getTime().toString() + " Last visited mapids: " + chr.getLastVisitedMapids());
}
c.announce(MaplePacketCreator.enableActions());
return;
}
@@ -45,7 +45,13 @@ public class EnterCashShopHandler extends AbstractMaplePacketHandler {
}
if(MapleMiniDungeonInfo.isDungeonMap(c.getPlayer().getMapId())) {
if(mc.getEventInstance() != null) {
c.announce(MaplePacketCreator.serverNotice(5, "Entering Cash Shop or MTS are disabled when registered on an event."));
c.announce(MaplePacketCreator.enableActions());
return;
}
if(MapleMiniDungeonInfo.isDungeonMap(mc.getMapId())) {
c.announce(MaplePacketCreator.serverNotice(5, "Changing channels or entering Cash Shop or MTS are disabled when inside a Mini-Dungeon."));
c.announce(MaplePacketCreator.enableActions());
return;
@@ -58,7 +58,13 @@ public final class EnterMTSHandler extends AbstractMaplePacketHandler {
return;
}
if(MapleMiniDungeonInfo.isDungeonMap(c.getPlayer().getMapId())) {
if(chr.getEventInstance() != null) {
c.announce(MaplePacketCreator.serverNotice(5, "Entering Cash Shop or MTS are disabled when registered on an event."));
c.announce(MaplePacketCreator.enableActions());
return;
}
if(MapleMiniDungeonInfo.isDungeonMap(chr.getMapId())) {
c.announce(MaplePacketCreator.serverNotice(5, "Changing channels or entering Cash Shop or MTS are disabled when inside a Mini-Dungeon."));
c.announce(MaplePacketCreator.enableActions());
return;
@@ -82,9 +82,9 @@ public final class PartyOperationHandler extends AbstractMaplePacketHandler {
player.setMPC(partyplayer);
player.getMap().addPartyMember(player);
player.silentPartyUpdate();
c.announce(MaplePacketCreator.partyCreated(partyplayer, party.getId()));
player.updateMapDropsUponPartyOperation(null);
player.partyOperationUpdate(party, null);
c.announce(MaplePacketCreator.partyCreated(party, partyplayer.getId()));
} else {
c.announce(MaplePacketCreator.serverNotice(5, "You can't create a party as you are already in one."));
}
@@ -94,7 +94,7 @@ public final class PartyOperationHandler extends AbstractMaplePacketHandler {
List<MapleCharacter> partymembers = player.getPartyMembers();
leaveParty(party, partyplayer, c);
player.updateMapDropsUponPartyOperation(partymembers);
player.partyOperationUpdate(party, partymembers);
break;
}
case 3: { // join
@@ -110,7 +110,7 @@ public final class PartyOperationHandler extends AbstractMaplePacketHandler {
player.receivePartyMemberHP();
player.updatePartyMemberHP();
player.updateMapDropsUponPartyOperation(null);
player.partyOperationUpdate(party, null);
} else {
c.announce(MaplePacketCreator.partyStatusMessage(17));
}
@@ -147,9 +147,9 @@ public final class PartyOperationHandler extends AbstractMaplePacketHandler {
player.setParty(party);
player.setMPC(partyplayer);
player.getMap().addPartyMember(player);
c.announce(MaplePacketCreator.partyCreated(partyplayer, party.getId()));
player.updateMapDropsUponPartyOperation(null);
player.partyOperationUpdate(party, null);
c.announce(MaplePacketCreator.partyCreated(party, partyplayer.getId()));
}
if (party.getMembers().size() < 6) {
invited.getClient().announce(MaplePacketCreator.partyInvite(player));
@@ -184,7 +184,7 @@ public final class PartyOperationHandler extends AbstractMaplePacketHandler {
emc.setParty(null);
world.updateParty(party.getId(), PartyOperation.EXPEL, expelled);
emc.updateMapDropsUponPartyOperation(partyMembers);
emc.partyOperationUpdate(party, partyMembers);
} else {
world.updateParty(party.getId(), PartyOperation.EXPEL, expelled);
}
@@ -54,10 +54,8 @@ public final class PetCommandHandler extends AbstractMaplePacketHandler {
if (Randomizer.nextInt(101) <= petCommand.getProbability()) {
pet.gainClosenessFullness(chr, petCommand.getIncrease(), 0, command);
}
else {
} else {
chr.getMap().broadcastMessage(MaplePacketCreator.commandResponse(chr.getId(), petIndex, command, false));
if(chr.getMount() != null) chr.getMap().broadcastMessage(MaplePacketCreator.updateMount(chr.getId(), chr.getMount(), false));
}
}
}
@@ -103,12 +103,18 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
int state = c.getLoginState();
boolean allowLogin = true;
Channel cserv = c.getChannelServer();
World world = server.getWorld(c.getWorld());
if(world == null) {
c.disconnect(true, false);
return;
}
Channel cserv = world.getChannel(c.getChannel());
if(cserv == null) {
c.setChannel(1);
cserv = c.getChannelServer();
cserv = world.getChannel(c.getChannel());
if(cserv == null) { // world server is out
if(cserv == null) {
c.disconnect(true, false);
return;
}
@@ -136,8 +142,6 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
return;
}
c.updateLoginState(MapleClient.LOGIN_LOGGEDIN);
World world = server.getWorld(c.getWorld());
cserv.addPlayer(player);
world.addPlayer(player);
@@ -29,6 +29,7 @@ import java.util.Map.Entry;
import java.util.concurrent.ScheduledFuture;
import net.server.Server;
import net.server.audit.LockCollector;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.MonitoredReentrantLock;
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
@@ -196,6 +197,19 @@ public abstract class BaseScheduler {
externalLocks.clear();
}
disposeLocks();
}
private void disposeLocks() {
LockCollector.getInstance().registerDisposeAction(new Runnable() {
@Override
public void run() {
emptyLocks();
}
});
}
private void emptyLocks() {
schedulerLock = schedulerLock.dispose();
}
}
@@ -24,6 +24,7 @@ import net.server.audit.locks.MonitoredLockType;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import net.server.audit.LockCollector;
import net.server.audit.locks.MonitoredReentrantLock;
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
@@ -76,7 +77,20 @@ public class MobAnimationScheduler extends BaseScheduler {
@Override
public void dispose() {
animationLock = animationLock.dispose();
disposeLocks();
super.dispose();
}
private void disposeLocks() {
LockCollector.getInstance().registerDisposeAction(new Runnable() {
@Override
public void run() {
emptyLocks();
}
});
}
private void emptyLocks() {
animationLock = animationLock.dispose();
}
}
@@ -25,6 +25,7 @@ import java.util.HashMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import net.server.audit.LockCollector;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.MonitoredReentrantLock;
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
@@ -111,7 +112,20 @@ public class MobStatusScheduler extends BaseScheduler {
@Override
public void dispose() {
overtimeStatusLock = overtimeStatusLock.dispose();
disposeLocks();
super.dispose();
}
private void disposeLocks() {
LockCollector.getInstance().registerDisposeAction(new Runnable() {
@Override
public void run() {
emptyLocks();
}
});
}
private void emptyLocks() {
overtimeStatusLock = overtimeStatusLock.dispose();
}
}
@@ -27,6 +27,7 @@ import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import net.AbstractMaplePacketHandler;
import net.server.Server;
import net.server.world.World;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
@@ -52,7 +53,14 @@ public final class CharSelectedHandler extends AbstractMaplePacketHandler {
}
c.setWorld(server.getCharacterWorld(charId));
if(c.getWorldServer().isWorldCapacityFull()) {
World wserv = c.getWorldServer();
if(wserv == null || wserv.isWorldCapacityFull()) {
c.announce(MaplePacketCreator.getAfterLoginError(10));
return;
}
String[] socket = server.getInetSocket(c.getWorld(), c.getChannel());
if(socket == null) {
c.announce(MaplePacketCreator.getAfterLoginError(10));
return;
}
@@ -61,7 +69,6 @@ public final class CharSelectedHandler extends AbstractMaplePacketHandler {
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
server.setCharacteridInTransition((InetSocketAddress) c.getSession().getRemoteAddress(), charId);
String[] socket = server.getIP(c.getWorld(), c.getChannel()).split(":");
try {
c.announce(MaplePacketCreator.getServerIP(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]), charId));
} catch (UnknownHostException | NumberFormatException e) {
@@ -6,6 +6,7 @@ import java.net.UnknownHostException;
import net.AbstractMaplePacketHandler;
import net.server.Server;
import net.server.world.World;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
import client.MapleClient;
@@ -34,7 +35,14 @@ public class CharSelectedWithPicHandler extends AbstractMaplePacketHandler {
if (c.checkPic(pic)) {
c.setWorld(server.getCharacterWorld(charId));
if(c.getWorldServer().isWorldCapacityFull()) {
World wserv = c.getWorldServer();
if(wserv == null || wserv.isWorldCapacityFull()) {
c.announce(MaplePacketCreator.getAfterLoginError(10));
return;
}
String[] socket = server.getInetSocket(c.getWorld(), c.getChannel());
if(socket == null) {
c.announce(MaplePacketCreator.getAfterLoginError(10));
return;
}
@@ -42,8 +50,7 @@ public class CharSelectedWithPicHandler extends AbstractMaplePacketHandler {
server.unregisterLoginState(c);
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
server.setCharacteridInTransition((InetSocketAddress) c.getSession().getRemoteAddress(), charId);
String[] socket = server.getIP(c.getWorld(), c.getChannel()).split(":");
try {
c.announce(MaplePacketCreator.getServerIP(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]), charId));
} catch (UnknownHostException | NumberFormatException e) {
@@ -24,6 +24,7 @@ package net.server.handlers.login;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
import net.server.Server;
import net.server.world.World;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
@@ -33,14 +34,21 @@ public final class CharlistRequestHandler extends AbstractMaplePacketHandler {
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
slea.readByte();
int world = slea.readByte();
c.setWorld(world);
if(Server.getInstance().getWorld(world).isWorldCapacityFull()) {
World wserv = Server.getInstance().getWorld(world);
if(wserv == null || wserv.isWorldCapacityFull()) {
c.announce(MaplePacketCreator.getServerStatus(2));
return;
}
c.setChannel(slea.readByte() + 1);
int channel = slea.readByte() + 1;
if(wserv.getChannel(channel) == null) {
c.announce(MaplePacketCreator.getServerStatus(2));
return;
}
c.setWorld(world);
c.setChannel(channel);
c.sendCharList(world);
}
}
@@ -5,6 +5,7 @@ import java.net.UnknownHostException;
import net.AbstractMaplePacketHandler;
import net.server.Server;
import net.server.world.World;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
import client.MapleClient;
@@ -37,7 +38,14 @@ public final class RegisterPicHandler extends AbstractMaplePacketHandler {
c.setPic(pic);
c.setWorld(server.getCharacterWorld(charId));
if(c.getWorldServer().isWorldCapacityFull()) {
World wserv = c.getWorldServer();
if(wserv == null || wserv.isWorldCapacityFull()) {
c.announce(MaplePacketCreator.getAfterLoginError(10));
return;
}
String[] socket = server.getInetSocket(c.getWorld(), c.getChannel());
if(socket == null) {
c.announce(MaplePacketCreator.getAfterLoginError(10));
return;
}
@@ -46,7 +54,6 @@ public final class RegisterPicHandler extends AbstractMaplePacketHandler {
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
server.setCharacteridInTransition((InetSocketAddress) c.getSession().getRemoteAddress(), charId);
String[] socket = server.getIP(c.getWorld(), c.getChannel()).split(":");
try {
c.announce(MaplePacketCreator.getServerIP(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]), charId));
} catch (UnknownHostException e) {
@@ -23,6 +23,7 @@ package net.server.handlers.login;
import client.MapleClient;
import constants.GameConstants;
import java.util.List;
import net.AbstractMaplePacketHandler;
import net.server.Server;
import net.server.world.World;
@@ -34,10 +35,10 @@ public final class ServerlistRequestHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
Server server = Server.getInstance();
server.loadAccountCharacters(c); // locks the login session until data is recovered from the cache or the DB.
c.setClickedNPC();
List<World> worlds = server.getWorlds();
c.requestedServerlist(worlds.size());
for (World world : server.getWorlds()) {
for (World world : worlds) {
c.announce(MaplePacketCreator.getServerList(world.getId(), GameConstants.WORLD_NAMES[world.getId()], world.getFlag(), world.getEventMessage(), world.getChannels()));
}
c.announce(MaplePacketCreator.getEndOfServerList());
@@ -41,7 +41,7 @@ public final class ViewAllCharHandler extends AbstractMaplePacketHandler {
}
int accountId = c.getAccID();
Pair<Pair<Integer, List<MapleCharacter>>, List<Pair<Integer, List<MapleCharacter>>>> loginBlob = Server.getInstance().loadAccountCharlist(accountId);
Pair<Pair<Integer, List<MapleCharacter>>, List<Pair<Integer, List<MapleCharacter>>>> loginBlob = Server.getInstance().loadAccountCharlist(accountId, c.getVisibleWorlds());
List<Pair<Integer, List<MapleCharacter>>> worldChars = loginBlob.getRight();
int chrTotal = loginBlob.getLeft().getLeft();
@@ -6,12 +6,12 @@ import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import net.AbstractMaplePacketHandler;
import net.server.Server;
import net.server.world.World;
import tools.MaplePacketCreator;
import tools.Randomizer;
import tools.data.input.SeekableLittleEndianAccessor;
public final class ViewAllCharRegisterPicHandler extends AbstractMaplePacketHandler { //Gey class name lol
public final class ViewAllCharRegisterPicHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
@@ -26,7 +26,8 @@ public final class ViewAllCharRegisterPicHandler extends AbstractMaplePacketHand
}
c.setWorld(server.getCharacterWorld(charId));
if(c.getWorldServer().isWorldCapacityFull()) {
World wserv = c.getWorldServer();
if(wserv == null || wserv.isWorldCapacityFull()) {
c.announce(MaplePacketCreator.getAfterLoginError(10));
return;
}
@@ -45,11 +46,16 @@ public final class ViewAllCharRegisterPicHandler extends AbstractMaplePacketHand
String pic = slea.readMapleAsciiString();
c.setPic(pic);
String[] socket = server.getInetSocket(c.getWorld(), channel);
if (socket == null) {
c.announce(MaplePacketCreator.getAfterLoginError(10));
return;
}
server.unregisterLoginState(c);
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
server.setCharacteridInTransition((InetSocketAddress) c.getSession().getRemoteAddress(), charId);
String[] socket = server.getIP(c.getWorld(), channel).split(":");
try {
c.announce(MaplePacketCreator.getServerIP(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]), charId));
} catch (UnknownHostException e) {
@@ -27,6 +27,7 @@ import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import net.AbstractMaplePacketHandler;
import net.server.Server;
import net.server.world.World;
import tools.MaplePacketCreator;
import tools.Randomizer;
import tools.data.input.SeekableLittleEndianAccessor;
@@ -45,7 +46,9 @@ public final class ViewAllCharSelectedHandler extends AbstractMaplePacketHandler
}
c.setWorld(server.getCharacterWorld(charId));
if(c.getWorldServer().isWorldCapacityFull()) {
World wserv = c.getWorldServer();
if(wserv == null || wserv.isWorldCapacityFull()) {
c.announce(MaplePacketCreator.getAfterLoginError(10));
return;
}
@@ -58,18 +61,23 @@ public final class ViewAllCharSelectedHandler extends AbstractMaplePacketHandler
}
try {
int channel = Randomizer.rand(1, c.getWorldServer().getChannelsSize());
int channel = Randomizer.rand(1, wserv.getChannelsSize());
c.setChannel(channel);
} catch (Exception e) {
e.printStackTrace();
c.setChannel(1);
}
String[] socket = server.getInetSocket(c.getWorld(), c.getChannel());
if(socket == null) {
c.announce(MaplePacketCreator.getAfterLoginError(10));
return;
}
server.unregisterLoginState(c);
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
server.setCharacteridInTransition((InetSocketAddress) c.getSession().getRemoteAddress(), charId);
String[] socket = server.getIP(c.getWorld(), c.getChannel()).split(":");
try {
c.announce(MaplePacketCreator.getServerIP(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]), charId));
} catch (UnknownHostException e) {
@@ -5,6 +5,7 @@ import java.net.UnknownHostException;
import net.AbstractMaplePacketHandler;
import net.server.Server;
import net.server.world.World;
import tools.MaplePacketCreator;
import tools.Randomizer;
import tools.data.input.SeekableLittleEndianAccessor;
@@ -27,7 +28,13 @@ public class ViewAllCharSelectedWithPicHandler extends AbstractMaplePacketHandle
}
c.setWorld(server.getCharacterWorld(charId));
int channel = Randomizer.rand(1, c.getWorldServer().getChannelsSize());
World wserv = c.getWorldServer();
if(wserv == null || wserv.isWorldCapacityFull()) {
c.announce(MaplePacketCreator.getAfterLoginError(10));
return;
}
int channel = Randomizer.rand(1, wserv.getChannelsSize());
c.setChannel(channel);
String macs = slea.readMapleAsciiString();
@@ -38,7 +45,8 @@ public class ViewAllCharSelectedWithPicHandler extends AbstractMaplePacketHandle
}
if (c.checkPic(pic)) {
if(c.getWorldServer().isWorldCapacityFull()) {
String[] socket = server.getInetSocket(c.getWorld(), c.getChannel());
if(socket == null) {
c.announce(MaplePacketCreator.getAfterLoginError(10));
return;
}
@@ -46,8 +54,7 @@ public class ViewAllCharSelectedWithPicHandler extends AbstractMaplePacketHandle
server.unregisterLoginState(c);
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
server.setCharacteridInTransition((InetSocketAddress) c.getSession().getRemoteAddress(), charId);
String[] socket = server.getIP(c.getWorld(), c.getChannel()).split(":");
try {
c.announce(MaplePacketCreator.getServerIP(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]), charId));
} catch (UnknownHostException e) {
@@ -0,0 +1,33 @@
/*
This file is part of the HeavenMS MapleStory Server
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 net.server.worker;
import net.server.audit.LockCollector;
/**
* @author Ronan
* @info Thread responsible for expiring locks signalized for dispose.
*/
public class ReleaseLockWorker implements Runnable {
@Override
public void run() {
LockCollector.getInstance().runLockCollector();
}
}
@@ -0,0 +1,40 @@
/*
This file is part of the HeavenMS MapleStory Server
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 net.server.worker;
import net.server.world.World;
/**
* @author Ronan
*/
public class ServerMessageWorker extends BaseWorker implements Runnable {
@Override
public void run() {
// It's purpose is for tracking whether the player client currently displays a boss HPBar and, if so,
// temporarily disable the server message for that player.
wserv.runDisabledServerMessagesSchedule();
}
public ServerMessageWorker(World world) {
super(world);
}
}
+54 -5
View File
@@ -30,9 +30,11 @@ import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Map;
import java.util.Comparator;
import net.server.audit.LockCollector;
import net.server.audit.locks.MonitoredReentrantLock;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
import server.maps.MapleDoor;
public class MapleParty {
private int id;
@@ -44,11 +46,12 @@ public class MapleParty {
private Map<Integer, Integer> histMembers = new HashMap<>();
private int nextEntry = 0;
private Map<Integer, MapleDoor> doors = new HashMap<>();
private MonitoredReentrantLock lock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.PARTY, true);
public MapleParty(int id, MaplePartyCharacter chrfor) {
this.leaderId = chrfor.getId();
this.members.add(chrfor);
this.id = id;
}
@@ -169,7 +172,7 @@ public class MapleParty {
}
}
public byte getPartyDoor(int cid) {
public List<Integer> getMembersSortedByHistory() {
List<Entry<Integer, Integer>> histList;
lock.lock();
@@ -187,16 +190,53 @@ public class MapleParty {
return ( o1.getValue() ).compareTo( o2.getValue() );
}
});
List<Integer> histSort = new LinkedList<>();
for(Entry<Integer, Integer> e : histList) {
histSort.add(e.getKey());
}
return histSort;
}
public byte getPartyDoor(int cid) {
List<Integer> histList = getMembersSortedByHistory();
byte slot = 0;
for(Entry<Integer, Integer> e: histList) {
if(e.getKey() == cid) break;
for(Integer e: histList) {
if(e == cid) break;
slot++;
}
return slot;
}
public void addDoor(Integer owner, MapleDoor door) {
lock.lock();
try {
this.doors.put(owner, door);
} finally {
lock.unlock();
}
}
public void removeDoor(Integer owner) {
lock.lock();
try {
this.doors.remove(owner);
} finally {
lock.unlock();
}
}
public Map<Integer, MapleDoor> getDoors() {
lock.lock();
try {
return Collections.unmodifiableMap(doors);
} finally {
lock.unlock();
}
}
public void assignNewLeader(MapleClient c) {
World world = c.getWorldServer();
MaplePartyCharacter newLeadr = null;
@@ -216,6 +256,15 @@ public class MapleParty {
}
public void disposeLocks() {
LockCollector.getInstance().registerDisposeAction(new Runnable() {
@Override
public void run() {
emptyLocks();
}
});
}
private void emptyLocks() {
lock = lock.dispose();
}
@@ -21,15 +21,8 @@
*/
package net.server.world;
import java.util.Map;
import java.util.Map.Entry;
import java.util.LinkedHashMap;
import java.util.Collection;
import server.maps.MapleDoor;
import client.MapleCharacter;
import client.MapleJob;
import java.util.Collections;
public class MaplePartyCharacter {
private String name;
@@ -38,7 +31,6 @@ public class MaplePartyCharacter {
private int channel, world;
private int jobid;
private int mapid;
private Map<Integer, MapleDoor> doors = new LinkedHashMap<>();
private boolean online;
private MapleJob job;
private MapleCharacter character;
@@ -54,9 +46,6 @@ public class MaplePartyCharacter {
this.mapid = maplechar.getMapId();
this.online = true;
this.job = maplechar.getJob();
for (Entry<Integer, MapleDoor> entry : maplechar.getDoors().entrySet()) {
doors.put(entry.getKey(), entry.getValue());
}
}
public MaplePartyCharacter() {
@@ -118,18 +107,6 @@ public class MaplePartyCharacter {
public int getGuildId() {
return character.getGuildId();
}
public void addDoor(Integer owner, MapleDoor door) {
this.doors.put(owner, door);
}
public void removeDoor(Integer owner) {
this.doors.remove(owner);
}
public Collection<MapleDoor> getDoors() {
return Collections.unmodifiableCollection(doors.values());
}
@Override
public int hashCode() {
+130 -32
View File
@@ -63,12 +63,15 @@ import server.maps.MaplePlayerShop;
import server.maps.MaplePlayerShopItem;
import server.maps.AbstractMapleMapObject;
import net.server.worker.CharacterAutosaverWorker;
import net.server.worker.HiredMerchantWorker;
import net.server.worker.MountTirednessWorker;
import net.server.worker.PetFullnessWorker;
import net.server.worker.ServerMessageWorker;
import net.server.worker.TimedMapObjectWorker;
import net.server.worker.WeddingReservationWorker;
import net.server.PlayerStorage;
import net.server.Server;
import net.server.audit.LockCollector;
import net.server.channel.Channel;
import net.server.channel.CharacterIdChannelPair;
import net.server.guild.MapleGuild;
@@ -119,15 +122,17 @@ public class World {
private MonitoredReentrantLock partyLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_PARTY, true);
private Map<Integer, Integer> owlSearched = new LinkedHashMap<>();
private MonitoredReentrantLock owlLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_OWL);
private Map<Integer, Integer> disabledServerMessages = new HashMap<>(); // reuse owl lock
private MonitoredReentrantLock srvMessagesLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_SRVMESSAGES);
private ScheduledFuture<?> srvMessagesSchedule;
private MonitoredReentrantLock activePetsLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_PETS, true);
private Map<Integer, Byte> activePets = new LinkedHashMap<>();
private Map<Integer, Integer> activePets = new LinkedHashMap<>();
private ScheduledFuture<?> petsSchedule;
private long petUpdate;
private MonitoredReentrantLock activeMountsLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_MOUNTS, true);
private Map<Integer, Byte> activeMounts = new LinkedHashMap<>();
private Map<Integer, Integer> activeMounts = new LinkedHashMap<>();
private ScheduledFuture<?> mountsSchedule;
private long mountUpdate;
@@ -135,7 +140,8 @@ public class World {
private Map<Integer, MaplePlayerShop> activePlayerShops = new LinkedHashMap<>();
private MonitoredReentrantLock activeMerchantsLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_MERCHS, true);
private Map<Integer, Pair<MapleHiredMerchant, Byte>> activeMerchants = new LinkedHashMap<>();
private Map<Integer, Pair<MapleHiredMerchant, Integer>> activeMerchants = new LinkedHashMap<>();
private ScheduledFuture<?> merchantSchedule;
private long merchantUpdate;
private Map<Runnable, Long> registeredTimedMapObjects = new LinkedHashMap<>();
@@ -161,7 +167,9 @@ public class World {
TimerManager tman = TimerManager.getInstance();
petsSchedule = tman.register(new PetFullnessWorker(this), 60 * 1000, 60 * 1000);
srvMessagesSchedule = tman.register(new ServerMessageWorker(this), 10 * 1000, 10 * 1000);
mountsSchedule = tman.register(new MountTirednessWorker(this), 60 * 1000, 60 * 1000);
merchantSchedule = tman.register(new HiredMerchantWorker(this), 10 * 60 * 1000, 10 * 60 * 1000);
timedMapObjectsSchedule = tman.register(new TimedMapObjectWorker(this), 60 * 1000, 60 * 1000);
charactersSchedule = tman.register(new CharacterAutosaverWorker(this), 60 * 60 * 1000, 60 * 60 * 1000);
marriagesSchedule = tman.register(new WeddingReservationWorker(this), ServerConstants.WEDDING_RESERVATION_INTERVAL * 60 * 1000, ServerConstants.WEDDING_RESERVATION_INTERVAL * 60 * 1000);
@@ -189,7 +197,11 @@ public class World {
public Channel getChannel(int channel) {
chnRLock.lock();
try {
return channels.get(channel - 1);
try {
return channels.get(channel - 1);
} catch (IndexOutOfBoundsException e) {
return null;
}
} finally {
chnRLock.unlock();
}
@@ -731,6 +743,7 @@ public class World {
partyLock.unlock();
}
party.addMember(chrfor);
return party;
}
@@ -784,7 +797,7 @@ public class World {
updateCharacterParty(party, operation, target, partyMembers);
for (MaplePartyCharacter partychar : partyMembers) {
MapleCharacter chr = getPlayerStorage().getCharacterByName(partychar.getName());
MapleCharacter chr = getPlayerStorage().getCharacterById(partychar.getId());
if (chr != null) {
if (operation == PartyOperation.DISBAND) {
chr.setParty(null);
@@ -799,7 +812,7 @@ public class World {
switch (operation) {
case LEAVE:
case EXPEL:
MapleCharacter chr = getPlayerStorage().getCharacterByName(target.getName());
MapleCharacter chr = getPlayerStorage().getCharacterById(target.getId());
if (chr != null) {
chr.getClient().announce(MaplePacketCreator.updateParty(chr.getClient().getChannel(), party, operation, target));
chr.setParty(null);
@@ -1126,7 +1139,7 @@ public class World {
}
public void addOwlItemSearch(Integer itemid) {
owlLock.lock();
srvMessagesLock.lock();
try {
Integer cur = owlSearched.get(itemid);
if(cur != null) {
@@ -1135,7 +1148,7 @@ public class World {
owlSearched.put(itemid, 1);
}
} finally {
owlLock.unlock();
srvMessagesLock.unlock();
}
}
@@ -1144,7 +1157,7 @@ public class World {
return new ArrayList<>(0);
}
owlLock.lock();
srvMessagesLock.lock();
try {
List<Pair<Integer, Integer>> searchCounts = new ArrayList<>(owlSearched.size());
@@ -1154,7 +1167,7 @@ public class World {
return searchCounts;
} finally {
owlLock.unlock();
srvMessagesLock.unlock();
}
}
@@ -1167,7 +1180,7 @@ public class World {
activePetsLock.lock();
try {
byte initProc;
int initProc;
if(System.currentTimeMillis() - petUpdate > 55000) initProc = ServerConstants.PET_EXHAUST_COUNT - 2;
else initProc = ServerConstants.PET_EXHAUST_COUNT - 1;
@@ -1189,7 +1202,7 @@ public class World {
}
public void runPetSchedule() {
Map<Integer, Byte> deployedPets;
Map<Integer, Integer> deployedPets;
activePetsLock.lock();
try {
@@ -1199,11 +1212,11 @@ public class World {
activePetsLock.unlock();
}
for(Map.Entry<Integer, Byte> dp: deployedPets.entrySet()) {
for(Map.Entry<Integer, Integer> dp: deployedPets.entrySet()) {
MapleCharacter chr = this.getPlayerStorage().getCharacterById(dp.getKey() / 4);
if(chr == null || !chr.isLoggedinWorld()) continue;
Byte dpVal = (byte)(dp.getValue() + 1);
Integer dpVal = dp.getValue() + 1;
if(dpVal == ServerConstants.PET_EXHAUST_COUNT) {
chr.runFullnessSchedule(dp.getKey() % 4);
dpVal = 0;
@@ -1226,7 +1239,7 @@ public class World {
Integer key = chr.getId();
activeMountsLock.lock();
try {
byte initProc;
int initProc;
if(System.currentTimeMillis() - mountUpdate > 45000) initProc = ServerConstants.MOUNT_EXHAUST_COUNT - 2;
else initProc = ServerConstants.MOUNT_EXHAUST_COUNT - 1;
@@ -1248,7 +1261,7 @@ public class World {
}
public void runMountSchedule() {
Map<Integer, Byte> deployedMounts;
Map<Integer, Integer> deployedMounts;
activeMountsLock.lock();
try {
mountUpdate = System.currentTimeMillis();
@@ -1257,11 +1270,11 @@ public class World {
activeMountsLock.unlock();
}
for(Map.Entry<Integer, Byte> dp: deployedMounts.entrySet()) {
for(Map.Entry<Integer, Integer> dp: deployedMounts.entrySet()) {
MapleCharacter chr = this.getPlayerStorage().getCharacterById(dp.getKey());
if(chr == null || !chr.isLoggedinWorld()) continue;
Byte dpVal = (byte)(dp.getValue() + 1);
int dpVal = dp.getValue() + 1;
if(dpVal == ServerConstants.MOUNT_EXHAUST_COUNT) {
chr.runTirednessSchedule();
dpVal = 0;
@@ -1320,8 +1333,8 @@ public class World {
public void registerHiredMerchant(MapleHiredMerchant hm) {
activeMerchantsLock.lock();
try {
byte initProc;
if(System.currentTimeMillis() - merchantUpdate > 5 * 60 * 1000) initProc = 1;
int initProc;
if(Server.getInstance().getCurrentTime() - merchantUpdate > 5 * 60 * 1000) initProc = 1;
else initProc = 0;
activeMerchants.put(hm.getOwnerId(), new Pair<>(hm, initProc));
@@ -1340,18 +1353,18 @@ public class World {
}
public void runHiredMerchantSchedule() {
Map<Integer, Pair<MapleHiredMerchant, Byte>> deployedMerchants;
Map<Integer, Pair<MapleHiredMerchant, Integer>> deployedMerchants;
activeMerchantsLock.lock();
try {
merchantUpdate = System.currentTimeMillis();
merchantUpdate = Server.getInstance().getCurrentTime();
deployedMerchants = new LinkedHashMap<>(activeMerchants);
for(Map.Entry<Integer, Pair<MapleHiredMerchant, Byte>> dm: deployedMerchants.entrySet()) {
byte timeOn = dm.getValue().getRight();
for(Map.Entry<Integer, Pair<MapleHiredMerchant, Integer>> dm: deployedMerchants.entrySet()) {
int timeOn = dm.getValue().getRight();
MapleHiredMerchant hm = dm.getValue().getLeft();
if(timeOn <= 144) { // 1440 minutes == 24hrs
activeMerchants.put(hm.getOwnerId(), new Pair<>(dm.getValue().getLeft(), (byte)(timeOn + 1)));
activeMerchants.put(hm.getOwnerId(), new Pair<>(dm.getValue().getLeft(), timeOn + 1));
} else {
hm.forceClose();
this.getChannel(hm.getChannel()).removeHiredMerchant(hm.getOwnerId());
@@ -1368,7 +1381,7 @@ public class World {
List<MapleHiredMerchant> hmList = new ArrayList<>();
activeMerchantsLock.lock();
try {
for(Pair<MapleHiredMerchant, Byte> hmp : activeMerchants.values()) {
for(Pair<MapleHiredMerchant, Integer> hmp : activeMerchants.values()) {
MapleHiredMerchant hm = hmp.getLeft();
if(hm.isOpen()) {
hmList.add(hm);
@@ -1397,7 +1410,7 @@ public class World {
public void registerTimedMapObject(Runnable r, long duration) {
timedMapObjectLock.lock();
try {
long expirationTime = System.currentTimeMillis() + duration;
long expirationTime = Server.getInstance().getCurrentTime() + duration;
registeredTimedMapObjects.put(r, expirationTime);
} finally {
timedMapObjectLock.unlock();
@@ -1409,7 +1422,7 @@ public class World {
timedMapObjectLock.lock();
try {
long timeNow = System.currentTimeMillis();
long timeNow = Server.getInstance().getCurrentTime();
for(Entry<Runnable, Long> rtmo : registeredTimedMapObjects.entrySet()) {
if(rtmo.getValue() <= timeNow) {
@@ -1429,6 +1442,68 @@ public class World {
}
}
public void resetDisabledServerMessages() {
srvMessagesLock.lock();
try {
disabledServerMessages.clear();
} finally {
srvMessagesLock.unlock();
}
}
public boolean registerDisabledServerMessage(int chrid) {
srvMessagesLock.lock();
try {
boolean alreadyDisabled = disabledServerMessages.containsKey(chrid);
disabledServerMessages.put(chrid, 0);
return alreadyDisabled;
} finally {
srvMessagesLock.unlock();
}
}
public boolean unregisterDisabledServerMessage(int chrid) {
srvMessagesLock.lock();
try {
return disabledServerMessages.remove(chrid) != null;
} finally {
srvMessagesLock.unlock();
}
}
public void runDisabledServerMessagesSchedule() {
List<Integer> toRemove = new LinkedList<>();
srvMessagesLock.lock();
try {
for(Entry<Integer, Integer> dsm : disabledServerMessages.entrySet()) {
int b = dsm.getValue();
if(b >= 4) { // ~35sec duration, 10sec update
toRemove.add(dsm.getKey());
} else {
disabledServerMessages.put(dsm.getKey(), ++b);
}
}
for(Integer chrid : toRemove) {
disabledServerMessages.remove(chrid);
}
} finally {
srvMessagesLock.unlock();
}
if(!toRemove.isEmpty()) {
for(Integer chrid : toRemove) {
MapleCharacter chr = players.getCharacterById(chrid);
if(chr != null && chr.isLoggedinWorld()) {
chr.announce(MaplePacketCreator.serverMessage(chr.getClient().getChannelServer().getServerMessage()));
}
}
}
}
public void setPlayerNpcMapStep(int mapid, int step) {
setPlayerNpcMapData(mapid, step, -1, false);
}
@@ -1670,7 +1745,7 @@ public class World {
}
}
private void disposeLocks() {
private void clearWorldData() {
List<MapleParty> pList;
partyLock.lock();
try {
@@ -1683,9 +1758,22 @@ public class World {
p.disposeLocks();
}
disposeLocks();
}
private void disposeLocks() {
LockCollector.getInstance().registerDisposeAction(new Runnable() {
@Override
public void run() {
emptyLocks();
}
});
}
private void emptyLocks() {
accountCharsLock = accountCharsLock.dispose();
partyLock = partyLock.dispose();
owlLock = owlLock.dispose();
srvMessagesLock = srvMessagesLock.dispose();
activePetsLock = activePetsLock.dispose();
activeMountsLock = activeMountsLock.dispose();
activePlayerShopsLock = activePlayerShopsLock.dispose();
@@ -1703,11 +1791,21 @@ public class World {
petsSchedule = null;
}
if(srvMessagesSchedule != null) {
srvMessagesSchedule.cancel(false);
srvMessagesSchedule = null;
}
if(mountsSchedule != null) {
mountsSchedule.cancel(false);
mountsSchedule = null;
}
if(merchantSchedule != null) {
merchantSchedule.cancel(false);
merchantSchedule = null;
}
if(timedMapObjectsSchedule != null) {
timedMapObjectsSchedule.cancel(false);
timedMapObjectsSchedule = null;
@@ -1726,6 +1824,6 @@ public class World {
players.disconnectAll();
players = null;
disposeLocks();
clearWorldData();
}
}
+114 -99
View File
@@ -22,7 +22,6 @@
package provider.wz;
import constants.GameConstants;
import constants.ServerConstants;
import java.awt.Point;
import java.io.File;
import java.io.FileInputStream;
@@ -30,8 +29,6 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.text.NumberFormat;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
@@ -74,22 +71,26 @@ public class XMLDomMapleData implements MapleData {
return ((MapleData) getParent()).getChildByPath(path.substring(path.indexOf("/") + 1));
}
Node myNode = node;
for (int x = 0; x < segments.length; x++) {
NodeList childNodes = myNode.getChildNodes();
boolean foundChild = false;
for (int i = 0; i < childNodes.getLength(); i++) {
Node childNode = childNodes.item(i);
if (childNode.getNodeType() == Node.ELEMENT_NODE && childNode.getAttributes().getNamedItem("name").getNodeValue().equals(segments[x])) {
myNode = childNode;
foundChild = true;
break;
}
}
if (!foundChild) {
return null;
}
}
Node myNode;
synchronized (this) { // the whole XML reading system seems susceptible to give nulls on strenuous read scenarios
myNode = node;
for (int x = 0; x < segments.length; x++) {
NodeList childNodes = myNode.getChildNodes();
boolean foundChild = false;
for (int i = 0; i < childNodes.getLength(); i++) {
Node childNode = childNodes.item(i);
if (childNode.getNodeType() == Node.ELEMENT_NODE && childNode.getAttributes().getNamedItem("name").getNodeValue().equals(segments[x])) {
myNode = childNode;
foundChild = true;
break;
}
}
if (!foundChild) {
return null;
}
}
}
XMLDomMapleData ret = new XMLDomMapleData(myNode);
ret.imageDataDir = new File(imageDataDir, getName() + "/" + path).getParentFile();
return ret;
@@ -97,102 +98,114 @@ public class XMLDomMapleData implements MapleData {
@Override
public List<MapleData> getChildren() {
List<MapleData> ret = new ArrayList<MapleData>();
NodeList childNodes = node.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node childNode = childNodes.item(i);
if (childNode.getNodeType() == Node.ELEMENT_NODE) {
XMLDomMapleData child = new XMLDomMapleData(childNode);
child.imageDataDir = new File(imageDataDir, getName());
ret.add(child);
}
}
List<MapleData> ret = new ArrayList<>();
synchronized (this) {
NodeList childNodes = node.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node childNode = childNodes.item(i);
if (childNode.getNodeType() == Node.ELEMENT_NODE) {
XMLDomMapleData child = new XMLDomMapleData(childNode);
child.imageDataDir = new File(imageDataDir, getName());
ret.add(child);
}
}
}
return ret;
}
@Override
public Object getData() {
NamedNodeMap attributes = node.getAttributes();
MapleDataType type = getType();
switch (type) {
case DOUBLE:
case FLOAT:
case INT:
case SHORT: {
String value = attributes.getNamedItem("value").getNodeValue();
Number nval = GameConstants.parseNumber(value);
synchronized (this) {
NamedNodeMap attributes = node.getAttributes();
MapleDataType type = getType();
switch (type) {
case DOUBLE:
case FLOAT:
case INT:
case SHORT: {
String value = attributes.getNamedItem("value").getNodeValue();
Number nval = GameConstants.parseNumber(value);
switch (type) {
case DOUBLE:
return nval.doubleValue();
case FLOAT:
return nval.floatValue();
case INT:
return nval.intValue();
case SHORT:
return nval.shortValue();
default:
return null;
switch (type) {
case DOUBLE:
return nval.doubleValue();
case FLOAT:
return nval.floatValue();
case INT:
return nval.intValue();
case SHORT:
return nval.shortValue();
default:
return null;
}
}
case STRING:
case UOL: {
String value = attributes.getNamedItem("value").getNodeValue();
return value;
}
case VECTOR: {
String x = attributes.getNamedItem("x").getNodeValue();
String y = attributes.getNamedItem("y").getNodeValue();
return new Point(Integer.parseInt(x), Integer.parseInt(y));
}
case CANVAS: {
String width = attributes.getNamedItem("width").getNodeValue();
String height = attributes.getNamedItem("height").getNodeValue();
return new FileStoredPngMapleCanvas(Integer.parseInt(width), Integer.parseInt(height), new File(
imageDataDir, getName() + ".png"));
}
default:
return null;
}
case STRING:
case UOL: {
String value = attributes.getNamedItem("value").getNodeValue();
return value;
}
case VECTOR: {
String x = attributes.getNamedItem("x").getNodeValue();
String y = attributes.getNamedItem("y").getNodeValue();
return new Point(Integer.parseInt(x), Integer.parseInt(y));
}
case CANVAS: {
String width = attributes.getNamedItem("width").getNodeValue();
String height = attributes.getNamedItem("height").getNodeValue();
return new FileStoredPngMapleCanvas(Integer.parseInt(width), Integer.parseInt(height), new File(
imageDataDir, getName() + ".png"));
}
default:
return null;
}
}
}
@Override
public MapleDataType getType() {
String nodeName = node.getNodeName();
if (nodeName.equals("imgdir")) {
return MapleDataType.PROPERTY;
} else if (nodeName.equals("canvas")) {
return MapleDataType.CANVAS;
} else if (nodeName.equals("convex")) {
return MapleDataType.CONVEX;
} else if (nodeName.equals("sound")) {
return MapleDataType.SOUND;
} else if (nodeName.equals("uol")) {
return MapleDataType.UOL;
} else if (nodeName.equals("double")) {
return MapleDataType.DOUBLE;
} else if (nodeName.equals("float")) {
return MapleDataType.FLOAT;
} else if (nodeName.equals("int")) {
return MapleDataType.INT;
} else if (nodeName.equals("short")) {
return MapleDataType.SHORT;
} else if (nodeName.equals("string")) {
return MapleDataType.STRING;
} else if (nodeName.equals("vector")) {
return MapleDataType.VECTOR;
} else if (nodeName.equals("null")) {
return MapleDataType.IMG_0x00;
}
String nodeName;
synchronized(this) {
nodeName = node.getNodeName();
}
switch (nodeName) {
case "imgdir":
return MapleDataType.PROPERTY;
case "canvas":
return MapleDataType.CANVAS;
case "convex":
return MapleDataType.CONVEX;
case "sound":
return MapleDataType.SOUND;
case "uol":
return MapleDataType.UOL;
case "double":
return MapleDataType.DOUBLE;
case "float":
return MapleDataType.FLOAT;
case "int":
return MapleDataType.INT;
case "short":
return MapleDataType.SHORT;
case "string":
return MapleDataType.STRING;
case "vector":
return MapleDataType.VECTOR;
case "null":
return MapleDataType.IMG_0x00;
}
return null;
}
@Override
public MapleDataEntity getParent() {
Node parentNode = node.getParentNode();
if (parentNode.getNodeType() == Node.DOCUMENT_NODE) {
return null;
}
Node parentNode;
synchronized(this) {
parentNode = node.getParentNode();
if (parentNode.getNodeType() == Node.DOCUMENT_NODE) {
return null;
}
}
XMLDomMapleData parentData = new XMLDomMapleData(parentNode);
parentData.imageDataDir = imageDataDir.getParentFile();
return parentData;
@@ -200,7 +213,9 @@ public class XMLDomMapleData implements MapleData {
@Override
public String getName() {
return node.getAttributes().getNamedItem("name").getNodeValue();
synchronized (this) {
return node.getAttributes().getNamedItem("name").getNodeValue();
}
}
@Override
+30 -12
View File
@@ -35,6 +35,7 @@ import java.util.Set;
import java.util.Iterator;
import java.util.Properties;
import javax.script.ScriptException;
import net.server.audit.LockCollector;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.MonitoredReentrantLock;
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
@@ -232,12 +233,11 @@ public class EventInstanceManager {
wL.lock();
try {
chars.put(chr.getId(), chr);
chr.setEventInstance(this);
} finally {
wL.unlock();
}
chr.setEventInstance(this);
sL.lock();
try {
em.getIv().invokeFunction("playerEntry", this, chr);
@@ -403,14 +403,13 @@ public class EventInstanceManager {
wL.lock();
try {
chars.remove(chr.getId());
chr.setEventInstance(null);
} finally {
wL.unlock();
}
gridRemove(chr);
dropExclusiveItems(chr);
chr.setEventInstance(null);
}
public int getPlayerCount() {
@@ -635,6 +634,13 @@ public class EventInstanceManager {
}
public void dispose() {
rL.lock();
try {
for(MapleCharacter chr: chars.values()) chr.setEventInstance(null);
} finally {
rL.unlock();
}
Thread t = new Thread( new Runnable() {
@Override
public void run() {
@@ -645,7 +651,7 @@ public class EventInstanceManager {
t.start();
}
public synchronized void dispose(boolean shutdown) {
public synchronized void dispose(boolean shutdown) { // should not trigger any event script method after disposed
if(disposed) return;
disposed = true;
@@ -660,14 +666,12 @@ public class EventInstanceManager {
ex.printStackTrace();
}
mapFactory.dispose();
wL.lock();
try {
for(MapleCharacter chr: chars.values()) chr.setEventInstance(null);
chars.clear();
mobs.clear();
mapFactory.dispose();
mapFactory = null;
} finally {
wL.unlock();
@@ -696,6 +700,15 @@ public class EventInstanceManager {
}
private void disposeLocks() {
LockCollector.getInstance().registerDisposeAction(new Runnable() {
@Override
public void run() {
emptyLocks();
}
});
}
private void emptyLocks() {
pL = pL.dispose();
sL = sL.dispose();
}
@@ -878,9 +891,9 @@ public class EventInstanceManager {
return (chr.getId() == getLeaderId());
}
public final MapleMap getInstanceMap(final int mapid) { //gets instance map from the channelserv
public final MapleMap getInstanceMap(final int mapid) {
if (disposed) {
return getMapFactory().getMap(mapid);
return null;
}
mapIds.add(mapid);
return getMapFactory().getMap(mapid);
@@ -1310,15 +1323,20 @@ public class EventInstanceManager {
}
public final void recoverOpenedGate(MapleCharacter chr, int thisMapId) {
Pair<String, Integer> gateData = null;
rL.lock();
try {
if(openedGates.containsKey(thisMapId)) {
Pair<String, Integer> gateData = openedGates.get(thisMapId);
chr.announce(MaplePacketCreator.environmentChange(gateData.getLeft(), gateData.getRight()));
gateData = openedGates.get(thisMapId);
}
} finally {
rL.unlock();
}
if(gateData != null) {
chr.announce(MaplePacketCreator.environmentChange(gateData.getLeft(), gateData.getRight()));
}
}
public final void giveEventPlayersStageReward(int thisStage) {
+31 -7
View File
@@ -52,6 +52,7 @@ import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import net.server.audit.LockCollector;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.MonitoredReentrantLock;
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
@@ -131,6 +132,15 @@ public class EventManager {
}
private void disposeLocks() {
LockCollector.getInstance().registerDisposeAction(new Runnable() {
@Override
public void run() {
emptyLocks();
}
});
}
private void emptyLocks() {
lobbyLock = lobbyLock.dispose();
queueLock = queueLock.dispose();
}
@@ -333,7 +343,9 @@ public class EventManager {
EventInstanceManager eim = (EventInstanceManager) (iv.invokeFunction("setup", leader.getClient().getChannel()));
if(eim == null) {
if(lobbyId > -1) setLockLobby(lobbyId, false);
if(lobbyId > -1) {
setLockLobby(lobbyId, false);
}
return false;
}
instanceLocks.put(eim.getName(), lobbyId);
@@ -363,15 +375,21 @@ public class EventManager {
try {
if(lobbyId == -1) {
lobbyId = availableLobbyInstance();
if(lobbyId == -1) return false;
if(lobbyId == -1) {
return false;
}
}
else {
if(!startLobbyInstance(lobbyId)) return false;
if(!startLobbyInstance(lobbyId)) {
return false;
}
}
EventInstanceManager eim = (EventInstanceManager) (iv.invokeFunction("setup", difficulty, (lobbyId > -1) ? lobbyId : leader.getId()));
if(eim == null) {
if(lobbyId > -1) setLockLobby(lobbyId, false);
if(lobbyId > -1) {
setLockLobby(lobbyId, false);
}
return false;
}
instanceLocks.put(eim.getName(), lobbyId);
@@ -408,7 +426,9 @@ public class EventManager {
EventInstanceManager eim = (EventInstanceManager) (iv.invokeFunction("setup", (Object) null));
if(eim == null) {
if(lobbyId > -1) setLockLobby(lobbyId, false);
if(lobbyId > -1) {
setLockLobby(lobbyId, false);
}
return false;
}
instanceLocks.put(eim.getName(), lobbyId);
@@ -446,7 +466,9 @@ public class EventManager {
EventInstanceManager eim = (EventInstanceManager) (iv.invokeFunction("setup", difficulty, (lobbyId > -1) ? lobbyId : party.getLeaderId()));
if(eim == null) {
if(lobbyId > -1) setLockLobby(lobbyId, false);
if(lobbyId > -1) {
setLockLobby(lobbyId, false);
}
return false;
}
instanceLocks.put(eim.getName(), lobbyId);
@@ -487,7 +509,9 @@ public class EventManager {
}
if(eim == null) {
if(lobbyId > -1) setLockLobby(lobbyId, false);
if(lobbyId > -1) {
setLockLobby(lobbyId, false);
}
return false;
}
instanceLocks.put(eim.getName(), lobbyId);
@@ -28,6 +28,7 @@ import java.util.Map.Entry;
import java.util.concurrent.ScheduledFuture;
import server.TimerManager;
import net.server.Server;
import net.server.audit.LockCollector;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.MonitoredReentrantLock;
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
@@ -161,10 +162,23 @@ public class EventScriptScheduler {
schedulerLock.unlock();
}
schedulerLock = schedulerLock.dispose();
disposeLocks();
}
});
t.start();
}
private void disposeLocks() {
LockCollector.getInstance().registerDisposeAction(new Runnable() {
@Override
public void run() {
emptyLocks();
}
});
}
private void emptyLocks() {
schedulerLock = schedulerLock.dispose();
}
}
@@ -25,6 +25,8 @@ import client.MapleClient;
import scripting.npc.NPCConversationManager;
import server.MapleItemInformationProvider;
import server.quest.MapleQuest;
import server.quest.actions.ExpAction;
import server.quest.actions.MesoAction;
/**
*
@@ -71,6 +73,16 @@ public class QuestActionManager extends NPCConversationManager {
forceCompleteQuest();
}
@Override
public void gainExp(int gain) {
ExpAction.runAction(getPlayer(), gain);
}
@Override
public void gainMeso(int gain) {
MesoAction.runAction(getPlayer(), gain);
}
public String getMedalName() { // usable only for medal quests (id 299XX)
MapleQuest q = MapleQuest.getInstance(quest);
return MapleItemInformationProvider.getInstance().getName(q.getMedalRequirement());
+1 -9
View File
@@ -897,15 +897,7 @@ public class MapleStatEffect {
MapleDoor door = new MapleDoor(applyto, doorPosition);
if(door.getOwnerId() >= 0) {
if (applyto.getParty() != null) {
for (MaplePartyCharacter partyMember : applyto.getParty().getMembers()) {
partyMember.getPlayer().addDoor(door.getOwnerId(), door);
partyMember.addDoor(door.getOwnerId(), door);
}
applyto.silentPartyUpdate();
} else {
applyto.addDoor(door.getOwnerId(), door);
}
applyto.applyPartyDoor(door, false);
door.getTarget().spawnDoor(door.getAreaDoor());
door.getTown().spawnDoor(door.getTownDoor());
+11 -10
View File
@@ -69,6 +69,7 @@ import server.maps.MapleMapObjectType;
import tools.MaplePacketCreator;
import tools.Pair;
import tools.Randomizer;
import net.server.audit.LockCollector;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
@@ -823,10 +824,6 @@ public class MapleMonster extends AbstractLoadedMapleLife {
}
if (hasBossHPBar()) {
if (this.getMap().countMonster(8810026) > 0 && this.getMap().getId() == 240060200) {
this.getMap().killAllMonsters();
return;
}
c.announceBossHpBar(this, this.hashCode(), makeBossHPBarPacket());
}
}
@@ -855,12 +852,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
statiLock.unlock();
}
monsterLock.lock();
try {
return stats.getEffectiveness(e);
} finally {
monsterLock.unlock();
}
return getMonsterEffectiveness(e);
}
private ElementalEffectiveness getMonsterEffectiveness(Element e) {
@@ -1478,6 +1470,15 @@ public class MapleMonster extends AbstractLoadedMapleLife {
}
public final void disposeLocks() {
LockCollector.getInstance().registerDisposeAction(new Runnable() {
@Override
public void run() {
emptyLocks();
}
});
}
private void emptyLocks() {
externalLock = externalLock.dispose();
monsterLock = monsterLock.dispose();
statiLock = statiLock.dispose();
+14 -15
View File
@@ -22,7 +22,6 @@
package server.maps;
import java.awt.Point;
import java.util.List;
import tools.Pair;
import server.MaplePortal;
@@ -43,7 +42,7 @@ public class MapleDoor {
private MapleDoorObject townDoor;
private MapleDoorObject areaDoor;
public MapleDoor(MapleCharacter owner, Point targetPosition) {
this.ownerId = owner.getId();
this.target = owner.getMap();
@@ -55,11 +54,11 @@ public class MapleDoor {
if(posStatus == null) {
this.town = this.target.getReturnMap();
this.townPortal = getDoorPortal(owner.getDoorSlot());
this.townPortal = getTownDoorPortal(owner.getDoorSlot());
if(townPortal != null) {
this.areaDoor = new MapleDoorObject(ownerId, town, target, false, targetPosition, townPortal.getPosition());
this.townDoor = new MapleDoorObject(ownerId, target, town, true, townPortal.getPosition(), targetPosition);
this.areaDoor = new MapleDoorObject(ownerId, town, target, townPortal.getId(), targetPosition, townPortal.getPosition());
this.townDoor = new MapleDoorObject(ownerId, target, town, -1, townPortal.getPosition(), targetPosition);
this.areaDoor.setPairOid(this.townDoor.getObjectId());
this.townDoor.setPairOid(this.areaDoor.getObjectId());
@@ -74,20 +73,20 @@ public class MapleDoor {
}
}
private MaplePortal getDoorPortal(int slot) {
List<MaplePortal> avail = town.getAvailableDoorPortals();
public void updateDoorPortal(MapleCharacter owner) {
int slot = owner.fetchDoorSlot();
try {
return avail.get(slot);
} catch (IndexOutOfBoundsException e) {
try {
return avail.get(0);
} catch (IndexOutOfBoundsException ex) {
return null;
}
MaplePortal nextTownPortal = getTownDoorPortal(slot);
if(nextTownPortal != null) {
townPortal = nextTownPortal;
areaDoor.update(nextTownPortal.getId(), nextTownPortal.getPosition());
}
}
private MaplePortal getTownDoorPortal(int doorid) {
return town.getDoorPortal(doorid);
}
public int getOwnerId() {
return ownerId;
}
+64 -16
View File
@@ -20,8 +20,11 @@
package server.maps;
import java.awt.Point;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import client.MapleCharacter;
import client.MapleClient;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
import tools.MaplePacketCreator;
/**
@@ -29,28 +32,66 @@ import tools.MaplePacketCreator;
* @author Ronan
*/
public class MapleDoorObject extends AbstractMapleMapObject {
private int ownerId;
private final int ownerId;
private int pairOid;
private boolean isTown;
private MapleMap from;
private MapleMap to;
private Point toPos;
private final MapleMap from;
private final MapleMap to;
private int linkedPortalId;
private Point linkedPos;
public MapleDoorObject(int owner, MapleMap destination, MapleMap origin, boolean town, Point targetPosition, Point toPosition) {
private final ReentrantReadWriteLock locks = new MonitoredReentrantReadWriteLock(MonitoredLockType.PLAYER_DOOR, true);
private ReentrantReadWriteLock.ReadLock rlock = locks.readLock();
private ReentrantReadWriteLock.WriteLock wlock = locks.writeLock();
public MapleDoorObject(int owner, MapleMap destination, MapleMap origin, int townPortalId, Point targetPosition, Point toPosition) {
super();
setPosition(targetPosition);
ownerId = owner;
isTown = town;
linkedPortalId = townPortalId;
from = origin;
to = destination;
toPos = toPosition;
linkedPos = toPosition;
}
public void update(int townPortalId, Point toPosition) {
wlock.lock();
try {
linkedPortalId = townPortalId;
linkedPos = toPosition;
} finally {
wlock.unlock();
}
}
private int getLinkedPortalId() {
rlock.lock();
try {
return linkedPortalId;
} finally {
rlock.unlock();
}
}
private Point getLinkedPortalPosition() {
rlock.lock();
try {
return linkedPos;
} finally {
rlock.unlock();
}
}
public void warp(final MapleCharacter chr) {
if (chr.getId() == ownerId || (chr.getParty() != null && chr.getParty().getMemberById(ownerId) != null)) {
chr.changeMap(to, toPos);
boolean onParty = chr.getParty() != null;
if (chr.getId() == ownerId || (onParty && chr.getParty().getMemberById(ownerId) != null)) {
if(!inTown() && !onParty) {
chr.changeMap(to, getLinkedPortalId());
} else {
chr.changeMap(to, getLinkedPortalPosition());
}
} else {
chr.getClient().announce(MaplePacketCreator.blockedMessage(6));
chr.getClient().announce(MaplePacketCreator.enableActions());
@@ -75,7 +116,14 @@ public class MapleDoorObject extends AbstractMapleMapObject {
if (client.getPlayer().getParty() != null && (ownerId == client.getPlayer().getId() || client.getPlayer().getParty().getMemberById(ownerId) != null)) {
client.announce(MaplePacketCreator.partyPortal(999999999, 999999999, new Point(-1, -1)));
}
client.announce(MaplePacketCreator.removeDoor(ownerId, isTown));
client.announce(MaplePacketCreator.removeDoor(ownerId, inTown()));
}
}
public void sendDestroyData(MapleClient client, boolean partyUpdate) {
if (client != null && from.getId() == client.getPlayer().getMapId()) {
client.announce(MaplePacketCreator.partyPortal(999999999, 999999999, new Point(-1, -1)));
client.announce(MaplePacketCreator.removeDoor(ownerId, inTown()));
}
}
@@ -92,7 +140,7 @@ public class MapleDoorObject extends AbstractMapleMapObject {
}
public boolean inTown() {
return isTown;
return getLinkedPortalId() == -1;
}
public MapleMap getFrom() {
@@ -104,19 +152,19 @@ public class MapleDoorObject extends AbstractMapleMapObject {
}
public MapleMap getTown() {
return isTown ? from : to;
return inTown() ? from : to;
}
public MapleMap getArea() {
return !isTown ? from : to;
return !inTown() ? from : to;
}
public Point getAreaPosition() {
return !isTown ? getPosition() : toPos;
return !inTown() ? getPosition() : getLinkedPortalPosition();
}
public Point toPosition() {
return toPos;
return getLinkedPortalPosition();
}
@Override
+16 -22
View File
@@ -982,7 +982,7 @@ public class MapleMap {
}
private static boolean shouldShowQuestItem(MapleCharacter chr, int questid, int itemid) {
return questid <= 0 || (chr.getQuestStatus(questid) == 1 && chr.needQuestItem(questid, itemid));
return questid <= 0 || chr.needQuestItem(questid, itemid);
}
public void updatePlayerItemDrops(int partyid, int charid, List<MapleCharacter> partyMembers, MapleCharacter partyLeaver) {
@@ -1462,7 +1462,7 @@ public class MapleMap {
removeMapObject(reactor);
if (reactor.getDelay() > 0) {
TimerManager.getInstance().schedule(new Runnable() {
registerMapSchedule(new Runnable() {
@Override
public void run() {
respawnReactor(reactor);
@@ -1857,14 +1857,14 @@ public class MapleMap {
final selfDestruction selfDestruction = monster.getStats().selfDestruction();
if (monster.getStats().removeAfter() > 0 || selfDestruction != null && selfDestruction.getHp() < 0) {
if (selfDestruction == null) {
TimerManager.getInstance().schedule(new Runnable() {
registerMapSchedule(new Runnable() {
@Override
public void run() {
killMonster(monster, null, false);
}
}, monster.getStats().removeAfter() * 1000);
} else {
TimerManager.getInstance().schedule(new Runnable() {
registerMapSchedule(new Runnable() {
@Override
public void run() {
killMonster(monster, null, false, selfDestruction.getAction());
@@ -2037,23 +2037,16 @@ public class MapleMap {
});
}
public List<MaplePortal> getAvailableDoorPortals() {
objectRLock.lock();
try {
List<MaplePortal> availablePortals = new ArrayList<>();
for (MaplePortal port : portals.values()) {
if (port.getType() == MaplePortal.DOOR_PORTAL) {
availablePortals.add(port);
}
}
return availablePortals;
} finally {
objectRLock.unlock();
public MaplePortal getDoorPortal(int doorid) {
MaplePortal doorPortal = portals.get(0x80 + doorid);
if(doorPortal == null) {
FilePrinter.printError(FilePrinter.EXCEPTION, "[DOOR] " + mapName + "(" + mapid + ") does not contain door portalid " + doorid);
return portals.get(0x80);
}
return doorPortal;
}
public void spawnSummon(final MapleSummon summon) {
spawnAndAddRangedMapObject(summon, new DelayedPacketCreation() {
@Override
@@ -2945,7 +2938,7 @@ public class MapleMap {
public MaplePortal getPortal(int portalid) {
return portals.get(portalid);
}
public void addMapleArea(Rectangle rec) {
areas.add(rec);
}
@@ -3323,8 +3316,9 @@ public class MapleMap {
reactor.hitReactor(c);
if (reactor.getDelay() > 0) {
TimerManager tMan = TimerManager.getInstance();
tMan.schedule(new Runnable() {
MapleMap reactorMap = reactor.getMap();
reactorMap.getChannelServer().registerOverallAction(reactorMap.getId(), new Runnable() {
@Override
public void run() {
reactor.lockReactor();
+1 -1
View File
@@ -184,7 +184,7 @@ public class MapleMapItem extends AbstractMapleMapObject {
public void sendSpawnData(final MapleClient client) {
MapleCharacter chr = client.getPlayer();
if (questid <= 0 || (chr.getQuestStatus(questid) == 1 && chr.needQuestItem(questid, item.getItemId()))) {
if (questid <= 0 || chr.needQuestItem(questid, item.getItemId())) {
this.lockItem();
try {
client.announce(MaplePacketCreator.dropItemFromMapObject(chr.getParty() != null, this, null, getPosition(), (byte) 2));
+9 -5
View File
@@ -48,14 +48,18 @@ public class ExpAction extends MapleQuestAction {
@Override
public void run(MapleCharacter chr, Integer extSelection) {
if (chr.isBeginnerJob() && chr.getLevel() < 10) {
chr.gainExp(exp, true, true);
runAction(chr, exp);
}
public static void runAction(MapleCharacter chr, int gain) {
if (chr.isBeginnerJob() && chr.getLevel() < 10) {
chr.gainExp(gain, true, true);
} else {
if(!ServerConstants.USE_QUEST_RATE) {
chr.gainExp(exp * chr.getExpRate(), true, true);
chr.gainExp(gain * chr.getExpRate(), true, true);
} else {
chr.gainExp(exp * ServerConstants.EXP_RATE * ServerConstants.QUEST_RATE, true, true);
chr.gainExp(gain * ServerConstants.EXP_RATE * ServerConstants.QUEST_RATE, true, true);
}
}
}
}
}
+9 -5
View File
@@ -49,14 +49,18 @@ public class MesoAction extends MapleQuestAction {
@Override
public void run(MapleCharacter chr, Integer extSelection) {
if(mesos < 0) {
chr.gainMeso(mesos, true, false, true);
runAction(chr, mesos);
}
public static void runAction(MapleCharacter chr, int gain) {
if(gain < 0) {
chr.gainMeso(gain, true, false, true);
} else {
if(!ServerConstants.USE_QUEST_RATE) {
chr.gainMeso(mesos * chr.getMesoRate(), true, false, true);
chr.gainMeso(gain * chr.getMesoRate(), true, false, true);
} else {
chr.gainMeso(mesos * ServerConstants.MESO_RATE * ServerConstants.QUEST_RATE, true, false, true);
chr.gainMeso(gain * ServerConstants.MESO_RATE * ServerConstants.QUEST_RATE, true, false, true);
}
}
}
}
}
+2 -1
View File
@@ -49,7 +49,8 @@ public class FilePrinter {
DEADLOCK_ERROR = "deadlocks.txt",
DEADLOCK_STACK = "deadlocks/path.txt",
DEADLOCK_LOCKS = "deadlocks/locks.txt",
DEADLOCK_STATE = "deadlocks/state.txt";
DEADLOCK_STATE = "deadlocks/state.txt",
DISPOSED_LOCKS = "deadlocks/disposed.txt";
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); //for file system purposes, it's nice to use yyyy-MM-dd
private static final String FILE_PATH = "logs/" + sdf.format(Calendar.getInstance().getTime()) + "/"; // + sdf.format(Calendar.getInstance().getTime()) + "/"
+28 -35
View File
@@ -628,7 +628,7 @@ public class MaplePacketCreator {
public static byte[] getAfterLoginError(int reason) {//same as above o.o
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(8);
mplew.writeShort(SendOpcode.SELECT_CHARACTER_BY_VAC.getValue());
mplew.writeShort(reason);//using other types then stated above = CRASH
mplew.writeShort(reason);//using other types than stated above = CRASH
return mplew.getPacket();
}
@@ -677,6 +677,8 @@ public class MaplePacketCreator {
* @return the successful authentication packet
*/
public static byte[] getAuthSuccess(MapleClient c) {
Server.getInstance().loadAccountCharacters(c); // locks the login session until data is recovered from the cache or the DB.
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.LOGIN_STATUS.getValue());
mplew.writeInt(0);
@@ -686,7 +688,7 @@ public class MaplePacketCreator {
boolean canFly = Server.getInstance().canFly(c.getAccID());
mplew.writeBool((ServerConstants.USE_ENFORCE_ADMIN_ACCOUNT || canFly) ? c.getGMLevel() > 1 : false); // thanks Steve(kaito1410) for pointing the GM account boolean here
mplew.write((c.getGMLevel() > 1 && canFly) ? 0x80 : 0); // Admin Byte. 0x80,0x40,0x20.. Rubbish.
mplew.write(((ServerConstants.USE_ENFORCE_ADMIN_ACCOUNT || canFly) && c.getGMLevel() > 1) ? 0x80 : 0); // Admin Byte. 0x80,0x40,0x20.. Rubbish.
mplew.write(0); // Country Code.
mplew.writeMapleAsciiString(c.getAccountName());
@@ -3689,27 +3691,23 @@ public class MaplePacketCreator {
return mplew.getPacket();
}
public static byte[] partyCreated(MaplePartyCharacter partychar, int partyId) {
public static byte[] partyCreated(MapleParty party, int partycharid) {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.PARTY_OPERATION.getValue());
mplew.write(8);
mplew.writeInt(partyId);
if (partychar.getDoors().size() > 0) {
boolean deployedPortal = false;
for (MapleDoor door : partychar.getDoors()) {
if(door.getOwnerId() == partychar.getId()) {
MapleDoorObject mdo = door.getAreaDoor();
mplew.writeInt(mdo.getTo().getId());
mplew.writeInt(mdo.getFrom().getId());
mplew.writeInt(mdo.getPosition().x);
mplew.writeInt(mdo.getPosition().y);
deployedPortal = true;
}
}
mplew.writeInt(party.getId());
Map<Integer, MapleDoor> partyDoors = party.getDoors();
if (partyDoors.size() > 0) {
MapleDoor door = partyDoors.get(partycharid);
if(!deployedPortal) {
if(door != null) {
MapleDoorObject mdo = door.getAreaDoor();
mplew.writeInt(mdo.getTo().getId());
mplew.writeInt(mdo.getFrom().getId());
mplew.writeInt(mdo.getPosition().x);
mplew.writeInt(mdo.getPosition().y);
} else {
mplew.writeInt(999999999);
mplew.writeInt(999999999);
mplew.writeInt(0);
@@ -3798,24 +3796,19 @@ public class MaplePacketCreator {
lew.writeInt(0);
}
}
Map<Integer, MapleDoor> partyDoors = party.getDoors();
for (MaplePartyCharacter partychar : partymembers) {
if (partychar.getChannel() == forchannel && !leaving) {
if (partychar.getDoors().size() > 0) {
boolean deployedPortal = false;
for (MapleDoor door : partychar.getDoors()) {
if(door.getOwnerId() == partychar.getId()) {
MapleDoorObject mdo = door.getTownDoor();
lew.writeInt(mdo.getTown().getId());
lew.writeInt(mdo.getArea().getId());
lew.writeInt(mdo.getPosition().x);
lew.writeInt(mdo.getPosition().y);
deployedPortal = true;
}
}
if(!deployedPortal) {
if (partyDoors.size() > 0) {
MapleDoor door = partyDoors.get(partychar.getId());
if(door != null) {
MapleDoorObject mdo = door.getTownDoor();
lew.writeInt(mdo.getTown().getId());
lew.writeInt(mdo.getArea().getId());
lew.writeInt(mdo.getPosition().x);
lew.writeInt(mdo.getPosition().y);
} else {
lew.writeInt(999999999);
lew.writeInt(999999999);
lew.writeInt(0);