Rename and clean up MapleMonsterAggroCoordinator

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