/** * This file is part of aion-emu <aion-emu.com>. * * aion-emu 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. * * aion-emu 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 aion-emu. If not, see <http://www.gnu.org/licenses/>. */ package com.aionemu.gameserver.world; import java.util.Iterator; import java.util.Map; import javolution.util.FastMap; import org.apache.log4j.Logger; import com.aionemu.commons.callbacks.Enhancable; import com.aionemu.gameserver.dataholders.WorldMapsData; import com.aionemu.gameserver.model.gameobjects.AionObject; import com.aionemu.gameserver.model.gameobjects.Npc; import com.aionemu.gameserver.model.gameobjects.VisibleObject; import com.aionemu.gameserver.model.gameobjects.player.Player; import com.aionemu.gameserver.model.templates.WorldMapTemplate; import com.aionemu.gameserver.utils.idfactory.IDFactory; import com.aionemu.gameserver.utils.idfactory.IDFactoryAionObject; import com.aionemu.gameserver.world.container.PlayerContainer; import com.aionemu.gameserver.world.exceptions.AlreadySpawnedException; import com.aionemu.gameserver.world.exceptions.DuplicateAionObjectException; import com.aionemu.gameserver.world.exceptions.NotSetPositionException; import com.aionemu.gameserver.world.exceptions.WorldMapNotExistException; import com.aionemu.gameserver.world.listeners.ObjectAddedToWorldListener; import com.aionemu.gameserver.world.listeners.ObjectRemovedFromWorldListener; import com.google.inject.Inject; /** * World object for storing and spawning, despawning etc players and other in-game objects. It also manage WorldMaps and * instances. * * @author -Nemesiss- * */ public class World { /** * Logger for this class. */ private static final Logger log = Logger.getLogger(World.class); /** * Container with all players that entered world. */ private final PlayerContainer allPlayers = new PlayerContainer(); /** * Container with all AionObjects in the world [ie Players, Npcs etc] */ private final Map<Integer, AionObject> allObjects = new FastMap<Integer, AionObject>().shared(); /** * World maps supported by server. */ private final Map<Integer, WorldMap> worldMaps = new FastMap<Integer, WorldMap>().shared(); private IDFactory aionObjectsIDFactory; /** * Constructor. * * @param worldMapsData */ @Inject public World(WorldMapsData worldMapsData, @IDFactoryAionObject IDFactory aionObjectsIDFactory) { this.aionObjectsIDFactory = aionObjectsIDFactory; for(WorldMapTemplate template : worldMapsData) { worldMaps.put(template.getMapId(), new WorldMap(template, this)); } } /** * Store object in the world. * * @param object */ @Enhancable(callback = ObjectAddedToWorldListener.class) public void storeObject(AionObject object) { if(allObjects.put(object.getObjectId(), object) != null) throw new DuplicateAionObjectException(); if(object instanceof Player) allPlayers.add((Player) object); } /** * Remove Object from the world.<br> * If the given object is Npc then it also releases it's objId from IDFactory. * * @param object */ @Enhancable(callback = ObjectRemovedFromWorldListener.class) public void removeObject(AionObject object) { allObjects.remove(object.getObjectId()); if(object instanceof Player) allPlayers.remove((Player) object); if(object instanceof Npc) aionObjectsIDFactory.releaseId(object.getObjectId()); } /** * Returns Players iterator. * * @return Players iterator. */ public Iterator<Player> getPlayersIterator() { return allPlayers.iterator(); } /** * Returns AionObjects iterator. * * @return AionObjects iterator. */ public Iterator<AionObject> getObjectsIterator() { return allObjects.values().iterator(); } /** * Finds player by player name. * * @param name * - name of player * @return Player */ public Player findPlayer(String name) { return allPlayers.get(name); } /** * Finds player by player objectId. * * @param objectId * - objectId of player * @return Player */ public Player findPlayer(int objectId) { return allPlayers.get(objectId); } /** * Finds AionObject by objectId. * * @param objectId * - objectId of AionOabject * @return AionObject */ public AionObject findAionObject(int objectId) { return allObjects.get(objectId); } /** * Return World Map by id * * @param id * - id of world map. * @return World map. */ public WorldMap getWorldMap(int id) { WorldMap map = worldMaps.get(id); /** * Check if world map exist */ if(map == null) throw new WorldMapNotExistException("Map: " + id + " not exist!"); return map; } /** * Update position of VisibleObject [used when object is moving on one map instance]. Check if active map region * changed and do all needed updates. * * @param object * @param newX * @param newY * @param newZ * @param newHeading */ public void updatePosition(VisibleObject object, float newX, float newY, float newZ, byte newHeading) { this.updatePosition(object, newX, newY, newZ, newHeading, true); } /** * * @param object * @param newX * @param newY * @param newZ * @param newHeading */ public void updatePosition(VisibleObject object, float newX, float newY, float newZ, byte newHeading, boolean updateKnownList) { //prevent updating object position in despawned state if(!object.isSpawned()) return; object.getPosition().setXYZH(newX, newY, newZ, newHeading); MapRegion oldRegion = object.getActiveRegion(); if(oldRegion == null) { log.warn(String.format("CHECKPOINT: oldregion is null, object coordinates - %d %d %d", object.getX(), object.getY(), object.getY())); return; } MapRegion newRegion = oldRegion.getParent().getRegion(object); if(newRegion != oldRegion) { oldRegion.remove(object); newRegion.add(object); object.getPosition().setMapRegion(newRegion); } if(updateKnownList) { object.updateKnownlist(); } } /** * Set position of VisibleObject without spawning [object will be invisible]. If object is spawned it will be * despawned first. * * @param object * @param mapId * @param x * @param y * @param z * @param heading * @throws NotSetPositionException * when object has not set position before. */ public void setPosition(VisibleObject object, int mapId, float x, float y, float z, byte heading) { int instanceId = 1; if(object.getWorldId() == mapId) { instanceId = object.getInstanceId(); } this.setPosition(object, mapId, instanceId, x, y, z, heading); } /** * * @param object * @param mapId * @param instance * @param x * @param y * @param z * @param heading */ public void setPosition(VisibleObject object, int mapId, int instance, float x, float y, float z, byte heading) { if(object.isSpawned()) despawn(object); object.getPosition().setXYZH(x, y, z, heading); object.getPosition().setMapRegion(getWorldMap(mapId).getWorldMapInstanceById(instance).getRegion(object)); } /** * Creates and return {@link WorldPosition} object, representing position with given parameters. * * @param mapId * @param x * @param y * @param z * @param heading * @return WorldPosition */ public WorldPosition createPosition(int mapId, float x, float y, float z, byte heading) { WorldPosition position = new WorldPosition(); position.setXYZH(x, y, z, heading); position.setMapRegion(getWorldMap(mapId).getWorldMapInstance().getRegion(x, y)); return position; } /** * Spawn VisibleObject at current position [use setPosition ]. Object will be visible by others and will see other * objects. * * @param object * @throws AlreadySpawnedException * when object is already spawned. */ public void spawn(VisibleObject object) { if(object.isSpawned()) throw new AlreadySpawnedException(); object.getPosition().setIsSpawned(true); if(object.getSpawn() != null) object.getSpawn().setSpawned(true, object.getInstanceId()); object.getActiveRegion().getParent().addObject(object); object.getActiveRegion().add(object); object.updateKnownlist(); } /** * Despawn VisibleObject, object will become invisible and object position will become invalid. All others objects * will be noticed that this object is no longer visible. * * @throws NullPointerException * if object is already despawned */ public void despawn(VisibleObject object) { object.getActiveRegion().getParent().removeObject(object); object.getActiveRegion().remove(object); object.getPosition().setIsSpawned(false); if(object.getSpawn() != null) object.getSpawn().setSpawned(false, object.getInstanceId()); object.clearKnownlist(); } }