123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643 |
- /*
- * Copyright (C) 2004-2015 L2J Server
- *
- * This file is part of L2J Server.
- *
- * L2J Server 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.
- *
- * L2J Server 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.l2jserver.gameserver;
- import java.nio.file.Files;
- import java.nio.file.Path;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import com.l2jserver.Config;
- import com.l2jserver.gameserver.data.xml.impl.DoorData;
- import com.l2jserver.gameserver.model.L2Object;
- import com.l2jserver.gameserver.model.L2World;
- import com.l2jserver.gameserver.model.Location;
- import com.l2jserver.gameserver.model.interfaces.ILocational;
- import com.l2jserver.gameserver.util.GeoUtils;
- import com.l2jserver.gameserver.util.LinePointIterator;
- import com.l2jserver.gameserver.util.LinePointIterator3D;
- import com.l2jserver.geodriver.Cell;
- import com.l2jserver.geodriver.GeoDriver;
- /**
- * Geodata.
- * @author -Nemesiss-, HorridoJoho
- */
- public class GeoData
- {
- private static final Logger LOGGER = LoggerFactory.getLogger(GeoData.class);
- private static final String FILE_NAME_FORMAT = "%d_%d.l2j";
- private static final int ELEVATED_SEE_OVER_DISTANCE = 2;
- private static final int MAX_SEE_OVER_HEIGHT = 48;
- private static final int SPAWN_Z_DELTA_LIMIT = 100;
-
- private final GeoDriver _driver = new GeoDriver();
-
- protected GeoData()
- {
- int loadedRegions = 0;
- try
- {
- for (int regionX = L2World.TILE_X_MIN; regionX <= L2World.TILE_X_MAX; regionX++)
- {
- for (int regionY = L2World.TILE_Y_MIN; regionY <= L2World.TILE_Y_MAX; regionY++)
- {
- final Path geoFilePath = Config.GEODATA_PATH.resolve(String.format(FILE_NAME_FORMAT, regionX, regionY));
- final Boolean loadFile = Config.GEODATA_REGIONS.get(regionX + "_" + regionY);
- if (loadFile != null)
- {
- if (loadFile)
- {
- LOGGER.info("{}: Loading {}...", getClass().getSimpleName(), geoFilePath.getFileName());
- _driver.loadRegion(geoFilePath, regionX, regionY);
- loadedRegions++;
- }
- }
- else if (Config.TRY_LOAD_UNSPECIFIED_REGIONS && Files.exists(geoFilePath))
- {
- try
- {
- LOGGER.info("{}: Loading {}...", getClass().getSimpleName(), geoFilePath.getFileName());
- _driver.loadRegion(geoFilePath, regionX, regionY);
- loadedRegions++;
- }
- catch (Exception e)
- {
- LOGGER.warn("{}: Failed to load {}!", getClass().getSimpleName(), geoFilePath.getFileName(), e);
- }
- }
- }
- }
- }
- catch (Exception e)
- {
- LOGGER.error("{}: Failed to load geodata!", e);
- System.exit(1);
- }
-
- LOGGER.info("{}: Loaded {} regions.", loadedRegions);
- }
-
- public boolean hasGeoPos(int geoX, int geoY)
- {
- return _driver.hasGeoPos(geoX, geoY);
- }
-
- public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe)
- {
- return _driver.checkNearestNswe(geoX, geoY, worldZ, nswe);
- }
-
- public boolean checkNearestNsweAntiCornerCut(int geoX, int geoY, int worldZ, int nswe)
- {
- boolean can = true;
- if ((nswe & Cell.NSWE_NORTH_EAST) == Cell.NSWE_NORTH_EAST)
- {
- // can = canEnterNeighbors(prevX, prevY - 1, prevGeoZ, Direction.EAST) && canEnterNeighbors(prevX + 1, prevY, prevGeoZ, Direction.NORTH);
- can = checkNearestNswe(geoX, geoY - 1, worldZ, Cell.NSWE_EAST) && checkNearestNswe(geoX + 1, geoY, worldZ, Cell.NSWE_NORTH);
- }
-
- if (can && ((nswe & Cell.NSWE_NORTH_WEST) == Cell.NSWE_NORTH_WEST))
- {
- // can = canEnterNeighbors(prevX, prevY - 1, prevGeoZ, Direction.WEST) && canEnterNeighbors(prevX - 1, prevY, prevGeoZ, Direction.NORTH);
- can = checkNearestNswe(geoX, geoY - 1, worldZ, Cell.NSWE_WEST) && checkNearestNswe(geoX, geoY - 1, worldZ, Cell.NSWE_NORTH);
- }
-
- if (can && ((nswe & Cell.NSWE_SOUTH_EAST) == Cell.NSWE_SOUTH_EAST))
- {
- // can = canEnterNeighbors(prevX, prevY + 1, prevGeoZ, Direction.EAST) && canEnterNeighbors(prevX + 1, prevY, prevGeoZ, Direction.SOUTH);
- can = checkNearestNswe(geoX, geoY + 1, worldZ, Cell.NSWE_EAST) && checkNearestNswe(geoX + 1, geoY, worldZ, Cell.NSWE_SOUTH);
- }
-
- if (can && ((nswe & Cell.NSWE_SOUTH_WEST) == Cell.NSWE_SOUTH_WEST))
- {
- // can = canEnterNeighbors(prevX, prevY + 1, prevGeoZ, Direction.WEST) && canEnterNeighbors(prevX - 1, prevY, prevGeoZ, Direction.SOUTH);
- can = checkNearestNswe(geoX, geoY + 1, worldZ, Cell.NSWE_WEST) && checkNearestNswe(geoX - 1, geoY, worldZ, Cell.NSWE_SOUTH);
- }
-
- return can && checkNearestNswe(geoX, geoY, worldZ, nswe);
- }
-
- public int getNearestZ(int geoX, int geoY, int worldZ)
- {
- return _driver.getNearestZ(geoX, geoY, worldZ);
- }
-
- public int getNextLowerZ(int geoX, int geoY, int worldZ)
- {
- return _driver.getNextLowerZ(geoX, geoY, worldZ);
- }
-
- public int getNextHigherZ(int geoX, int geoY, int worldZ)
- {
- return _driver.getNextHigherZ(geoX, geoY, worldZ);
- }
-
- public int getGeoX(int worldX)
- {
- return _driver.getGeoX(worldX);
- }
-
- public int getGeoY(int worldY)
- {
- return _driver.getGeoY(worldY);
- }
-
- public int getWorldX(int geoX)
- {
- return _driver.getWorldX(geoX);
- }
-
- public int getWorldY(int geoY)
- {
- return _driver.getWorldY(geoY);
- }
-
- // ///////////////////
- // L2J METHODS
- /**
- * Gets the height.
- * @param x the x coordinate
- * @param y the y coordinate
- * @param z the z coordinate
- * @return the height
- */
- public int getHeight(int x, int y, int z)
- {
- return getNearestZ(getGeoX(x), getGeoY(y), z);
- }
-
- /**
- * Gets the spawn height.
- * @param x the x coordinate
- * @param y the y coordinate
- * @param z the the z coordinate
- * @return the spawn height
- */
- public int getSpawnHeight(int x, int y, int z)
- {
- final int geoX = getGeoX(x);
- final int geoY = getGeoY(y);
-
- if (!hasGeoPos(geoX, geoY))
- {
- return z;
- }
-
- int nextLowerZ = getNextLowerZ(geoX, geoY, z + 20);
- return Math.abs(nextLowerZ - z) <= SPAWN_Z_DELTA_LIMIT ? nextLowerZ : z;
- }
-
- /**
- * Gets the spawn height.
- * @param location the location
- * @return the spawn height
- */
- public int getSpawnHeight(Location location)
- {
- return getSpawnHeight(location.getX(), location.getY(), location.getZ());
- }
-
- /**
- * Can see target. Doors as target always return true. Checks doors between.
- * @param cha the character
- * @param target the target
- * @return {@code true} if the character can see the target (LOS), {@code false} otherwise
- */
- public boolean canSeeTarget(L2Object cha, L2Object target)
- {
- if (target.isDoor())
- {
- // can always see doors :o
- return true;
- }
-
- return canSeeTarget(cha.getX(), cha.getY(), cha.getZ(), cha.getInstanceId(), target.getX(), target.getY(), target.getZ(), target.getInstanceId());
- }
-
- /**
- * Can see target. Checks doors between.
- * @param cha the character
- * @param worldPosition the world position
- * @return {@code true} if the character can see the target at the given world position, {@code false} otherwise
- */
- public boolean canSeeTarget(L2Object cha, ILocational worldPosition)
- {
- return canSeeTarget(cha.getX(), cha.getY(), cha.getZ(), cha.getInstanceId(), worldPosition.getX(), worldPosition.getY(), worldPosition.getZ());
- }
-
- /**
- * Can see target. Checks doors between.
- * @param x the x coordinate
- * @param y the y coordinate
- * @param z the z coordinate
- * @param instanceId
- * @param tx the target's x coordinate
- * @param ty the target's y coordinate
- * @param tz the target's z coordinate
- * @param tInstanceId the target's instanceId
- * @return
- */
- public boolean canSeeTarget(int x, int y, int z, int instanceId, int tx, int ty, int tz, int tInstanceId)
- {
- if ((instanceId != tInstanceId))
- {
- return false;
- }
- return canSeeTarget(x, y, z, instanceId, tx, ty, tz);
- }
-
- /**
- * Can see target. Checks doors between.
- * @param x the x coordinate
- * @param y the y coordinate
- * @param z the z coordinate
- * @param instanceId
- * @param tx the target's x coordinate
- * @param ty the target's y coordinate
- * @param tz the target's z coordinate
- * @return {@code true} if there is line of sight between the given coordinate sets, {@code false} otherwise
- */
- public boolean canSeeTarget(int x, int y, int z, int instanceId, int tx, int ty, int tz)
- {
- if (DoorData.getInstance().checkIfDoorsBetween(x, y, z, tx, ty, tz, instanceId, true))
- {
- return false;
- }
- return canSeeTarget(x, y, z, tx, ty, tz);
- }
-
- private int getLosGeoZ(int prevX, int prevY, int prevGeoZ, int curX, int curY, int nswe)
- {
- if ((((nswe & Cell.NSWE_NORTH) != 0) && ((nswe & Cell.NSWE_SOUTH) != 0)) || (((nswe & Cell.NSWE_WEST) != 0) && ((nswe & Cell.NSWE_EAST) != 0)))
- {
- throw new RuntimeException("Multiple directions!");
- }
-
- if (checkNearestNsweAntiCornerCut(prevX, prevY, prevGeoZ, nswe))
- {
- return getNearestZ(curX, curY, prevGeoZ);
- }
- return getNextHigherZ(curX, curY, prevGeoZ);
- }
-
- /**
- * Can see target. Does not check doors between.
- * @param x the x coordinate
- * @param y the y coordinate
- * @param z the z coordinate
- * @param tx the target's x coordinate
- * @param ty the target's y coordinate
- * @param tz the target's z coordinate
- * @return {@code true} if there is line of sight between the given coordinate sets, {@code false} otherwise
- */
- public boolean canSeeTarget(int x, int y, int z, int tx, int ty, int tz)
- {
- int geoX = getGeoX(x);
- int geoY = getGeoY(y);
- int tGeoX = getGeoX(tx);
- int tGeoY = getGeoY(ty);
-
- z = getNearestZ(geoX, geoY, z);
- tz = getNearestZ(tGeoX, tGeoY, tz);
-
- // fastpath
- if ((geoX == tGeoX) && (geoY == tGeoY))
- {
- if (hasGeoPos(tGeoX, tGeoY))
- {
- return z == tz;
- }
-
- return true;
- }
-
- if (tz > z)
- {
- int tmp = tx;
- tx = x;
- x = tmp;
-
- tmp = ty;
- ty = y;
- y = tmp;
-
- tmp = tz;
- tz = z;
- z = tmp;
-
- tmp = tGeoX;
- tGeoX = geoX;
- geoX = tmp;
-
- tmp = tGeoY;
- tGeoY = geoY;
- geoY = tmp;
- }
-
- LinePointIterator3D pointIter = new LinePointIterator3D(geoX, geoY, z, tGeoX, tGeoY, tz);
- // first point is guaranteed to be available, skip it, we can always see our own position
- pointIter.next();
- int prevX = pointIter.x();
- int prevY = pointIter.y();
- int prevZ = pointIter.z();
- int prevGeoZ = prevZ;
- int ptIndex = 0;
- while (pointIter.next())
- {
- int curX = pointIter.x();
- int curY = pointIter.y();
-
- if ((curX == prevX) && (curY == prevY))
- {
- continue;
- }
-
- int beeCurZ = pointIter.z();
- int curGeoZ = prevGeoZ;
-
- // check if the position has geodata
- if (hasGeoPos(curX, curY))
- {
- int beeCurGeoZ = getNearestZ(curX, curY, beeCurZ);
- int nswe = GeoUtils.computeNswe(prevX, prevY, curX, curY);// .computeDirection(prevX, prevY, curX, curY);
- curGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, curX, curY, nswe);
- int maxHeight;
- if (ptIndex < ELEVATED_SEE_OVER_DISTANCE)
- {
- maxHeight = z + MAX_SEE_OVER_HEIGHT;
- }
- else
- {
- maxHeight = beeCurZ + MAX_SEE_OVER_HEIGHT;
- }
-
- boolean canSeeThrough = false;
- if ((curGeoZ <= maxHeight) && (curGeoZ <= beeCurGeoZ))
- {
- if ((nswe & Cell.NSWE_NORTH_EAST) == Cell.NSWE_NORTH_EAST)
- {
- int northGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX, prevY - 1, Cell.NSWE_EAST);
- int eastGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX + 1, prevY, Cell.NSWE_NORTH);
- canSeeThrough = (northGeoZ <= maxHeight) && (eastGeoZ <= maxHeight) && (northGeoZ <= getNearestZ(prevX, prevY - 1, beeCurZ)) && (eastGeoZ <= getNearestZ(prevX + 1, prevY, beeCurZ));
- }
- else if ((nswe & Cell.NSWE_NORTH_WEST) == Cell.NSWE_NORTH_WEST)
- {
- int northGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX, prevY - 1, Cell.NSWE_WEST);
- int westGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX - 1, prevY, Cell.NSWE_NORTH);
- canSeeThrough = (northGeoZ <= maxHeight) && (westGeoZ <= maxHeight) && (northGeoZ <= getNearestZ(prevX, prevY - 1, beeCurZ)) && (westGeoZ <= getNearestZ(prevX - 1, prevY, beeCurZ));
- }
- else if ((nswe & Cell.NSWE_SOUTH_EAST) == Cell.NSWE_SOUTH_EAST)
- {
- int southGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX, prevY + 1, Cell.NSWE_EAST);
- int eastGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX + 1, prevY, Cell.NSWE_SOUTH);
- canSeeThrough = (southGeoZ <= maxHeight) && (eastGeoZ <= maxHeight) && (southGeoZ <= getNearestZ(prevX, prevY + 1, beeCurZ)) && (eastGeoZ <= getNearestZ(prevX + 1, prevY, beeCurZ));
- }
- else if ((nswe & Cell.NSWE_SOUTH_WEST) == Cell.NSWE_SOUTH_WEST)
- {
- int southGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX, prevY + 1, Cell.NSWE_WEST);
- int westGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX - 1, prevY, Cell.NSWE_SOUTH);
- canSeeThrough = (southGeoZ <= maxHeight) && (westGeoZ <= maxHeight) && (southGeoZ <= getNearestZ(prevX, prevY + 1, beeCurZ)) && (westGeoZ <= getNearestZ(prevX - 1, prevY, beeCurZ));
- }
- else
- {
- canSeeThrough = true;
- }
- }
-
- if (!canSeeThrough)
- {
- return false;
- }
- }
-
- prevX = curX;
- prevY = curY;
- prevGeoZ = curGeoZ;
- ++ptIndex;
- }
-
- return true;
- }
-
- /**
- * Verifies if the is a path between origin's location and destination, if not returns the closest location.
- * @param origin the origin
- * @param destination the destination
- * @return the destination if there is a path or the closes location
- */
- public Location moveCheck(ILocational origin, ILocational destination)
- {
- return moveCheck(origin.getX(), origin.getY(), origin.getZ(), destination.getX(), destination.getY(), destination.getZ(), origin.getInstanceId());
- }
-
- /**
- * Move check.
- * @param x the x coordinate
- * @param y the y coordinate
- * @param z the z coordinate
- * @param tx the target's x coordinate
- * @param ty the target's y coordinate
- * @param tz the target's z coordinate
- * @param instanceId the instance id
- * @return the last Location (x,y,z) where player can walk - just before wall
- */
- public Location moveCheck(int x, int y, int z, int tx, int ty, int tz, int instanceId)
- {
- int geoX = getGeoX(x);
- int geoY = getGeoY(y);
- z = getNearestZ(geoX, geoY, z);
- int tGeoX = getGeoX(tx);
- int tGeoY = getGeoY(ty);
- tz = getNearestZ(tGeoX, tGeoY, tz);
-
- if (DoorData.getInstance().checkIfDoorsBetween(x, y, z, tx, ty, tz, instanceId, false))
- {
- return new Location(x, y, getHeight(x, y, z));
- }
-
- LinePointIterator pointIter = new LinePointIterator(geoX, geoY, tGeoX, tGeoY);
- // first point is guaranteed to be available
- pointIter.next();
- int prevX = pointIter.x();
- int prevY = pointIter.y();
- int prevZ = z;
-
- while (pointIter.next())
- {
- int curX = pointIter.x();
- int curY = pointIter.y();
- int curZ = getNearestZ(curX, curY, prevZ);
-
- if (hasGeoPos(prevX, prevY))
- {
- int nswe = GeoUtils.computeNswe(prevX, prevY, curX, curY);
- if (!checkNearestNsweAntiCornerCut(prevX, prevY, prevZ, nswe))
- {
- // can't move, return previous location
- return new Location(getWorldX(prevX), getWorldY(prevY), prevZ);
- }
- }
-
- prevX = curX;
- prevY = curY;
- prevZ = curZ;
- }
-
- if (hasGeoPos(prevX, prevY) && (prevZ != tz))
- {
- // different floors, return start location
- return new Location(x, y, z);
- }
-
- return new Location(tx, ty, tz);
- }
-
- /**
- * Checks if its possible to move from one location to another.
- * @param fromX the X coordinate to start checking from
- * @param fromY the Y coordinate to start checking from
- * @param fromZ the Z coordinate to start checking from
- * @param toX the X coordinate to end checking at
- * @param toY the Y coordinate to end checking at
- * @param toZ the Z coordinate to end checking at
- * @param instanceId the instance ID
- * @return {@code true} if the character at start coordinates can move to end coordinates, {@code false} otherwise
- */
- public boolean canMove(int fromX, int fromY, int fromZ, int toX, int toY, int toZ, int instanceId)
- {
- int geoX = getGeoX(fromX);
- int geoY = getGeoY(fromY);
- fromZ = getNearestZ(geoX, geoY, fromZ);
- int tGeoX = getGeoX(toX);
- int tGeoY = getGeoY(toY);
- toZ = getNearestZ(tGeoX, tGeoY, toZ);
-
- if (DoorData.getInstance().checkIfDoorsBetween(fromX, fromY, fromZ, toX, toY, toZ, instanceId, false))
- {
- return false;
- }
-
- LinePointIterator pointIter = new LinePointIterator(geoX, geoY, tGeoX, tGeoY);
- // first point is guaranteed to be available
- pointIter.next();
- int prevX = pointIter.x();
- int prevY = pointIter.y();
- int prevZ = fromZ;
-
- while (pointIter.next())
- {
- int curX = pointIter.x();
- int curY = pointIter.y();
- int curZ = getNearestZ(curX, curY, prevZ);
-
- if (hasGeoPos(prevX, prevY))
- {
- int nswe = GeoUtils.computeNswe(prevX, prevY, curX, curY);
- if (!checkNearestNsweAntiCornerCut(prevX, prevY, prevZ, nswe))
- {
- return false;
- }
- }
-
- prevX = curX;
- prevY = curY;
- prevZ = curZ;
- }
-
- if (hasGeoPos(prevX, prevY) && (prevZ != toZ))
- {
- // different floors
- return false;
- }
-
- return true;
- }
-
- public int traceTerrainZ(int x, int y, int z, int tx, int ty)
- {
- int geoX = getGeoX(x);
- int geoY = getGeoY(y);
- z = getNearestZ(geoX, geoY, z);
- int tGeoX = getGeoX(tx);
- int tGeoY = getGeoY(ty);
-
- LinePointIterator pointIter = new LinePointIterator(geoX, geoY, tGeoX, tGeoY);
- // first point is guaranteed to be available
- pointIter.next();
- int prevZ = z;
-
- while (pointIter.next())
- {
- int curX = pointIter.x();
- int curY = pointIter.y();
- int curZ = getNearestZ(curX, curY, prevZ);
-
- prevZ = curZ;
- }
-
- return prevZ;
- }
-
- /**
- * Checks if its possible to move from one location to another.
- * @param from the {@code ILocational} to start checking from
- * @param toX the X coordinate to end checking at
- * @param toY the Y coordinate to end checking at
- * @param toZ the Z coordinate to end checking at
- * @return {@code true} if the character at start coordinates can move to end coordinates, {@code false} otherwise
- */
- public boolean canMove(ILocational from, int toX, int toY, int toZ)
- {
- return canMove(from.getX(), from.getY(), from.getZ(), toX, toY, toZ, from.getInstanceId());
- }
-
- /**
- * Checks if its possible to move from one location to another.
- * @param from the {@code ILocational} to start checking from
- * @param to the {@code ILocational} to end checking at
- * @return {@code true} if the character at start coordinates can move to end coordinates, {@code false} otherwise
- */
- public boolean canMove(ILocational from, ILocational to)
- {
- return canMove(from, to.getX(), to.getY(), to.getZ());
- }
-
- /**
- * Checks the specified position for available geodata.
- * @param x the X coordinate
- * @param y the Y coordinate
- * @return {@code true} if there is geodata for the given coordinates, {@code false} otherwise
- */
- public boolean hasGeo(int x, int y)
- {
- return hasGeoPos(getGeoX(x), getGeoY(y));
- }
-
- public static GeoData getInstance()
- {
- return SingletonHolder._instance;
- }
-
- private static class SingletonHolder
- {
- protected final static GeoData _instance = new GeoData();
- }
- }
|