From e75139e5e6ae83c7a5447115ec92ce2650906adb Mon Sep 17 00:00:00 2001 From: P0nk Date: Thu, 9 Sep 2021 21:32:52 +0200 Subject: [PATCH] Rename and clean up MapleMonsterAggroCoordinator --- ...ator.java => MonsterAggroCoordinator.java} | 126 ++++++++++-------- src/main/java/server/life/MapleMonster.java | 12 +- src/main/java/server/maps/MapleMap.java | 8 +- 3 files changed, 77 insertions(+), 69 deletions(-) rename src/main/java/net/server/coordinator/world/{MapleMonsterAggroCoordinator.java => MonsterAggroCoordinator.java} (91%) diff --git a/src/main/java/net/server/coordinator/world/MapleMonsterAggroCoordinator.java b/src/main/java/net/server/coordinator/world/MonsterAggroCoordinator.java similarity index 91% rename from src/main/java/net/server/coordinator/world/MapleMonsterAggroCoordinator.java rename to src/main/java/net/server/coordinator/world/MonsterAggroCoordinator.java index fdef4e5604..c4f24fe242 100644 --- a/src/main/java/net/server/coordinator/world/MapleMonsterAggroCoordinator.java +++ b/src/main/java/net/server/coordinator/world/MonsterAggroCoordinator.java @@ -36,57 +36,60 @@ import java.util.Map.Entry; import java.util.concurrent.ScheduledFuture; /** - * * @author Ronan */ -public class MapleMonsterAggroCoordinator { - +public class MonsterAggroCoordinator { + private MonitoredReentrantLock lock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.MAP_AGGRO); - private MonitoredReentrantLock idleLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.MAP_AGGRO_IDLE, true); + private final MonitoredReentrantLock idleLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.MAP_AGGRO_IDLE, true); private long lastStopTime = Server.getInstance().getCurrentTime(); - + private ScheduledFuture aggroMonitor = null; - - private Map> mobAggroEntries = new HashMap<>(); - private Map> mobSortedAggros = new HashMap<>(); - - private Set mapPuppetEntries = new HashSet<>(); - + + private final Map> mobAggroEntries = new HashMap<>(); + private final Map> mobSortedAggros = new HashMap<>(); + + private final Set mapPuppetEntries = new HashSet<>(); + private class PlayerAggroEntry { protected int cid; protected int averageDamage = 0; protected int currentDamageInstances = 0; protected long accumulatedDamage = 0; - + protected int expireStreak = 0; protected int updateStreak = 0; protected int toNextUpdate = 0; protected int entryRank = -1; - + protected PlayerAggroEntry(int cid) { this.cid = cid; } } - + public void stopAggroCoordinator() { idleLock.lock(); try { - if (aggroMonitor == null) return; - + if (aggroMonitor == null) { + return; + } + aggroMonitor.cancel(false); aggroMonitor = null; } finally { idleLock.unlock(); } - + lastStopTime = Server.getInstance().getCurrentTime(); } - + public void startAggroCoordinator() { idleLock.lock(); try { - if (aggroMonitor != null) return; - + if (aggroMonitor != null) { + return; + } + aggroMonitor = TimerManager.getInstance().register(() -> { runAggroUpdate(1); runSortLeadingCharactersAggro(); @@ -94,17 +97,17 @@ public class MapleMonsterAggroCoordinator { } finally { idleLock.unlock(); } - + int timeDelta = (int) Math.ceil((Server.getInstance().getCurrentTime() - lastStopTime) / YamlConfig.config.server.MOB_STATUS_AGGRO_INTERVAL); if (timeDelta > 0) { runAggroUpdate(timeDelta); } } - + private static void updateEntryExpiration(PlayerAggroEntry pae) { pae.toNextUpdate = (int) Math.ceil((120000L / YamlConfig.config.server.MOB_STATUS_AGGRO_INTERVAL) / Math.pow(2, pae.expireStreak + pae.currentDamageInstances)); } - + private static void insertEntryDamage(PlayerAggroEntry pae, int damage) { synchronized (pae) { long totalDamage = pae.averageDamage; @@ -116,16 +119,16 @@ public class MapleMonsterAggroCoordinator { updateEntryExpiration(pae); pae.currentDamageInstances += 1; - pae.averageDamage = (int)(totalDamage / pae.currentDamageInstances); + pae.averageDamage = (int) (totalDamage / pae.currentDamageInstances); pae.accumulatedDamage = totalDamage; } } - + private static boolean expiredAfterUpdateEntryDamage(PlayerAggroEntry pae, int deltaTime) { synchronized (pae) { pae.updateStreak += 1; pae.toNextUpdate -= deltaTime; - + if (pae.toNextUpdate <= 0) { // reached dmg instance expire time pae.expireStreak += 1; updateEntryExpiration(pae); @@ -136,14 +139,16 @@ public class MapleMonsterAggroCoordinator { } pae.accumulatedDamage = pae.averageDamage * pae.currentDamageInstances; } - + return false; } } - + public void addAggroDamage(MapleMonster mob, int cid, int damage) { // assumption: should not trigger after dispose() - if (!mob.isAlive()) return; - + if (!mob.isAlive()) { + return; + } + List sortedAggro = mobSortedAggros.get(mob); Map mobAggro = mobAggroEntries.get(mob); if (mobAggro == null) { @@ -153,7 +158,7 @@ public class MapleMonsterAggroCoordinator { if (mobAggro == null) { mobAggro = new HashMap<>(); mobAggroEntries.put(mob, mobAggro); - + sortedAggro = new LinkedList<>(); mobSortedAggros.put(mob, sortedAggro); } else { @@ -166,15 +171,15 @@ public class MapleMonsterAggroCoordinator { return; } } - + PlayerAggroEntry aggroEntry = mobAggro.get(cid); if (aggroEntry == null) { aggroEntry = new PlayerAggroEntry(cid); - + synchronized (mobAggro) { synchronized (sortedAggro) { PlayerAggroEntry mappedEntry = mobAggro.get(cid); - + if (mappedEntry == null) { mobAggro.put(aggroEntry.cid, aggroEntry); sortedAggro.add(aggroEntry); @@ -186,10 +191,10 @@ public class MapleMonsterAggroCoordinator { } else if (damage < 1) { return; } - + insertEntryDamage(aggroEntry, damage); } - + private void runAggroUpdate(int deltaTime) { List>> aggroMobs = new LinkedList<>(); lock.lock(); @@ -200,11 +205,11 @@ public class MapleMonsterAggroCoordinator { } finally { lock.unlock(); } - + for (Pair> am : aggroMobs) { Map mobAggro = am.getRight(); List sortedAggro = mobSortedAggros.get(am.getLeft()); - + if (sortedAggro != null) { List toRemove = new LinkedList<>(); List toRemoveIdx = new ArrayList<>(mobAggro.size()); @@ -215,8 +220,11 @@ public class MapleMonsterAggroCoordinator { for (PlayerAggroEntry pae : mobAggro.values()) { if (expiredAfterUpdateEntryDamage(pae, deltaTime)) { toRemove.add(pae.cid); - if (pae.entryRank > -1) toRemoveIdx.add(pae.entryRank); - else toRemoveByFetch.add(pae.cid); + if (pae.entryRank > -1) { + toRemoveIdx.add(pae.entryRank); + } else { + toRemoveByFetch.add(pae.cid); + } } } @@ -224,7 +232,7 @@ public class MapleMonsterAggroCoordinator { for (Integer cid : toRemove) { mobAggro.remove(cid); } - + if (mobAggro.isEmpty()) { // all aggro on this mob expired if (!am.getLeft().isBoss()) { am.getLeft().aggroResetAggro(); @@ -240,7 +248,7 @@ public class MapleMonsterAggroCoordinator { sortedAggro.remove(idx); } } - + if (!toRemoveByFetch.isEmpty()) { for (Integer cid : toRemoveByFetch) { for (int i = 0; i < sortedAggro.size(); i++) { @@ -256,7 +264,7 @@ public class MapleMonsterAggroCoordinator { } } } - + private static void insertionSortAggroList(List paeList) { for (int i = 1; i < paeList.size(); i++) { PlayerAggroEntry pae = paeList.get(i); @@ -280,23 +288,23 @@ public class MapleMonsterAggroCoordinator { i += 1; } } - + public boolean isLeadingCharacterAggro(MapleMonster mob, Character player) { if (mob.isLeadingPuppetInVicinity()) { return false; } else if (mob.isCharacterPuppetInVicinity(player)) { return true; } - + // by assuming the quasi-sorted nature of "mobAggroList", this method // returns whether the player given as parameter can be elected as next aggro leader - + List mobAggroList = mobSortedAggros.get(mob); if (mobAggroList != null) { synchronized (mobAggroList) { mobAggroList = new ArrayList<>(mobAggroList.subList(0, Math.min(mobAggroList.size(), 5))); } - + MapleMap map = mob.getMap(); for (PlayerAggroEntry pae : mobAggroList) { Character chr = map.getCharacterById(pae.cid); @@ -309,10 +317,10 @@ public class MapleMonsterAggroCoordinator { } } } - + return false; } - + public void runSortLeadingCharactersAggro() { List> aggroList; lock.lock(); @@ -321,14 +329,14 @@ public class MapleMonsterAggroCoordinator { } finally { lock.unlock(); } - + for (List mobAggroList : aggroList) { synchronized (mobAggroList) { insertionSortAggroList(mobAggroList); } } } - + public void removeAggroEntries(MapleMonster mob) { lock.lock(); try { @@ -338,28 +346,28 @@ public class MapleMonsterAggroCoordinator { lock.unlock(); } } - + public void addPuppetAggro(Character player) { synchronized (mapPuppetEntries) { mapPuppetEntries.add(player.getId()); } } - + public void removePuppetAggro(Integer cid) { synchronized (mapPuppetEntries) { mapPuppetEntries.remove(cid); } } - + public List getPuppetAggroList() { synchronized (mapPuppetEntries) { return new ArrayList<>(mapPuppetEntries); } } - + public void dispose() { stopAggroCoordinator(); - + lock.lock(); try { mobAggroEntries.clear(); @@ -367,14 +375,14 @@ public class MapleMonsterAggroCoordinator { } finally { lock.unlock(); } - + disposeLocks(); } - + private void disposeLocks() { LockCollector.getInstance().registerDisposeAction(() -> emptyLocks()); } - + private void emptyLocks() { lock = lock.dispose(); } diff --git a/src/main/java/server/life/MapleMonster.java b/src/main/java/server/life/MapleMonster.java index 048fb8cf2f..ef96976430 100644 --- a/src/main/java/server/life/MapleMonster.java +++ b/src/main/java/server/life/MapleMonster.java @@ -33,7 +33,7 @@ import net.server.audit.locks.MonitoredLockType; import net.server.audit.locks.MonitoredReentrantLock; import net.server.audit.locks.factory.MonitoredReentrantLockFactory; import net.server.channel.Channel; -import net.server.coordinator.world.MapleMonsterAggroCoordinator; +import net.server.coordinator.world.MonsterAggroCoordinator; import net.server.services.task.channel.MobAnimationService; import net.server.services.task.channel.MobClearSkillService; import net.server.services.task.channel.MobStatusService; @@ -1417,7 +1417,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { return map; } - public MapleMonsterAggroCoordinator getMapAggroCoordinator() { + public MonsterAggroCoordinator getMapAggroCoordinator() { return map.getAggroCoordinator(); } @@ -1927,7 +1927,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { } public void aggroAddPuppet(Character player) { - MapleMonsterAggroCoordinator mmac = map.getAggroCoordinator(); + MonsterAggroCoordinator mmac = map.getAggroCoordinator(); mmac.addPuppetAggro(player); aggroUpdatePuppetController(player); @@ -1938,7 +1938,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { } public void aggroRemovePuppet(Character player) { - MapleMonsterAggroCoordinator mmac = map.getAggroCoordinator(); + MonsterAggroCoordinator mmac = map.getAggroCoordinator(); mmac.removePuppetAggro(player.getId()); aggroUpdatePuppetController(null); @@ -1985,7 +1985,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { } if (newController == null || !isCharacterPuppetInVicinity(newController)) { - MapleMonsterAggroCoordinator mmac = map.getAggroCoordinator(); + MonsterAggroCoordinator mmac = map.getAggroCoordinator(); List puppetOwners = mmac.getPuppetAggroList(); List toRemovePuppets = new LinkedList<>(); @@ -2074,7 +2074,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { * */ public void aggroMonsterDamage(Character attacker, int damage) { - MapleMonsterAggroCoordinator mmac = this.getMapAggroCoordinator(); + MonsterAggroCoordinator mmac = this.getMapAggroCoordinator(); mmac.addAggroDamage(this, attacker.getId(), damage); Character chrController = this.getController(); // aggro based on DPS rather than first-come-first-served, now live after suggestions thanks to MedicOP, Thora, Vcoc diff --git a/src/main/java/server/maps/MapleMap.java b/src/main/java/server/maps/MapleMap.java index c6d7fbdd0b..c953bd1667 100644 --- a/src/main/java/server/maps/MapleMap.java +++ b/src/main/java/server/maps/MapleMap.java @@ -44,7 +44,7 @@ import net.server.audit.locks.factory.MonitoredReadLockFactory; import net.server.audit.locks.factory.MonitoredReentrantLockFactory; import net.server.audit.locks.factory.MonitoredWriteLockFactory; import net.server.channel.Channel; -import net.server.coordinator.world.MapleMonsterAggroCoordinator; +import net.server.coordinator.world.MonsterAggroCoordinator; import net.server.services.task.channel.FaceExpressionService; import net.server.services.task.channel.MobMistService; import net.server.services.task.channel.OverallService; @@ -130,7 +130,7 @@ public class MapleMap { private int fieldType; private int fieldLimit = 0; private int mobCapacity = -1; - private MapleMonsterAggroCoordinator aggroMonitor = null; // aggroMonitor activity in sync with itemMonitor + private MonsterAggroCoordinator aggroMonitor = null; // aggroMonitor activity in sync with itemMonitor private ScheduledFuture itemMonitor = null; private ScheduledFuture expireItemsTask = null; private ScheduledFuture mobSpawnLootTask = null; @@ -183,7 +183,7 @@ public class MapleMap { objectRLock = MonitoredReadLockFactory.createLock(objectLock); objectWLock = MonitoredWriteLockFactory.createLock(objectLock); - aggroMonitor = new MapleMonsterAggroCoordinator(); + aggroMonitor = new MonsterAggroCoordinator(); } public void setEventInstance(EventInstanceManager eim) { @@ -3052,7 +3052,7 @@ public class MapleMap { mapArea.setBounds(vrLeft, vrTop, vrRight - vrLeft, vrBottom - vrTop); } - public MapleMonsterAggroCoordinator getAggroCoordinator() { + public MonsterAggroCoordinator getAggroCoordinator() { return aggroMonitor; }