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;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import com.l2jmobius.gameserver.model.actor.L2Npc;
@ -29,31 +30,54 @@ import com.l2jmobius.gameserver.model.events.timers.TimerHolder;
*/
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)
{
final L2Npc npc = timer.getNpc();
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();
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)
{
final Set<TimerHolder<?>> timers = _timers.remove(objectId);
final List<TimerHolder<?>> timers = _timers.remove(objectId);
if (timers != null)
{
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);
}
}
}
public static TimersManager getInstance()
{

View File

@ -16,10 +16,13 @@
*/
package com.l2jmobius.gameserver.model.events;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Npc;
@ -52,13 +55,7 @@ public final class TimerExecutor<T>
public boolean addTimer(TimerHolder<T> holder)
{
final Set<TimerHolder<T>> timers = _timers.computeIfAbsent(holder.getEvent(), key -> ConcurrentHashMap.newKeySet());
for (TimerHolder<T> timer : timers)
{
if (timer.equals(holder))
{
timer.cancelTimer();
}
}
removeAndCancelTimers(timers, holder::isEqual);
return timers.add(holder);
}
@ -174,7 +171,7 @@ public final class TimerExecutor<T>
}
// Remove the timer
timers.removeIf(holder::equals);
removeAndCancelTimers(timers, holder::isEqual);
// If there's no events inside that set remove it
if (timers.isEmpty())
@ -265,16 +262,7 @@ public final class TimerExecutor<T>
return false;
}
final Iterator<TimerHolder<T>> holders = timers.iterator();
while (holders.hasNext())
{
final TimerHolder<T> holder = holders.next();
if (holder.isEqual(event, npc, player))
{
holders.remove();
return holder.cancelTimer();
}
}
removeAndCancelTimers(timers, timer -> timer.isEqual(event, npc, player));
return false;
}
@ -284,7 +272,38 @@ public final class TimerExecutor<T>
*/
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()
{
// 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())
{
return false;
@ -145,6 +155,15 @@ public class TimerHolder<T> implements Runnable
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
public void run()
{
@ -155,24 +174,6 @@ public class TimerHolder<T> implements Runnable
_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
public String toString()
{

View File

@ -16,8 +16,9 @@
*/
package com.l2jmobius.gameserver.instancemanager;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import com.l2jmobius.gameserver.model.actor.L2Npc;
@ -29,31 +30,54 @@ import com.l2jmobius.gameserver.model.events.timers.TimerHolder;
*/
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)
{
final L2Npc npc = timer.getNpc();
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();
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)
{
final Set<TimerHolder<?>> timers = _timers.remove(objectId);
final List<TimerHolder<?>> timers = _timers.remove(objectId);
if (timers != null)
{
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);
}
}
}
public static TimersManager getInstance()
{

View File

@ -16,10 +16,13 @@
*/
package com.l2jmobius.gameserver.model.events;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Npc;
@ -52,13 +55,7 @@ public final class TimerExecutor<T>
public boolean addTimer(TimerHolder<T> holder)
{
final Set<TimerHolder<T>> timers = _timers.computeIfAbsent(holder.getEvent(), key -> ConcurrentHashMap.newKeySet());
for (TimerHolder<T> timer : timers)
{
if (timer.equals(holder))
{
timer.cancelTimer();
}
}
removeAndCancelTimers(timers, holder::isEqual);
return timers.add(holder);
}
@ -174,7 +171,7 @@ public final class TimerExecutor<T>
}
// Remove the timer
timers.removeIf(holder::equals);
removeAndCancelTimers(timers, holder::isEqual);
// If there's no events inside that set remove it
if (timers.isEmpty())
@ -265,16 +262,7 @@ public final class TimerExecutor<T>
return false;
}
final Iterator<TimerHolder<T>> holders = timers.iterator();
while (holders.hasNext())
{
final TimerHolder<T> holder = holders.next();
if (holder.isEqual(event, npc, player))
{
holders.remove();
return holder.cancelTimer();
}
}
removeAndCancelTimers(timers, timer -> timer.isEqual(event, npc, player));
return false;
}
@ -284,7 +272,38 @@ public final class TimerExecutor<T>
*/
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()
{
// 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())
{
return false;
@ -145,6 +155,15 @@ public class TimerHolder<T> implements Runnable
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
public void run()
{
@ -155,24 +174,6 @@ public class TimerHolder<T> implements Runnable
_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
public String toString()
{

View File

@ -16,8 +16,9 @@
*/
package com.l2jmobius.gameserver.instancemanager;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import com.l2jmobius.gameserver.model.actor.L2Npc;
@ -29,31 +30,54 @@ import com.l2jmobius.gameserver.model.events.timers.TimerHolder;
*/
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)
{
final L2Npc npc = timer.getNpc();
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();
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)
{
final Set<TimerHolder<?>> timers = _timers.remove(objectId);
final List<TimerHolder<?>> timers = _timers.remove(objectId);
if (timers != null)
{
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);
}
}
}
public static TimersManager getInstance()
{

View File

@ -16,10 +16,13 @@
*/
package com.l2jmobius.gameserver.model.events;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Npc;
@ -52,13 +55,7 @@ public final class TimerExecutor<T>
public boolean addTimer(TimerHolder<T> holder)
{
final Set<TimerHolder<T>> timers = _timers.computeIfAbsent(holder.getEvent(), key -> ConcurrentHashMap.newKeySet());
for (TimerHolder<T> timer : timers)
{
if (timer.equals(holder))
{
timer.cancelTimer();
}
}
removeAndCancelTimers(timers, holder::isEqual);
return timers.add(holder);
}
@ -174,7 +171,7 @@ public final class TimerExecutor<T>
}
// Remove the timer
timers.removeIf(holder::equals);
removeAndCancelTimers(timers, holder::isEqual);
// If there's no events inside that set remove it
if (timers.isEmpty())
@ -265,16 +262,7 @@ public final class TimerExecutor<T>
return false;
}
final Iterator<TimerHolder<T>> holders = timers.iterator();
while (holders.hasNext())
{
final TimerHolder<T> holder = holders.next();
if (holder.isEqual(event, npc, player))
{
holders.remove();
return holder.cancelTimer();
}
}
removeAndCancelTimers(timers, timer -> timer.isEqual(event, npc, player));
return false;
}
@ -284,7 +272,38 @@ public final class TimerExecutor<T>
*/
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()
{
// 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())
{
return false;
@ -145,6 +155,15 @@ public class TimerHolder<T> implements Runnable
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
public void run()
{
@ -155,24 +174,6 @@ public class TimerHolder<T> implements Runnable
_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
public String toString()
{

View File

@ -16,8 +16,9 @@
*/
package com.l2jmobius.gameserver.instancemanager;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import com.l2jmobius.gameserver.model.actor.L2Npc;
@ -29,31 +30,54 @@ import com.l2jmobius.gameserver.model.events.timers.TimerHolder;
*/
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)
{
final L2Npc npc = timer.getNpc();
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();
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)
{
final Set<TimerHolder<?>> timers = _timers.remove(objectId);
final List<TimerHolder<?>> timers = _timers.remove(objectId);
if (timers != null)
{
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);
}
}
}
public static TimersManager getInstance()
{

View File

@ -16,10 +16,13 @@
*/
package com.l2jmobius.gameserver.model.events;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Npc;
@ -52,13 +55,7 @@ public final class TimerExecutor<T>
public boolean addTimer(TimerHolder<T> holder)
{
final Set<TimerHolder<T>> timers = _timers.computeIfAbsent(holder.getEvent(), key -> ConcurrentHashMap.newKeySet());
for (TimerHolder<T> timer : timers)
{
if (timer.equals(holder))
{
timer.cancelTimer();
}
}
removeAndCancelTimers(timers, holder::isEqual);
return timers.add(holder);
}
@ -174,7 +171,7 @@ public final class TimerExecutor<T>
}
// Remove the timer
timers.removeIf(holder::equals);
removeAndCancelTimers(timers, holder::isEqual);
// If there's no events inside that set remove it
if (timers.isEmpty())
@ -265,16 +262,7 @@ public final class TimerExecutor<T>
return false;
}
final Iterator<TimerHolder<T>> holders = timers.iterator();
while (holders.hasNext())
{
final TimerHolder<T> holder = holders.next();
if (holder.isEqual(event, npc, player))
{
holders.remove();
return holder.cancelTimer();
}
}
removeAndCancelTimers(timers, timer -> timer.isEqual(event, npc, player));
return false;
}
@ -284,7 +272,38 @@ public final class TimerExecutor<T>
*/
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()
{
// 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())
{
return false;
@ -145,6 +155,15 @@ public class TimerHolder<T> implements Runnable
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
public void run()
{
@ -155,24 +174,6 @@ public class TimerHolder<T> implements Runnable
_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
public String toString()
{

View File

@ -16,8 +16,9 @@
*/
package com.l2jmobius.gameserver.instancemanager;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import com.l2jmobius.gameserver.model.actor.L2Npc;
@ -29,31 +30,54 @@ import com.l2jmobius.gameserver.model.events.timers.TimerHolder;
*/
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)
{
final L2Npc npc = timer.getNpc();
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();
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)
{
final Set<TimerHolder<?>> timers = _timers.remove(objectId);
final List<TimerHolder<?>> timers = _timers.remove(objectId);
if (timers != null)
{
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);
}
}
}
public static TimersManager getInstance()
{

View File

@ -16,10 +16,13 @@
*/
package com.l2jmobius.gameserver.model.events;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Npc;
@ -52,13 +55,7 @@ public final class TimerExecutor<T>
public boolean addTimer(TimerHolder<T> holder)
{
final Set<TimerHolder<T>> timers = _timers.computeIfAbsent(holder.getEvent(), key -> ConcurrentHashMap.newKeySet());
for (TimerHolder<T> timer : timers)
{
if (timer.equals(holder))
{
timer.cancelTimer();
}
}
removeAndCancelTimers(timers, holder::isEqual);
return timers.add(holder);
}
@ -174,7 +171,7 @@ public final class TimerExecutor<T>
}
// Remove the timer
timers.removeIf(holder::equals);
removeAndCancelTimers(timers, holder::isEqual);
// If there's no events inside that set remove it
if (timers.isEmpty())
@ -265,16 +262,7 @@ public final class TimerExecutor<T>
return false;
}
final Iterator<TimerHolder<T>> holders = timers.iterator();
while (holders.hasNext())
{
final TimerHolder<T> holder = holders.next();
if (holder.isEqual(event, npc, player))
{
holders.remove();
return holder.cancelTimer();
}
}
removeAndCancelTimers(timers, timer -> timer.isEqual(event, npc, player));
return false;
}
@ -284,7 +272,38 @@ public final class TimerExecutor<T>
*/
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()
{
// 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())
{
return false;
@ -145,6 +155,15 @@ public class TimerHolder<T> implements Runnable
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
public void run()
{
@ -155,24 +174,6 @@ public class TimerHolder<T> implements Runnable
_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
public String toString()
{

View File

@ -16,8 +16,9 @@
*/
package com.l2jmobius.gameserver.instancemanager;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import com.l2jmobius.gameserver.model.actor.L2Npc;
@ -29,31 +30,54 @@ import com.l2jmobius.gameserver.model.events.timers.TimerHolder;
*/
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)
{
final L2Npc npc = timer.getNpc();
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();
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)
{
final Set<TimerHolder<?>> timers = _timers.remove(objectId);
final List<TimerHolder<?>> timers = _timers.remove(objectId);
if (timers != null)
{
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);
}
}
}
public static TimersManager getInstance()
{

View File

@ -16,10 +16,13 @@
*/
package com.l2jmobius.gameserver.model.events;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Npc;
@ -52,13 +55,7 @@ public final class TimerExecutor<T>
public boolean addTimer(TimerHolder<T> holder)
{
final Set<TimerHolder<T>> timers = _timers.computeIfAbsent(holder.getEvent(), key -> ConcurrentHashMap.newKeySet());
for (TimerHolder<T> timer : timers)
{
if (timer.equals(holder))
{
timer.cancelTimer();
}
}
removeAndCancelTimers(timers, holder::isEqual);
return timers.add(holder);
}
@ -174,7 +171,7 @@ public final class TimerExecutor<T>
}
// Remove the timer
timers.removeIf(holder::equals);
removeAndCancelTimers(timers, holder::isEqual);
// If there's no events inside that set remove it
if (timers.isEmpty())
@ -265,16 +262,7 @@ public final class TimerExecutor<T>
return false;
}
final Iterator<TimerHolder<T>> holders = timers.iterator();
while (holders.hasNext())
{
final TimerHolder<T> holder = holders.next();
if (holder.isEqual(event, npc, player))
{
holders.remove();
return holder.cancelTimer();
}
}
removeAndCancelTimers(timers, timer -> timer.isEqual(event, npc, player));
return false;
}
@ -284,7 +272,38 @@ public final class TimerExecutor<T>
*/
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()
{
// 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())
{
return false;
@ -145,6 +155,15 @@ public class TimerHolder<T> implements Runnable
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
public void run()
{
@ -155,24 +174,6 @@ public class TimerHolder<T> implements Runnable
_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
public String toString()
{