Timer improvements.

Contributed by Liamxroy.
This commit is contained in:
MobiusDev 2018-04-02 11:47:45 +00:00
parent 5f6f504fde
commit 8b5f046d73
18 changed files with 522 additions and 258 deletions

View File

@ -16,8 +16,9 @@
*/ */
package com.l2jmobius.gameserver.instancemanager; package com.l2jmobius.gameserver.instancemanager;
import java.util.ArrayList;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.L2Npc;
@ -29,29 +30,52 @@ import com.l2jmobius.gameserver.model.events.timers.TimerHolder;
*/ */
public class TimersManager public class TimersManager
{ {
private final Map<Integer, Set<TimerHolder<?>>> _timers = new ConcurrentHashMap<>(); private final Map<Integer, List<TimerHolder<?>>> _timers = new ConcurrentHashMap<>();
public void registerTimer(TimerHolder<?> timer) public void registerTimer(TimerHolder<?> timer)
{ {
final L2Npc npc = timer.getNpc(); final L2Npc npc = timer.getNpc();
if (npc != null) if (npc != null)
{ {
_timers.computeIfAbsent(npc.getObjectId(), key -> ConcurrentHashMap.newKeySet()).add(timer); final List<TimerHolder<?>> npcTimers = _timers.computeIfAbsent(npc.getObjectId(), key -> new ArrayList<>());
synchronized (npcTimers)
{
npcTimers.add(timer);
}
} }
final L2PcInstance player = timer.getPlayer(); final L2PcInstance player = timer.getPlayer();
if (player != null) if (player != null)
{ {
_timers.computeIfAbsent(player.getObjectId(), key -> ConcurrentHashMap.newKeySet()).add(timer); final List<TimerHolder<?>> playerTimers = _timers.computeIfAbsent(player.getObjectId(), key -> new ArrayList<>());
synchronized (playerTimers)
{
playerTimers.add(timer);
}
} }
} }
public void cancelTimers(int objectId) public void cancelTimers(int objectId)
{ {
final Set<TimerHolder<?>> timers = _timers.remove(objectId); final List<TimerHolder<?>> timers = _timers.remove(objectId);
if (timers != null) if (timers != null)
{ {
timers.forEach(TimerHolder::cancelTimer); synchronized (timers)
{
timers.forEach(TimerHolder::cancelTimer);
}
}
}
public void unregisterTimer(int objectId, TimerHolder<?> timer)
{
final List<TimerHolder<?>> timers = _timers.get(objectId);
if (timers != null)
{
synchronized (timers)
{
timers.remove(timer);
}
} }
} }

View File

@ -16,10 +16,13 @@
*/ */
package com.l2jmobius.gameserver.model.events; package com.l2jmobius.gameserver.model.events;
import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import com.l2jmobius.gameserver.model.StatsSet; import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.L2Npc;
@ -52,13 +55,7 @@ public final class TimerExecutor<T>
public boolean addTimer(TimerHolder<T> holder) public boolean addTimer(TimerHolder<T> holder)
{ {
final Set<TimerHolder<T>> timers = _timers.computeIfAbsent(holder.getEvent(), key -> ConcurrentHashMap.newKeySet()); final Set<TimerHolder<T>> timers = _timers.computeIfAbsent(holder.getEvent(), key -> ConcurrentHashMap.newKeySet());
for (TimerHolder<T> timer : timers) removeAndCancelTimers(timers, holder::isEqual);
{
if (timer.equals(holder))
{
timer.cancelTimer();
}
}
return timers.add(holder); return timers.add(holder);
} }
@ -174,7 +171,7 @@ public final class TimerExecutor<T>
} }
// Remove the timer // Remove the timer
timers.removeIf(holder::equals); removeAndCancelTimers(timers, holder::isEqual);
// If there's no events inside that set remove it // If there's no events inside that set remove it
if (timers.isEmpty()) if (timers.isEmpty())
@ -265,16 +262,7 @@ public final class TimerExecutor<T>
return false; return false;
} }
final Iterator<TimerHolder<T>> holders = timers.iterator(); removeAndCancelTimers(timers, timer -> timer.isEqual(event, npc, player));
while (holders.hasNext())
{
final TimerHolder<T> holder = holders.next();
if (holder.isEqual(event, npc, player))
{
holders.remove();
return holder.cancelTimer();
}
}
return false; return false;
} }
@ -284,7 +272,38 @@ public final class TimerExecutor<T>
*/ */
public void cancelTimersOf(L2Npc npc) public void cancelTimersOf(L2Npc npc)
{ {
_timers.values().forEach(timers -> timers.stream().filter(holder -> holder.getNpc() == npc).forEach(TimerHolder::cancelTimer)); removeAndCancelTimers(timer -> timer.getNpc() == npc);
}
/**
* Removes and Cancels all timers matching the condition
* @param condition
*/
private void removeAndCancelTimers(Predicate<TimerHolder<T>> condition)
{
Objects.requireNonNull(condition);
final Collection<Set<TimerHolder<T>>> allTimers = _timers.values();
for (Set<TimerHolder<T>> timers : allTimers)
{
removeAndCancelTimers(timers, condition);
}
}
private void removeAndCancelTimers(Set<TimerHolder<T>> timers, Predicate<TimerHolder<T>> condition)
{
Objects.requireNonNull(timers);
Objects.requireNonNull(condition);
final Iterator<TimerHolder<T>> it = timers.iterator();
while (it.hasNext())
{
final TimerHolder<T> timer = it.next();
if (condition.test(timer))
{
it.remove();
timer.cancelTimer();
}
}
} }
/** /**

View File

@ -107,6 +107,16 @@ public class TimerHolder<T> implements Runnable
*/ */
public boolean cancelTimer() public boolean cancelTimer()
{ {
// Make sure to unregister this timer even if the task is already completed (TimerExecutor#onTimerPostExecute calls this method).
if (_npc != null)
{
TimersManager.getInstance().unregisterTimer(_npc.getObjectId(), this);
}
if (_player != null)
{
TimersManager.getInstance().unregisterTimer(_player.getObjectId(), this);
}
if (_task.isCancelled() || _task.isDone()) if (_task.isCancelled() || _task.isDone())
{ {
return false; return false;
@ -145,6 +155,15 @@ public class TimerHolder<T> implements Runnable
return _event.equals(event) && (_npc == npc) && (_player == player); return _event.equals(event) && (_npc == npc) && (_player == player);
} }
/**
* @param timer the other timer to be compared with.
* @return {@code true} of both of timers' npc, event and player match, {@code false} otherwise.
*/
public boolean isEqual(TimerHolder<T> timer)
{
return _event.equals(timer._event) && (_npc == timer._npc) && (_player == timer._player);
}
@Override @Override
public void run() public void run()
{ {
@ -155,24 +174,6 @@ public class TimerHolder<T> implements Runnable
_eventScript.onTimerEvent(this); _eventScript.onTimerEvent(this);
} }
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
if (!(obj instanceof TimerHolder))
{
return false;
}
@SuppressWarnings("unchecked")
final TimerHolder<T> holder = (TimerHolder<T>) obj;
return isEqual(holder._event, holder._npc, holder._player);
}
@Override @Override
public String toString() public String toString()
{ {

View File

@ -16,8 +16,9 @@
*/ */
package com.l2jmobius.gameserver.instancemanager; package com.l2jmobius.gameserver.instancemanager;
import java.util.ArrayList;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.L2Npc;
@ -29,29 +30,52 @@ import com.l2jmobius.gameserver.model.events.timers.TimerHolder;
*/ */
public class TimersManager public class TimersManager
{ {
private final Map<Integer, Set<TimerHolder<?>>> _timers = new ConcurrentHashMap<>(); private final Map<Integer, List<TimerHolder<?>>> _timers = new ConcurrentHashMap<>();
public void registerTimer(TimerHolder<?> timer) public void registerTimer(TimerHolder<?> timer)
{ {
final L2Npc npc = timer.getNpc(); final L2Npc npc = timer.getNpc();
if (npc != null) if (npc != null)
{ {
_timers.computeIfAbsent(npc.getObjectId(), key -> ConcurrentHashMap.newKeySet()).add(timer); final List<TimerHolder<?>> npcTimers = _timers.computeIfAbsent(npc.getObjectId(), key -> new ArrayList<>());
synchronized (npcTimers)
{
npcTimers.add(timer);
}
} }
final L2PcInstance player = timer.getPlayer(); final L2PcInstance player = timer.getPlayer();
if (player != null) if (player != null)
{ {
_timers.computeIfAbsent(player.getObjectId(), key -> ConcurrentHashMap.newKeySet()).add(timer); final List<TimerHolder<?>> playerTimers = _timers.computeIfAbsent(player.getObjectId(), key -> new ArrayList<>());
synchronized (playerTimers)
{
playerTimers.add(timer);
}
} }
} }
public void cancelTimers(int objectId) public void cancelTimers(int objectId)
{ {
final Set<TimerHolder<?>> timers = _timers.remove(objectId); final List<TimerHolder<?>> timers = _timers.remove(objectId);
if (timers != null) if (timers != null)
{ {
timers.forEach(TimerHolder::cancelTimer); synchronized (timers)
{
timers.forEach(TimerHolder::cancelTimer);
}
}
}
public void unregisterTimer(int objectId, TimerHolder<?> timer)
{
final List<TimerHolder<?>> timers = _timers.get(objectId);
if (timers != null)
{
synchronized (timers)
{
timers.remove(timer);
}
} }
} }

View File

@ -16,10 +16,13 @@
*/ */
package com.l2jmobius.gameserver.model.events; package com.l2jmobius.gameserver.model.events;
import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import com.l2jmobius.gameserver.model.StatsSet; import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.L2Npc;
@ -52,13 +55,7 @@ public final class TimerExecutor<T>
public boolean addTimer(TimerHolder<T> holder) public boolean addTimer(TimerHolder<T> holder)
{ {
final Set<TimerHolder<T>> timers = _timers.computeIfAbsent(holder.getEvent(), key -> ConcurrentHashMap.newKeySet()); final Set<TimerHolder<T>> timers = _timers.computeIfAbsent(holder.getEvent(), key -> ConcurrentHashMap.newKeySet());
for (TimerHolder<T> timer : timers) removeAndCancelTimers(timers, holder::isEqual);
{
if (timer.equals(holder))
{
timer.cancelTimer();
}
}
return timers.add(holder); return timers.add(holder);
} }
@ -174,7 +171,7 @@ public final class TimerExecutor<T>
} }
// Remove the timer // Remove the timer
timers.removeIf(holder::equals); removeAndCancelTimers(timers, holder::isEqual);
// If there's no events inside that set remove it // If there's no events inside that set remove it
if (timers.isEmpty()) if (timers.isEmpty())
@ -265,16 +262,7 @@ public final class TimerExecutor<T>
return false; return false;
} }
final Iterator<TimerHolder<T>> holders = timers.iterator(); removeAndCancelTimers(timers, timer -> timer.isEqual(event, npc, player));
while (holders.hasNext())
{
final TimerHolder<T> holder = holders.next();
if (holder.isEqual(event, npc, player))
{
holders.remove();
return holder.cancelTimer();
}
}
return false; return false;
} }
@ -284,7 +272,38 @@ public final class TimerExecutor<T>
*/ */
public void cancelTimersOf(L2Npc npc) public void cancelTimersOf(L2Npc npc)
{ {
_timers.values().forEach(timers -> timers.stream().filter(holder -> holder.getNpc() == npc).forEach(TimerHolder::cancelTimer)); removeAndCancelTimers(timer -> timer.getNpc() == npc);
}
/**
* Removes and Cancels all timers matching the condition
* @param condition
*/
private void removeAndCancelTimers(Predicate<TimerHolder<T>> condition)
{
Objects.requireNonNull(condition);
final Collection<Set<TimerHolder<T>>> allTimers = _timers.values();
for (Set<TimerHolder<T>> timers : allTimers)
{
removeAndCancelTimers(timers, condition);
}
}
private void removeAndCancelTimers(Set<TimerHolder<T>> timers, Predicate<TimerHolder<T>> condition)
{
Objects.requireNonNull(timers);
Objects.requireNonNull(condition);
final Iterator<TimerHolder<T>> it = timers.iterator();
while (it.hasNext())
{
final TimerHolder<T> timer = it.next();
if (condition.test(timer))
{
it.remove();
timer.cancelTimer();
}
}
} }
/** /**

View File

@ -107,6 +107,16 @@ public class TimerHolder<T> implements Runnable
*/ */
public boolean cancelTimer() public boolean cancelTimer()
{ {
// Make sure to unregister this timer even if the task is already completed (TimerExecutor#onTimerPostExecute calls this method).
if (_npc != null)
{
TimersManager.getInstance().unregisterTimer(_npc.getObjectId(), this);
}
if (_player != null)
{
TimersManager.getInstance().unregisterTimer(_player.getObjectId(), this);
}
if (_task.isCancelled() || _task.isDone()) if (_task.isCancelled() || _task.isDone())
{ {
return false; return false;
@ -145,6 +155,15 @@ public class TimerHolder<T> implements Runnable
return _event.equals(event) && (_npc == npc) && (_player == player); return _event.equals(event) && (_npc == npc) && (_player == player);
} }
/**
* @param timer the other timer to be compared with.
* @return {@code true} of both of timers' npc, event and player match, {@code false} otherwise.
*/
public boolean isEqual(TimerHolder<T> timer)
{
return _event.equals(timer._event) && (_npc == timer._npc) && (_player == timer._player);
}
@Override @Override
public void run() public void run()
{ {
@ -155,24 +174,6 @@ public class TimerHolder<T> implements Runnable
_eventScript.onTimerEvent(this); _eventScript.onTimerEvent(this);
} }
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
if (!(obj instanceof TimerHolder))
{
return false;
}
@SuppressWarnings("unchecked")
final TimerHolder<T> holder = (TimerHolder<T>) obj;
return isEqual(holder._event, holder._npc, holder._player);
}
@Override @Override
public String toString() public String toString()
{ {

View File

@ -16,8 +16,9 @@
*/ */
package com.l2jmobius.gameserver.instancemanager; package com.l2jmobius.gameserver.instancemanager;
import java.util.ArrayList;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.L2Npc;
@ -29,29 +30,52 @@ import com.l2jmobius.gameserver.model.events.timers.TimerHolder;
*/ */
public class TimersManager public class TimersManager
{ {
private final Map<Integer, Set<TimerHolder<?>>> _timers = new ConcurrentHashMap<>(); private final Map<Integer, List<TimerHolder<?>>> _timers = new ConcurrentHashMap<>();
public void registerTimer(TimerHolder<?> timer) public void registerTimer(TimerHolder<?> timer)
{ {
final L2Npc npc = timer.getNpc(); final L2Npc npc = timer.getNpc();
if (npc != null) if (npc != null)
{ {
_timers.computeIfAbsent(npc.getObjectId(), key -> ConcurrentHashMap.newKeySet()).add(timer); final List<TimerHolder<?>> npcTimers = _timers.computeIfAbsent(npc.getObjectId(), key -> new ArrayList<>());
synchronized (npcTimers)
{
npcTimers.add(timer);
}
} }
final L2PcInstance player = timer.getPlayer(); final L2PcInstance player = timer.getPlayer();
if (player != null) if (player != null)
{ {
_timers.computeIfAbsent(player.getObjectId(), key -> ConcurrentHashMap.newKeySet()).add(timer); final List<TimerHolder<?>> playerTimers = _timers.computeIfAbsent(player.getObjectId(), key -> new ArrayList<>());
synchronized (playerTimers)
{
playerTimers.add(timer);
}
} }
} }
public void cancelTimers(int objectId) public void cancelTimers(int objectId)
{ {
final Set<TimerHolder<?>> timers = _timers.remove(objectId); final List<TimerHolder<?>> timers = _timers.remove(objectId);
if (timers != null) if (timers != null)
{ {
timers.forEach(TimerHolder::cancelTimer); synchronized (timers)
{
timers.forEach(TimerHolder::cancelTimer);
}
}
}
public void unregisterTimer(int objectId, TimerHolder<?> timer)
{
final List<TimerHolder<?>> timers = _timers.get(objectId);
if (timers != null)
{
synchronized (timers)
{
timers.remove(timer);
}
} }
} }

View File

@ -16,10 +16,13 @@
*/ */
package com.l2jmobius.gameserver.model.events; package com.l2jmobius.gameserver.model.events;
import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import com.l2jmobius.gameserver.model.StatsSet; import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.L2Npc;
@ -52,13 +55,7 @@ public final class TimerExecutor<T>
public boolean addTimer(TimerHolder<T> holder) public boolean addTimer(TimerHolder<T> holder)
{ {
final Set<TimerHolder<T>> timers = _timers.computeIfAbsent(holder.getEvent(), key -> ConcurrentHashMap.newKeySet()); final Set<TimerHolder<T>> timers = _timers.computeIfAbsent(holder.getEvent(), key -> ConcurrentHashMap.newKeySet());
for (TimerHolder<T> timer : timers) removeAndCancelTimers(timers, holder::isEqual);
{
if (timer.equals(holder))
{
timer.cancelTimer();
}
}
return timers.add(holder); return timers.add(holder);
} }
@ -174,7 +171,7 @@ public final class TimerExecutor<T>
} }
// Remove the timer // Remove the timer
timers.removeIf(holder::equals); removeAndCancelTimers(timers, holder::isEqual);
// If there's no events inside that set remove it // If there's no events inside that set remove it
if (timers.isEmpty()) if (timers.isEmpty())
@ -265,16 +262,7 @@ public final class TimerExecutor<T>
return false; return false;
} }
final Iterator<TimerHolder<T>> holders = timers.iterator(); removeAndCancelTimers(timers, timer -> timer.isEqual(event, npc, player));
while (holders.hasNext())
{
final TimerHolder<T> holder = holders.next();
if (holder.isEqual(event, npc, player))
{
holders.remove();
return holder.cancelTimer();
}
}
return false; return false;
} }
@ -284,7 +272,38 @@ public final class TimerExecutor<T>
*/ */
public void cancelTimersOf(L2Npc npc) public void cancelTimersOf(L2Npc npc)
{ {
_timers.values().forEach(timers -> timers.stream().filter(holder -> holder.getNpc() == npc).forEach(TimerHolder::cancelTimer)); removeAndCancelTimers(timer -> timer.getNpc() == npc);
}
/**
* Removes and Cancels all timers matching the condition
* @param condition
*/
private void removeAndCancelTimers(Predicate<TimerHolder<T>> condition)
{
Objects.requireNonNull(condition);
final Collection<Set<TimerHolder<T>>> allTimers = _timers.values();
for (Set<TimerHolder<T>> timers : allTimers)
{
removeAndCancelTimers(timers, condition);
}
}
private void removeAndCancelTimers(Set<TimerHolder<T>> timers, Predicate<TimerHolder<T>> condition)
{
Objects.requireNonNull(timers);
Objects.requireNonNull(condition);
final Iterator<TimerHolder<T>> it = timers.iterator();
while (it.hasNext())
{
final TimerHolder<T> timer = it.next();
if (condition.test(timer))
{
it.remove();
timer.cancelTimer();
}
}
} }
/** /**

View File

@ -107,6 +107,16 @@ public class TimerHolder<T> implements Runnable
*/ */
public boolean cancelTimer() public boolean cancelTimer()
{ {
// Make sure to unregister this timer even if the task is already completed (TimerExecutor#onTimerPostExecute calls this method).
if (_npc != null)
{
TimersManager.getInstance().unregisterTimer(_npc.getObjectId(), this);
}
if (_player != null)
{
TimersManager.getInstance().unregisterTimer(_player.getObjectId(), this);
}
if (_task.isCancelled() || _task.isDone()) if (_task.isCancelled() || _task.isDone())
{ {
return false; return false;
@ -145,6 +155,15 @@ public class TimerHolder<T> implements Runnable
return _event.equals(event) && (_npc == npc) && (_player == player); return _event.equals(event) && (_npc == npc) && (_player == player);
} }
/**
* @param timer the other timer to be compared with.
* @return {@code true} of both of timers' npc, event and player match, {@code false} otherwise.
*/
public boolean isEqual(TimerHolder<T> timer)
{
return _event.equals(timer._event) && (_npc == timer._npc) && (_player == timer._player);
}
@Override @Override
public void run() public void run()
{ {
@ -155,24 +174,6 @@ public class TimerHolder<T> implements Runnable
_eventScript.onTimerEvent(this); _eventScript.onTimerEvent(this);
} }
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
if (!(obj instanceof TimerHolder))
{
return false;
}
@SuppressWarnings("unchecked")
final TimerHolder<T> holder = (TimerHolder<T>) obj;
return isEqual(holder._event, holder._npc, holder._player);
}
@Override @Override
public String toString() public String toString()
{ {

View File

@ -16,8 +16,9 @@
*/ */
package com.l2jmobius.gameserver.instancemanager; package com.l2jmobius.gameserver.instancemanager;
import java.util.ArrayList;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.L2Npc;
@ -29,29 +30,52 @@ import com.l2jmobius.gameserver.model.events.timers.TimerHolder;
*/ */
public class TimersManager public class TimersManager
{ {
private final Map<Integer, Set<TimerHolder<?>>> _timers = new ConcurrentHashMap<>(); private final Map<Integer, List<TimerHolder<?>>> _timers = new ConcurrentHashMap<>();
public void registerTimer(TimerHolder<?> timer) public void registerTimer(TimerHolder<?> timer)
{ {
final L2Npc npc = timer.getNpc(); final L2Npc npc = timer.getNpc();
if (npc != null) if (npc != null)
{ {
_timers.computeIfAbsent(npc.getObjectId(), key -> ConcurrentHashMap.newKeySet()).add(timer); final List<TimerHolder<?>> npcTimers = _timers.computeIfAbsent(npc.getObjectId(), key -> new ArrayList<>());
synchronized (npcTimers)
{
npcTimers.add(timer);
}
} }
final L2PcInstance player = timer.getPlayer(); final L2PcInstance player = timer.getPlayer();
if (player != null) if (player != null)
{ {
_timers.computeIfAbsent(player.getObjectId(), key -> ConcurrentHashMap.newKeySet()).add(timer); final List<TimerHolder<?>> playerTimers = _timers.computeIfAbsent(player.getObjectId(), key -> new ArrayList<>());
synchronized (playerTimers)
{
playerTimers.add(timer);
}
} }
} }
public void cancelTimers(int objectId) public void cancelTimers(int objectId)
{ {
final Set<TimerHolder<?>> timers = _timers.remove(objectId); final List<TimerHolder<?>> timers = _timers.remove(objectId);
if (timers != null) if (timers != null)
{ {
timers.forEach(TimerHolder::cancelTimer); synchronized (timers)
{
timers.forEach(TimerHolder::cancelTimer);
}
}
}
public void unregisterTimer(int objectId, TimerHolder<?> timer)
{
final List<TimerHolder<?>> timers = _timers.get(objectId);
if (timers != null)
{
synchronized (timers)
{
timers.remove(timer);
}
} }
} }

View File

@ -16,10 +16,13 @@
*/ */
package com.l2jmobius.gameserver.model.events; package com.l2jmobius.gameserver.model.events;
import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import com.l2jmobius.gameserver.model.StatsSet; import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.L2Npc;
@ -52,13 +55,7 @@ public final class TimerExecutor<T>
public boolean addTimer(TimerHolder<T> holder) public boolean addTimer(TimerHolder<T> holder)
{ {
final Set<TimerHolder<T>> timers = _timers.computeIfAbsent(holder.getEvent(), key -> ConcurrentHashMap.newKeySet()); final Set<TimerHolder<T>> timers = _timers.computeIfAbsent(holder.getEvent(), key -> ConcurrentHashMap.newKeySet());
for (TimerHolder<T> timer : timers) removeAndCancelTimers(timers, holder::isEqual);
{
if (timer.equals(holder))
{
timer.cancelTimer();
}
}
return timers.add(holder); return timers.add(holder);
} }
@ -174,7 +171,7 @@ public final class TimerExecutor<T>
} }
// Remove the timer // Remove the timer
timers.removeIf(holder::equals); removeAndCancelTimers(timers, holder::isEqual);
// If there's no events inside that set remove it // If there's no events inside that set remove it
if (timers.isEmpty()) if (timers.isEmpty())
@ -265,16 +262,7 @@ public final class TimerExecutor<T>
return false; return false;
} }
final Iterator<TimerHolder<T>> holders = timers.iterator(); removeAndCancelTimers(timers, timer -> timer.isEqual(event, npc, player));
while (holders.hasNext())
{
final TimerHolder<T> holder = holders.next();
if (holder.isEqual(event, npc, player))
{
holders.remove();
return holder.cancelTimer();
}
}
return false; return false;
} }
@ -284,7 +272,38 @@ public final class TimerExecutor<T>
*/ */
public void cancelTimersOf(L2Npc npc) public void cancelTimersOf(L2Npc npc)
{ {
_timers.values().forEach(timers -> timers.stream().filter(holder -> holder.getNpc() == npc).forEach(TimerHolder::cancelTimer)); removeAndCancelTimers(timer -> timer.getNpc() == npc);
}
/**
* Removes and Cancels all timers matching the condition
* @param condition
*/
private void removeAndCancelTimers(Predicate<TimerHolder<T>> condition)
{
Objects.requireNonNull(condition);
final Collection<Set<TimerHolder<T>>> allTimers = _timers.values();
for (Set<TimerHolder<T>> timers : allTimers)
{
removeAndCancelTimers(timers, condition);
}
}
private void removeAndCancelTimers(Set<TimerHolder<T>> timers, Predicate<TimerHolder<T>> condition)
{
Objects.requireNonNull(timers);
Objects.requireNonNull(condition);
final Iterator<TimerHolder<T>> it = timers.iterator();
while (it.hasNext())
{
final TimerHolder<T> timer = it.next();
if (condition.test(timer))
{
it.remove();
timer.cancelTimer();
}
}
} }
/** /**

View File

@ -107,6 +107,16 @@ public class TimerHolder<T> implements Runnable
*/ */
public boolean cancelTimer() public boolean cancelTimer()
{ {
// Make sure to unregister this timer even if the task is already completed (TimerExecutor#onTimerPostExecute calls this method).
if (_npc != null)
{
TimersManager.getInstance().unregisterTimer(_npc.getObjectId(), this);
}
if (_player != null)
{
TimersManager.getInstance().unregisterTimer(_player.getObjectId(), this);
}
if (_task.isCancelled() || _task.isDone()) if (_task.isCancelled() || _task.isDone())
{ {
return false; return false;
@ -145,6 +155,15 @@ public class TimerHolder<T> implements Runnable
return _event.equals(event) && (_npc == npc) && (_player == player); return _event.equals(event) && (_npc == npc) && (_player == player);
} }
/**
* @param timer the other timer to be compared with.
* @return {@code true} of both of timers' npc, event and player match, {@code false} otherwise.
*/
public boolean isEqual(TimerHolder<T> timer)
{
return _event.equals(timer._event) && (_npc == timer._npc) && (_player == timer._player);
}
@Override @Override
public void run() public void run()
{ {
@ -155,24 +174,6 @@ public class TimerHolder<T> implements Runnable
_eventScript.onTimerEvent(this); _eventScript.onTimerEvent(this);
} }
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
if (!(obj instanceof TimerHolder))
{
return false;
}
@SuppressWarnings("unchecked")
final TimerHolder<T> holder = (TimerHolder<T>) obj;
return isEqual(holder._event, holder._npc, holder._player);
}
@Override @Override
public String toString() public String toString()
{ {

View File

@ -16,8 +16,9 @@
*/ */
package com.l2jmobius.gameserver.instancemanager; package com.l2jmobius.gameserver.instancemanager;
import java.util.ArrayList;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.L2Npc;
@ -29,29 +30,52 @@ import com.l2jmobius.gameserver.model.events.timers.TimerHolder;
*/ */
public class TimersManager public class TimersManager
{ {
private final Map<Integer, Set<TimerHolder<?>>> _timers = new ConcurrentHashMap<>(); private final Map<Integer, List<TimerHolder<?>>> _timers = new ConcurrentHashMap<>();
public void registerTimer(TimerHolder<?> timer) public void registerTimer(TimerHolder<?> timer)
{ {
final L2Npc npc = timer.getNpc(); final L2Npc npc = timer.getNpc();
if (npc != null) if (npc != null)
{ {
_timers.computeIfAbsent(npc.getObjectId(), key -> ConcurrentHashMap.newKeySet()).add(timer); final List<TimerHolder<?>> npcTimers = _timers.computeIfAbsent(npc.getObjectId(), key -> new ArrayList<>());
synchronized (npcTimers)
{
npcTimers.add(timer);
}
} }
final L2PcInstance player = timer.getPlayer(); final L2PcInstance player = timer.getPlayer();
if (player != null) if (player != null)
{ {
_timers.computeIfAbsent(player.getObjectId(), key -> ConcurrentHashMap.newKeySet()).add(timer); final List<TimerHolder<?>> playerTimers = _timers.computeIfAbsent(player.getObjectId(), key -> new ArrayList<>());
synchronized (playerTimers)
{
playerTimers.add(timer);
}
} }
} }
public void cancelTimers(int objectId) public void cancelTimers(int objectId)
{ {
final Set<TimerHolder<?>> timers = _timers.remove(objectId); final List<TimerHolder<?>> timers = _timers.remove(objectId);
if (timers != null) if (timers != null)
{ {
timers.forEach(TimerHolder::cancelTimer); synchronized (timers)
{
timers.forEach(TimerHolder::cancelTimer);
}
}
}
public void unregisterTimer(int objectId, TimerHolder<?> timer)
{
final List<TimerHolder<?>> timers = _timers.get(objectId);
if (timers != null)
{
synchronized (timers)
{
timers.remove(timer);
}
} }
} }

View File

@ -16,10 +16,13 @@
*/ */
package com.l2jmobius.gameserver.model.events; package com.l2jmobius.gameserver.model.events;
import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import com.l2jmobius.gameserver.model.StatsSet; import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.L2Npc;
@ -52,13 +55,7 @@ public final class TimerExecutor<T>
public boolean addTimer(TimerHolder<T> holder) public boolean addTimer(TimerHolder<T> holder)
{ {
final Set<TimerHolder<T>> timers = _timers.computeIfAbsent(holder.getEvent(), key -> ConcurrentHashMap.newKeySet()); final Set<TimerHolder<T>> timers = _timers.computeIfAbsent(holder.getEvent(), key -> ConcurrentHashMap.newKeySet());
for (TimerHolder<T> timer : timers) removeAndCancelTimers(timers, holder::isEqual);
{
if (timer.equals(holder))
{
timer.cancelTimer();
}
}
return timers.add(holder); return timers.add(holder);
} }
@ -174,7 +171,7 @@ public final class TimerExecutor<T>
} }
// Remove the timer // Remove the timer
timers.removeIf(holder::equals); removeAndCancelTimers(timers, holder::isEqual);
// If there's no events inside that set remove it // If there's no events inside that set remove it
if (timers.isEmpty()) if (timers.isEmpty())
@ -265,16 +262,7 @@ public final class TimerExecutor<T>
return false; return false;
} }
final Iterator<TimerHolder<T>> holders = timers.iterator(); removeAndCancelTimers(timers, timer -> timer.isEqual(event, npc, player));
while (holders.hasNext())
{
final TimerHolder<T> holder = holders.next();
if (holder.isEqual(event, npc, player))
{
holders.remove();
return holder.cancelTimer();
}
}
return false; return false;
} }
@ -284,7 +272,38 @@ public final class TimerExecutor<T>
*/ */
public void cancelTimersOf(L2Npc npc) public void cancelTimersOf(L2Npc npc)
{ {
_timers.values().forEach(timers -> timers.stream().filter(holder -> holder.getNpc() == npc).forEach(TimerHolder::cancelTimer)); removeAndCancelTimers(timer -> timer.getNpc() == npc);
}
/**
* Removes and Cancels all timers matching the condition
* @param condition
*/
private void removeAndCancelTimers(Predicate<TimerHolder<T>> condition)
{
Objects.requireNonNull(condition);
final Collection<Set<TimerHolder<T>>> allTimers = _timers.values();
for (Set<TimerHolder<T>> timers : allTimers)
{
removeAndCancelTimers(timers, condition);
}
}
private void removeAndCancelTimers(Set<TimerHolder<T>> timers, Predicate<TimerHolder<T>> condition)
{
Objects.requireNonNull(timers);
Objects.requireNonNull(condition);
final Iterator<TimerHolder<T>> it = timers.iterator();
while (it.hasNext())
{
final TimerHolder<T> timer = it.next();
if (condition.test(timer))
{
it.remove();
timer.cancelTimer();
}
}
} }
/** /**

View File

@ -107,6 +107,16 @@ public class TimerHolder<T> implements Runnable
*/ */
public boolean cancelTimer() public boolean cancelTimer()
{ {
// Make sure to unregister this timer even if the task is already completed (TimerExecutor#onTimerPostExecute calls this method).
if (_npc != null)
{
TimersManager.getInstance().unregisterTimer(_npc.getObjectId(), this);
}
if (_player != null)
{
TimersManager.getInstance().unregisterTimer(_player.getObjectId(), this);
}
if (_task.isCancelled() || _task.isDone()) if (_task.isCancelled() || _task.isDone())
{ {
return false; return false;
@ -145,6 +155,15 @@ public class TimerHolder<T> implements Runnable
return _event.equals(event) && (_npc == npc) && (_player == player); return _event.equals(event) && (_npc == npc) && (_player == player);
} }
/**
* @param timer the other timer to be compared with.
* @return {@code true} of both of timers' npc, event and player match, {@code false} otherwise.
*/
public boolean isEqual(TimerHolder<T> timer)
{
return _event.equals(timer._event) && (_npc == timer._npc) && (_player == timer._player);
}
@Override @Override
public void run() public void run()
{ {
@ -155,24 +174,6 @@ public class TimerHolder<T> implements Runnable
_eventScript.onTimerEvent(this); _eventScript.onTimerEvent(this);
} }
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
if (!(obj instanceof TimerHolder))
{
return false;
}
@SuppressWarnings("unchecked")
final TimerHolder<T> holder = (TimerHolder<T>) obj;
return isEqual(holder._event, holder._npc, holder._player);
}
@Override @Override
public String toString() public String toString()
{ {

View File

@ -16,8 +16,9 @@
*/ */
package com.l2jmobius.gameserver.instancemanager; package com.l2jmobius.gameserver.instancemanager;
import java.util.ArrayList;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.L2Npc;
@ -29,29 +30,52 @@ import com.l2jmobius.gameserver.model.events.timers.TimerHolder;
*/ */
public class TimersManager public class TimersManager
{ {
private final Map<Integer, Set<TimerHolder<?>>> _timers = new ConcurrentHashMap<>(); private final Map<Integer, List<TimerHolder<?>>> _timers = new ConcurrentHashMap<>();
public void registerTimer(TimerHolder<?> timer) public void registerTimer(TimerHolder<?> timer)
{ {
final L2Npc npc = timer.getNpc(); final L2Npc npc = timer.getNpc();
if (npc != null) if (npc != null)
{ {
_timers.computeIfAbsent(npc.getObjectId(), key -> ConcurrentHashMap.newKeySet()).add(timer); final List<TimerHolder<?>> npcTimers = _timers.computeIfAbsent(npc.getObjectId(), key -> new ArrayList<>());
synchronized (npcTimers)
{
npcTimers.add(timer);
}
} }
final L2PcInstance player = timer.getPlayer(); final L2PcInstance player = timer.getPlayer();
if (player != null) if (player != null)
{ {
_timers.computeIfAbsent(player.getObjectId(), key -> ConcurrentHashMap.newKeySet()).add(timer); final List<TimerHolder<?>> playerTimers = _timers.computeIfAbsent(player.getObjectId(), key -> new ArrayList<>());
synchronized (playerTimers)
{
playerTimers.add(timer);
}
} }
} }
public void cancelTimers(int objectId) public void cancelTimers(int objectId)
{ {
final Set<TimerHolder<?>> timers = _timers.remove(objectId); final List<TimerHolder<?>> timers = _timers.remove(objectId);
if (timers != null) if (timers != null)
{ {
timers.forEach(TimerHolder::cancelTimer); synchronized (timers)
{
timers.forEach(TimerHolder::cancelTimer);
}
}
}
public void unregisterTimer(int objectId, TimerHolder<?> timer)
{
final List<TimerHolder<?>> timers = _timers.get(objectId);
if (timers != null)
{
synchronized (timers)
{
timers.remove(timer);
}
} }
} }

View File

@ -16,10 +16,13 @@
*/ */
package com.l2jmobius.gameserver.model.events; package com.l2jmobius.gameserver.model.events;
import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import com.l2jmobius.gameserver.model.StatsSet; import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.L2Npc;
@ -52,13 +55,7 @@ public final class TimerExecutor<T>
public boolean addTimer(TimerHolder<T> holder) public boolean addTimer(TimerHolder<T> holder)
{ {
final Set<TimerHolder<T>> timers = _timers.computeIfAbsent(holder.getEvent(), key -> ConcurrentHashMap.newKeySet()); final Set<TimerHolder<T>> timers = _timers.computeIfAbsent(holder.getEvent(), key -> ConcurrentHashMap.newKeySet());
for (TimerHolder<T> timer : timers) removeAndCancelTimers(timers, holder::isEqual);
{
if (timer.equals(holder))
{
timer.cancelTimer();
}
}
return timers.add(holder); return timers.add(holder);
} }
@ -174,7 +171,7 @@ public final class TimerExecutor<T>
} }
// Remove the timer // Remove the timer
timers.removeIf(holder::equals); removeAndCancelTimers(timers, holder::isEqual);
// If there's no events inside that set remove it // If there's no events inside that set remove it
if (timers.isEmpty()) if (timers.isEmpty())
@ -265,16 +262,7 @@ public final class TimerExecutor<T>
return false; return false;
} }
final Iterator<TimerHolder<T>> holders = timers.iterator(); removeAndCancelTimers(timers, timer -> timer.isEqual(event, npc, player));
while (holders.hasNext())
{
final TimerHolder<T> holder = holders.next();
if (holder.isEqual(event, npc, player))
{
holders.remove();
return holder.cancelTimer();
}
}
return false; return false;
} }
@ -284,7 +272,38 @@ public final class TimerExecutor<T>
*/ */
public void cancelTimersOf(L2Npc npc) public void cancelTimersOf(L2Npc npc)
{ {
_timers.values().forEach(timers -> timers.stream().filter(holder -> holder.getNpc() == npc).forEach(TimerHolder::cancelTimer)); removeAndCancelTimers(timer -> timer.getNpc() == npc);
}
/**
* Removes and Cancels all timers matching the condition
* @param condition
*/
private void removeAndCancelTimers(Predicate<TimerHolder<T>> condition)
{
Objects.requireNonNull(condition);
final Collection<Set<TimerHolder<T>>> allTimers = _timers.values();
for (Set<TimerHolder<T>> timers : allTimers)
{
removeAndCancelTimers(timers, condition);
}
}
private void removeAndCancelTimers(Set<TimerHolder<T>> timers, Predicate<TimerHolder<T>> condition)
{
Objects.requireNonNull(timers);
Objects.requireNonNull(condition);
final Iterator<TimerHolder<T>> it = timers.iterator();
while (it.hasNext())
{
final TimerHolder<T> timer = it.next();
if (condition.test(timer))
{
it.remove();
timer.cancelTimer();
}
}
} }
/** /**

View File

@ -107,6 +107,16 @@ public class TimerHolder<T> implements Runnable
*/ */
public boolean cancelTimer() public boolean cancelTimer()
{ {
// Make sure to unregister this timer even if the task is already completed (TimerExecutor#onTimerPostExecute calls this method).
if (_npc != null)
{
TimersManager.getInstance().unregisterTimer(_npc.getObjectId(), this);
}
if (_player != null)
{
TimersManager.getInstance().unregisterTimer(_player.getObjectId(), this);
}
if (_task.isCancelled() || _task.isDone()) if (_task.isCancelled() || _task.isDone())
{ {
return false; return false;
@ -145,6 +155,15 @@ public class TimerHolder<T> implements Runnable
return _event.equals(event) && (_npc == npc) && (_player == player); return _event.equals(event) && (_npc == npc) && (_player == player);
} }
/**
* @param timer the other timer to be compared with.
* @return {@code true} of both of timers' npc, event and player match, {@code false} otherwise.
*/
public boolean isEqual(TimerHolder<T> timer)
{
return _event.equals(timer._event) && (_npc == timer._npc) && (_player == timer._player);
}
@Override @Override
public void run() public void run()
{ {
@ -155,24 +174,6 @@ public class TimerHolder<T> implements Runnable
_eventScript.onTimerEvent(this); _eventScript.onTimerEvent(this);
} }
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
if (!(obj instanceof TimerHolder))
{
return false;
}
@SuppressWarnings("unchecked")
final TimerHolder<T> holder = (TimerHolder<T>) obj;
return isEqual(holder._event, holder._npc, holder._player);
}
@Override @Override
public String toString() public String toString()
{ {