com.l2jfree.gameserver.model.world.L2WorldRegion.java Source code

Java tutorial

Introduction

Here is the source code for com.l2jfree.gameserver.model.world.L2WorldRegion.java

Source

/*
 * 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 <http://www.gnu.org/licenses/>.
 */
package com.l2jfree.gameserver.model.world;

import java.util.Arrays;
import java.util.concurrent.ScheduledFuture;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.l2jfree.Config;
import com.l2jfree.gameserver.ThreadPoolManager;
import com.l2jfree.gameserver.datatables.SpawnTable;
import com.l2jfree.gameserver.gameobjects.L2Attackable;
import com.l2jfree.gameserver.gameobjects.L2Creature;
import com.l2jfree.gameserver.gameobjects.L2Npc;
import com.l2jfree.gameserver.gameobjects.L2Object;
import com.l2jfree.gameserver.gameobjects.L2Playable;
import com.l2jfree.gameserver.gameobjects.ai.CtrlIntention;
import com.l2jfree.gameserver.model.mapregion.L2MapArea;
import com.l2jfree.gameserver.model.mapregion.L2MapRegion;
import com.l2jfree.gameserver.model.mapregion.L2SpecialMapRegion;
import com.l2jfree.gameserver.model.skills.L2Skill;
import com.l2jfree.gameserver.model.world.spawn.L2Spawn;
import com.l2jfree.gameserver.model.zone.L2Zone;
import com.l2jfree.util.concurrent.L2EntityMap;
import com.l2jfree.util.concurrent.L2ReadWriteEntityMap;

public final class L2WorldRegion {
    private static final Log _log = LogFactory.getLog(L2WorldRegion.class);

    public static final int MAP_MIN_X = -131072;
    public static final int MAP_MAX_X = 228608;
    public static final int MAP_MIN_Y = -262144;
    public static final int MAP_MAX_Y = 262144;

    private final L2EntityMap<L2Playable> _playables = new L2ReadWriteEntityMap<L2Playable>();
    private final L2EntityMap<L2Object> _objects = new L2ReadWriteEntityMap<L2Object>();

    private final int _tileX;
    private final int _tileY;

    private L2WorldRegion[] _surroundingRegions = new L2WorldRegion[0];
    private L2Zone[] _zones = new L2Zone[0];
    private L2SpecialMapRegion[] _specialMapRegions = new L2SpecialMapRegion[0];
    private L2MapArea[] _mapAreas = new L2MapArea[0];

    private volatile boolean _active = Config.GRIDS_ALWAYS_ON;
    private ScheduledFuture<?> _neighborsTask;

    public L2WorldRegion(int pTileX, int pTileY) {
        _tileX = pTileX;
        _tileY = pTileY;
    }

    public L2Zone[] getZones() {
        return _zones;
    }

    public void addZone(L2Zone zone) {
        _zones = Arrays.copyOf(_zones, _zones.length + 1);
        _zones[_zones.length - 1] = zone;
    }

    public void clearZones() {
        _zones = new L2Zone[0];
    }

    public void revalidateZones(L2Creature character) {
        // do NOT update the world region while the character is still in the process of teleporting
        // Once the teleport is COMPLETED, revalidation occurs safely, at that time.

        if (character.isTeleporting())
            return;

        for (L2Zone z : _zones)
            z.revalidateInZone(character);
    }

    public void removeFromZones(L2Creature character) {
        for (L2Zone z : _zones)
            z.removeFromZone(character);
    }

    public boolean containsZone(int zoneId) {
        for (L2Zone z : _zones)
            if (z.getId() == zoneId)
                return true;

        return false;
    }

    public L2Zone getZone(L2Zone.ZoneType zt, int x, int y) {
        for (L2Zone z : _zones)
            if (z.getType() == zt)
                if (z.isInsideZone(x, y))
                    return z;

        return null;
    }

    public void onDie(L2Creature character) {
        for (L2Zone z : _zones)
            z.onDie(character);
    }

    public void onRevive(L2Creature character) {
        for (L2Zone z : _zones)
            z.onRevive(character);
    }

    public boolean checkEffectRangeInsidePeaceZone(L2Skill skill, final int x, final int y, final int z) {
        final int range = skill.getEffectRange();
        final int up = y + range;
        final int down = y - range;
        final int left = x + range;
        final int right = x - range;

        for (L2Zone e : _zones) {
            if (e.isPeace()) {
                if (e.isCloserThan(x, y, range))
                    return true;

                if (e.isInsideZone(x, up, z))
                    return false;

                if (e.isInsideZone(x, down, z))
                    return false;

                if (e.isInsideZone(left, y, z))
                    return false;

                if (e.isInsideZone(right, y, z))
                    return false;

                if (e.isInsideZone(x, y, z))
                    return false;
            }
        }

        return true;
    }

    public void addMapRegion(L2MapRegion mapregion) {
        if (mapregion instanceof L2SpecialMapRegion)
            _specialMapRegions = (L2SpecialMapRegion[]) ArrayUtils.add(_specialMapRegions, mapregion);
        else
            _mapAreas = (L2MapArea[]) ArrayUtils.add(_mapAreas, mapregion);
    }

    public void clearMapRegions() {
        _specialMapRegions = new L2SpecialMapRegion[0];
        _mapAreas = new L2MapArea[0];
    }

    public L2MapRegion getMapRegion(int x, int y, int z) {
        for (L2SpecialMapRegion region : _specialMapRegions)
            if (region.checkIfInRegion(x, y, z))
                return region;

        for (L2MapArea region : _mapAreas)
            if (region.checkIfInRegion(x, y, z))
                return region;

        return null;
    }

    private final class NeighborsTask implements Runnable {
        private final boolean _isActivating;

        public NeighborsTask(boolean isActivating) {
            _isActivating = isActivating;
        }

        @Override
        public void run() {
            if (_isActivating) {
                for (L2WorldRegion neighbor : getSurroundingRegions())
                    neighbor.setActive(true);
            } else {
                if (areNeighborsEmpty())
                    setActive(false);

                for (L2WorldRegion neighbor : getSurroundingRegions())
                    if (neighbor.areNeighborsEmpty())
                        neighbor.setActive(false);
            }
        }
    }

    private void setActive(boolean active) {
        if (_active == active)
            return;

        _active = active;

        if (!active) {
            for (L2Object obj : getVisibleObjects()) {
                if (obj instanceof L2Attackable) {
                    L2Attackable mob = (L2Attackable) obj;

                    mob.setTarget(null);
                    mob.stopMove(null, false);
                    mob.stopAllEffects();
                    mob.clearAggroList();
                    mob.resetAbsorbList();
                    mob.getKnownList().removeAllKnownObjects();
                    mob.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
                    mob.getAI().stopAITask();
                }

                if (obj instanceof L2Npc)
                    ((L2Npc) obj).stopRandomAnimation();
            }
        } else {
            final L2Object[][] surroundingObjects = getAllSurroundingObjects2DArray();

            for (L2Object obj : getVisibleObjects()) {
                if (obj == null)
                    continue;

                if (obj instanceof L2Attackable)
                    ((L2Attackable) obj).getStatus().startHpMpRegeneration();

                else if (obj instanceof L2Npc)
                    ((L2Npc) obj).broadcastRandomAnimation(false);

                obj.getKnownList().tryAddObjects(surroundingObjects);
            }
        }
    }

    public boolean isActive() {
        return _active;
    }

    // check if all 9 neighbors (including self) are inactive or active but with no players.
    // returns true if the above condition is met.
    public boolean areNeighborsEmpty() {
        // if this region is occupied, return false.
        if (isActive() && !_playables.isEmpty())
            return false;

        // if any one of the neighbors is occupied, return false
        for (L2WorldRegion neighbor : getSurroundingRegions())
            if (neighbor.isActive() && !neighbor._playables.isEmpty())
                return false;

        // in all other cases, return true.
        return true;
    }

    /**
     * Immediately sets self as active and starts a timer to set neighbors as active this timer is to avoid turning on
     * neighbors in the case when a person just teleported into a region and then teleported out immediately...there is
     * no reason to activate all the neighbors in that case.
     */
    private void startActivation() {
        // first set self to active and do self-tasks...
        setActive(true);

        // if the timer to deactivate neighbors is running, cancel it.
        synchronized (this) {
            if (_neighborsTask != null) {
                _neighborsTask.cancel(true);
                _neighborsTask = null;
            }

            // then, set a timer to activate the neighbors
            _neighborsTask = ThreadPoolManager.getInstance().schedule(new NeighborsTask(true),
                    1000 * Config.GRID_NEIGHBOR_TURNON_TIME);
        }
    }

    /**
     * starts a timer to set neighbors (including self) as inactive this timer is to avoid turning off neighbors in the
     * case when a person just moved out of a region that he may very soon return to. There is no reason to turn self &
     * neighbors off in that case.
     */
    private void startDeactivation() {
        // if the timer to activate neighbors is running, cancel it.
        synchronized (this) {
            if (_neighborsTask != null) {
                _neighborsTask.cancel(true);
                _neighborsTask = null;
            }

            // start a timer to "suggest" a deactivate to self and neighbors.
            // suggest means: first check if a neighbor has L2Players in it.  If not, deactivate.
            _neighborsTask = ThreadPoolManager.getInstance().schedule(new NeighborsTask(false),
                    1000 * Config.GRID_NEIGHBOR_TURNOFF_TIME);
        }
    }

    /**
     * Add the L2Object in the _visibleObjects containing L2Object visible in this L2WorldRegion <BR>
     * If L2Object is a L2Player, Add the L2Player in the L2ObjectHashSet(L2Player) _allPlayable containing
     * L2Player of all player in game in this L2WorldRegion <BR>
     * Assert : object.getCurrentWorldRegion() == this
     */
    public void addVisibleObject(L2Object object, boolean addToKnownLists) {
        if (Config.ASSERT)
            assert object.getWorldRegion() == this;

        if (object == null)
            return;

        if (object instanceof L2Playable) {
            _playables.add((L2Playable) object);

            // if this is the first player to enter the region, activate self & neighbors
            if (!Config.GRIDS_ALWAYS_ON && _playables.size() == 1)
                startActivation();
        }

        _objects.add(object);

        if (addToKnownLists) {
            for (L2WorldRegion reg : getSurroundingRegions()) {
                for (L2Object element : reg.getVisibleObjects()) {
                    element.getKnownList().addKnownObject(object);
                    object.getKnownList().addKnownObject(element);
                }
            }
        }
    }

    /**
     * Remove the L2Object from the L2ObjectHashSet(L2Object) _visibleObjects in this L2WorldRegion <BR>
     * <BR>
     * If L2Object is a L2Player, remove it from the L2ObjectHashSet(L2Player) _allPlayable of this
     * L2WorldRegion <BR>
     * Assert : object.getCurrentWorldRegion() == this || object.getCurrentWorldRegion() == null
     */
    public void removeVisibleObject(L2Object object, boolean removeFromKnownlist) {
        if (Config.ASSERT)
            assert object.getWorldRegion() == this || object.getWorldRegion() == null;

        if (object == null)
            return;

        _objects.remove(object);

        if (object instanceof L2Playable) {
            _playables.remove((L2Playable) object);

            if (!Config.GRIDS_ALWAYS_ON && _playables.isEmpty())
                startDeactivation();
        }

        if (removeFromKnownlist) {
            for (L2WorldRegion reg : getSurroundingRegions()) {
                for (L2Object element : reg.getVisibleObjects()) {
                    element.getKnownList().removeKnownObject(object);
                    object.getKnownList().removeKnownObject(element);
                }
            }
        }
    }

    public void addSurroundingRegion(L2WorldRegion region) {
        _surroundingRegions = Arrays.copyOf(_surroundingRegions, _surroundingRegions.length + 1);
        _surroundingRegions[_surroundingRegions.length - 1] = region;
    }

    public L2WorldRegion[] getSurroundingRegions() {
        return _surroundingRegions;
    }

    public L2Object[] getVisibleObjects() {
        return _objects.toArray(L2Object.class);
    }

    public L2Playable[] getVisiblePlayables() {
        return _playables.toArray(L2Playable.class);
    }

    public String getName() {
        return "(" + _tileX + ", " + _tileY + ")";
    }

    /**
     * Deleted all spawns in the world.
     */
    public synchronized void deleteVisibleNpcSpawns() {
        for (L2Object obj : getVisibleObjects()) {
            if (obj instanceof L2Npc) {
                L2Npc npc = (L2Npc) obj;
                npc.deleteMe();

                L2Spawn spawn = npc.getSpawn();
                if (spawn != null) {
                    spawn.stopRespawn();
                    SpawnTable.getInstance().deleteSpawn(spawn, false);
                }
            }
        }

        _log.info("All visible NPC's deleted in Region: " + getName());
    }

    public L2Object[][] getAllSurroundingObjects2DArray() {
        final L2Object[][] result = new L2Object[_surroundingRegions.length][];

        for (int i = 0; i < _surroundingRegions.length; i++)
            result[i] = _surroundingRegions[i].getVisibleObjects();

        return result;
    }
}