/* * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ package com.l2jfree.gameserver.taskmanager; import java.util.ArrayList; import com.l2jfree.gameserver.GameTimeController; import com.l2jfree.gameserver.ai.CtrlEvent; import com.l2jfree.gameserver.model.actor.L2Character; import com.l2jfree.gameserver.threadmanager.FIFOSimpleExecutableQueue; import com.l2jfree.util.L2Collections; import com.l2jfree.util.L2FastSet; import com.l2jfree.util.concurrent.RunnableStatsManager; /** * @author NB4L1 */ public final class MovementController extends AbstractPeriodicTaskManager { private static final class SingletonHolder { private static final MovementController INSTANCE = new MovementController(); } public static MovementController getInstance() { return SingletonHolder.INSTANCE; } private final L2FastSet _movingChars = new L2FastSet().setShared(true); private final EvtArrivedManager _evtArrivedManager = new EvtArrivedManager(); private final EvtArrivedRevalidateManager _evtArrivedRevalidateManager = new EvtArrivedRevalidateManager(); private MovementController() { super(GameTimeController.MILLIS_IN_TICK); } public void add(L2Character cha, int ticks) { _movingChars.add(cha); } public void remove(L2Character cha) { _movingChars.remove(cha); _evtArrivedManager.remove(cha); _evtArrivedRevalidateManager.remove(cha); } @Override public void run() { final ArrayList arrivedChars = L2Collections.newArrayList(); final ArrayList followers = L2Collections.newArrayList(); for (L2Character cha : _movingChars) { boolean arrived = cha.updatePosition(GameTimeController.getGameTicks()); // normal movement to an exact coordinate if (cha.getAI().getFollowTarget() == null) { if (arrived) arrivedChars.add(cha); } // following a target else { followers.add(cha); } } // the followed chars must move before checking for acting radius for (L2Character follower : followers) { // we have reached our target if (follower.getAI().isInsideActingRadius()) arrivedChars.add(follower); } _movingChars.removeAll(arrivedChars); followers.removeAll(arrivedChars); _evtArrivedManager.executeAll(arrivedChars); _evtArrivedRevalidateManager.executeAll(followers); L2Collections.recycle(arrivedChars); L2Collections.recycle(followers); } private final class EvtArrivedManager extends FIFOSimpleExecutableQueue { @Override protected void removeAndExecuteFirst() { final L2Character cha = removeFirst(); final long begin = System.nanoTime(); try { cha.getKnownList().updateKnownObjects(); if (cha.hasAI()) cha.getAI().notifyEvent(CtrlEvent.EVT_ARRIVED); } catch (RuntimeException e) { _log.warn("", e); } finally { RunnableStatsManager.handleStats(cha.getClass(), "notifyEvent(CtrlEvent.EVT_ARRIVED)", System.nanoTime() - begin); } } } private final class EvtArrivedRevalidateManager extends FIFOSimpleExecutableQueue { @Override protected void removeAndExecuteFirst() { final L2Character cha = removeFirst(); final long begin = System.nanoTime(); try { if (cha.hasAI()) cha.getAI().notifyEvent(CtrlEvent.EVT_ARRIVED_REVALIDATE); } catch (RuntimeException e) { _log.warn("", e); } finally { RunnableStatsManager.handleStats(cha.getClass(), "notifyEvent(CtrlEvent.EVT_ARRIVED_REVALIDATE)", System.nanoTime() - begin); } } } }