Replaced GeoData engine with newest version.

This commit is contained in:
MobiusDev
2017-07-19 23:56:27 +00:00
parent dc770c4a85
commit 40563ace6c
62 changed files with 4212 additions and 3499 deletions

View File

@@ -9,8 +9,6 @@
<classpathentry kind="lib" path="dist/libs/javolution-5.5.1.jar"/>
<classpathentry kind="lib" path="dist/libs/jython-engine-2.2.1.jar"/>
<classpathentry kind="lib" path="dist/libs/jython.jar"/>
<classpathentry kind="lib" path="dist/libs/L2J_GeoAbstraction.jar"/>
<classpathentry kind="lib" path="dist/libs/L2J_GeoDriver.jar"/>
<classpathentry kind="lib" path="dist/libs/mchange-commons-0.2.jar"/>
<classpathentry kind="lib" path="dist/libs/mmocore.jar"/>
<classpathentry kind="lib" path="dist/libs/mysql-connector-java-5.1.23-bin.jar"/>

View File

@@ -0,0 +1,75 @@
# ---------------------------------------------------------------------------
# GeoData
# ---------------------------------------------------------------------------
# Pathfinding options:
# 0 = Disabled
# 1 = Enabled using path node files
# 2 = Enabled using geodata cells at runtime
# Default: 0
PathFinding = 0
# Pathnode directory
# Default: data/pathnode
PathnodeDirectory = data/pathnode
# Pathfinding array buffers configuration
PathFindBuffers = 100x6;128x6;192x6;256x4;320x4;384x4;500x2
# Weight for nodes without obstacles far from walls
LowWeight = 0.5
# Weight for nodes near walls
MediumWeight = 2
# Weight for nodes with obstacles
HighWeight = 3
# Angle paths will be more "smart", but in cost of higher CPU utilization
AdvancedDiagonalStrategy = True
# Weight for diagonal movement. Used only with AdvancedDiagonalStrategy = True
# Default: LowWeight * sqrt(2)
DiagonalWeight = 0.707
# Maximum number of LOS postfilter passes, 0 will disable postfilter.
# Default: 3
MaxPostfilterPasses = 3
# Path debug function.
# Nodes known to pathfinder will be displayed as adena, constructed path as antidots.
# Number of the items show node cost * 10
# Potions display path after first stage filter
# Red potions - actual waypoints. Green potions - nodes removed by LOS postfilter
# This function FOR DEBUG PURPOSES ONLY, never use it on the live server !
DebugPath = False
# True = Loads GeoData buffer's content into physical memory.
# False = Does not necessarily imply that the GeoData buffer's content is not resident in physical memory.
# Default: True
ForceGeoData = True
# This setting controls Client <--> Server Player coordinates synchronization:
# -1 - Will synchronize only Z from Client --> Server. Default when no geodata.
# 1 - Synchronization Client --> Server only. Using this option (without geodata) makes it more difficult for players to bypass obstacles.
# 2 - Intended for geodata (at least with cell-level pathfinding, otherwise can you try -1).
# Server sends validation packet if client goes too far from server calculated coordinates.
# Default: -1
CoordSynchronize = -1
# Geodata files folder
GeoDataPath = ./data/geodata
# True: Try to load regions not specified below(won't disturb server startup when file does not exist)
# False: Don't load any regions other than the ones specified with True below
TryLoadUnspecifiedRegions = True
# List of regions to be required to load
# eg.:
# Both regions required
# 22_22=True
# 19_20=true
# Exclude region from loading
# 25_26=false
# True: Region is required for the server to startup
# False: Region is not considered to be loaded

View File

@@ -1,16 +0,0 @@
# Geodata files folder
geodataPath = ./data/geodata
# True: Try to load regions not specified below(won't disturb server startup when file does not exist)
# False: Don't load any regions other than the ones specified with True below
tryLoadUnspecifiedRegions = True
# List of regions to be required to load
# eg.:
# Both regions required
# 22_22=True
# 19_20=true
# Exclude region from loading
# 25_26=false
# True: Region is required for the server to startup
# False: Region is not considered to be loaded

View File

@@ -376,9 +376,8 @@ admin_geo_pos = 100
admin_geo_spawn_pos = 100
admin_geo_can_see = 100
admin_geo_can_move = 100
admin_geoeditor_connect = 100
admin_geoeditor_join = 100
admin_geoeditor_leave = 100
admin_geogrid = 100
admin_geomap =100
###############
### MANOR ###

View File

@@ -5,7 +5,6 @@
Debug = False
Assert = False
Developer = False
AcceptGeoeditorConn = False
# if true the server will be a test server (listed by clients setted up to list testserver)
TestServer = False
@@ -253,77 +252,6 @@ GridsAlwaysOn = False
GridNeighborTurnOnTime = 1
GridNeighborTurnOffTime = 90
# =================================================================
# GeoData & PathNode
# =================================================================
# GeoData options:
# 0 = GeoData and PathFinding OFF (default)
# 1 = GeoData used to check Line Of Sight (LOS) targetting and
# L2Playable movement. You need to download files for data/geodata folder.
# Monsters can pass walls but not aggro through them.
# 2 = Full GeoData enabled. Includes PathFinding (requires also /data/pathnode
# files if CellPathFinding not enabled) and all character moves go through
# geodata checks (if a mob passes a wall, pathfinding didn't find a route
# but we allow attack and returning home).
# Recommended server memory minimum 2 GB, rather 3 GB.
GeoData = 0
# GeoData driver to use
# Default: com.l2j.geodriver.GeoDriver
GeoDataDriver = com.l2j.geodriver.GeoDriver
# Cell-level pathfinding, produces more accurate routes but is (maybe 10x)
# heavier to calculate. Recommended for small servers at least. If False,
# pathnode files are used. Uses a max nr of nodes in calculation which can
# be adjusted in the algorithm if it needs to be faster.
CellPathFinding = False
# Pathnode directory folder
PathnodeDirectory = ./data/pathnode
# Pathfinding array buffers configuration
PathFindBuffers = 100x6;128x6;192x6;256x4;320x4;384x4;500x2
# Weight for nodes without obstacles far from walls
LowWeight = 0.5
# Weight for nodes near walls
MediumWeight = 2
# Weight for nodes with obstacles
HighWeight = 3
# Angle paths will be more "smart", but in cost of higher CPU utilization
AdvancedDiagonalStrategy = True
# Weight for diagonal movement. Used only with AdvancedDiagonalStrategy = True
# Default: LowWeight * sqrt(2)
DiagonalWeight = 0.707
# Maximum number of LOS postfilter passes, 0 will disable postfilter.
# Default: 3
MaxPostfilterPasses = 3
# Path debug function.
# Nodes known to pathfinder will be displayed as adena, constructed path as antidots.
# Number of the items show node cost * 10
# Potions display path after first stage filter
# Red potions - actual waypoints. Green potions - nodes removed by LOS postfilter
# This function FOR DEBUG PURPOSES ONLY, never use it on the live server!
DebugPath = False
#[True]Loads GeoData buffer's content into physical memory.
#[False] Does not necessarily imply that the GeoData buffer's content is not resident in physical memory.
ForceGeodata = True
# This is setting of Client <--> Server Player coordinates synchronization,
# -1 - Will synchronize only Z from Client --> Server. Default when no geodata.
# 1 - Synchronization Client --> Server only. Using this option (without geodata) it is more difficult for players to bypass obstacles
# 2 - Intended for geodata (at least when cell-level pathfinding, otherwise can try -1 also)!
# Server sends validation packet if client goes too far from server calculated coordinates.
CoordSynchronize = -1
# Falling Damage
# ---------------------------------------------------------------------------
# Allow characters to receive damage from falling.

View File

@@ -23,9 +23,9 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.datatables.SkillTable;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.instancemanager.GrandBossManager;
import com.l2jmobius.gameserver.model.L2Character;
import com.l2jmobius.gameserver.model.L2Effect;
@@ -165,10 +165,7 @@ public class Baium extends Quest
final L2GrandBossInstance baium = (L2GrandBossInstance) addSpawn(LIVE_BAIUM, loc_x, loc_y, loc_z, heading, false, 0);
GrandBossManager.getInstance().addBoss(baium);
final L2NpcInstance _baium = baium;
ThreadPoolManager.getInstance().scheduleGeneral(new Runnable()
{
@Override
public void run()
ThreadPoolManager.getInstance().scheduleGeneral(() ->
{
try
{
@@ -183,7 +180,6 @@ public class Baium extends Quest
{
e.printStackTrace();
}
}
}, 100L);
}
else
@@ -219,10 +215,7 @@ public class Baium extends Quest
startQuestTimer("baium_despawn", 60000, npc, null, true);
startQuestTimer("skill_range", 500, npc, null, true);
final L2NpcInstance baium = npc;
ThreadPoolManager.getInstance().scheduleGeneral(new Runnable()
{
@Override
public void run()
ThreadPoolManager.getInstance().scheduleGeneral(() ->
{
try
{
@@ -233,7 +226,6 @@ public class Baium extends Quest
{
e.printStackTrace();
}
}
}, 11100L);
// TODO: the person who woke baium up should be knocked across the room, onto a wall, and
@@ -313,10 +305,7 @@ public class Baium extends Quest
final L2GrandBossInstance baium = (L2GrandBossInstance) addSpawn(LIVE_BAIUM, npc);
GrandBossManager.getInstance().addBoss(baium);
final L2NpcInstance _baium = baium;
ThreadPoolManager.getInstance().scheduleGeneral(new Runnable()
{
@Override
public void run()
ThreadPoolManager.getInstance().scheduleGeneral(() ->
{
try
{
@@ -330,7 +319,6 @@ public class Baium extends Quest
{
e.printStackTrace();
}
}
}, 100L);
}
else

View File

@@ -16,8 +16,8 @@
*/
package ai.individual;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.model.L2CharPosition;
import com.l2jmobius.gameserver.model.L2Character;
import com.l2jmobius.gameserver.model.L2Summon;

Binary file not shown.

Binary file not shown.

View File

@@ -22,12 +22,16 @@ import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.logging.Logger;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.base.Experience;
import com.l2jmobius.gameserver.util.FloodProtectorConfig;
import com.l2jmobius.util.StringUtil;
@@ -46,6 +50,9 @@ import javolution.util.FastMap;
public final class Config
{
protected static Logger _log = Logger.getLogger(Config.class.getName());
public static final String EOL = System.lineSeparator();
/** Debug/release mode */
public static boolean DEBUG;
/** Enable/disable assertions */
@@ -578,8 +585,6 @@ public final class Config
/** Accept multi-items drop ? */
public static boolean MULTIPLE_ITEM_DROP;
/** Coord Synchronization */
public static int COORD_SYNCHRONIZE;
/** Falling Damage */
public static boolean ENABLE_FALLING_DAMAGE;
@@ -730,6 +735,8 @@ public final class Config
public static final String OLYMPIAD_CONFIGURATION_FILE = "config/olympiad.ini";
/** Properties file for extensions configurations */
public static final String EXTENSIONS_CONFIGURATION_FILE = "config/extensions.ini";
/** Properties file for GeoData configurations */
public static final String GEODATA_CONFIGURATION_FILE = "config/GeoData.ini";
/** Text file containing hexadecimal value of server ID */
public static final String HEXID_FILE = "./config/hexid.txt";
/**
@@ -1269,12 +1276,8 @@ public final class Config
public static int CS_SUPPORT3_FEE;
public static int CS_SUPPORT4_FEE;
/** GeoData 0/1/2 */
public static int GEODATA;
public static String GEODATA_DRIVER;
/** Cell PathFinding */
public static boolean GEODATA_CELLFINDING;
/** GeoData Settings */
public static int PATHFINDING;
public static File PATHNODE_DIR;
public static String PATHFIND_BUFFERS;
public static float LOW_WEIGHT;
@@ -1284,10 +1287,11 @@ public final class Config
public static float DIAGONAL_WEIGHT;
public static int MAX_POSTFILTER_PASSES;
public static boolean DEBUG_PATH;
/** Force loading GeoData to physical memory */
public static boolean FORCE_GEODATA;
public static boolean ACCEPT_GEOEDITOR_CONN;
public static int COORD_SYNCHRONIZE;
public static Path GEODATA_PATH;
public static boolean TRY_LOAD_UNSPECIFIED_REGIONS;
public static Map<String, Boolean> GEODATA_REGIONS;
/** Max number of buffs */
public static byte BUFFS_MAX_AMOUNT;
@@ -1376,6 +1380,45 @@ public final class Config
throw new Error("MinProtocolRevision is bigger than MaxProtocolRevision in server configuration file.");
}
_log.info("Loading GeoData Configuration Files.");
final Properties geoData = new Properties();
try (InputStream is = new FileInputStream(new File(GEODATA_CONFIGURATION_FILE)))
{
geoData.load(is);
}
catch (final Exception e)
{
e.printStackTrace();
throw new Error("Failed to Load " + GEODATA_CONFIGURATION_FILE + " File.");
}
PATHFINDING = Integer.parseInt(geoData.getProperty("PathFinding", "0"));
PATHFIND_BUFFERS = geoData.getProperty("PathFindBuffers", "100x6;128x6;192x6;256x4;320x4;384x4;500x2");
LOW_WEIGHT = Float.parseFloat(geoData.getProperty("LowWeight", "0.5f"));
MEDIUM_WEIGHT = Float.parseFloat(geoData.getProperty("MediumWeight", "2"));
HIGH_WEIGHT = Float.parseFloat(geoData.getProperty("HighWeight", "3"));
ADVANCED_DIAGONAL_STRATEGY = Boolean.parseBoolean(geoData.getProperty("AdvancedDiagonalStrategy", "true"));
DIAGONAL_WEIGHT = Float.parseFloat(geoData.getProperty("DiagonalWeight", "0.707f"));
MAX_POSTFILTER_PASSES = Integer.parseInt(geoData.getProperty("MaxPostfilterPasses", "3"));
DEBUG_PATH = Boolean.parseBoolean(geoData.getProperty("DebugPath", "false"));
FORCE_GEODATA = Boolean.parseBoolean(geoData.getProperty("ForceGeoData", "true"));
COORD_SYNCHRONIZE = Integer.parseInt(geoData.getProperty("CoordSynchronize", "-1"));
GEODATA_PATH = Paths.get(geoData.getProperty("GeoDataPath", "./data/geodata"));
TRY_LOAD_UNSPECIFIED_REGIONS = Boolean.parseBoolean(geoData.getProperty("TryLoadUnspecifiedRegions", "true"));
GEODATA_REGIONS = new HashMap<>();
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 String key = regionX + "_" + regionY;
if (geoData.containsKey(regionX + "_" + regionY))
{
GEODATA_REGIONS.put(key, Boolean.parseBoolean(geoData.getProperty(key, "false")));
}
}
}
final Properties optionsSettings = new Properties();
try (InputStream is = new FileInputStream(new File(OPTIONS_FILE)))
{
@@ -1392,7 +1435,6 @@ public final class Config
DEBUG = Boolean.parseBoolean(optionsSettings.getProperty("Debug", "false"));
ASSERT = Boolean.parseBoolean(optionsSettings.getProperty("Assert", "false"));
DEVELOPER = Boolean.parseBoolean(optionsSettings.getProperty("Developer", "false"));
ACCEPT_GEOEDITOR_CONN = Boolean.parseBoolean(optionsSettings.getProperty("AcceptGeoeditorConn", "False"));
TEST_SERVER = Boolean.parseBoolean(optionsSettings.getProperty("TestServer", "false"));
SERVER_LIST_TESTSERVER = Boolean.parseBoolean(optionsSettings.getProperty("TestServer", "false"));
@@ -1422,7 +1464,7 @@ public final class Config
MULTIPLE_ITEM_DROP = Boolean.valueOf(optionsSettings.getProperty("MultipleItemDrop", "True"));
final String str = optionsSettings.getProperty("EnableFallingDamage", "auto");
ENABLE_FALLING_DAMAGE = "auto".equalsIgnoreCase(str) ? GEODATA > 0 : Boolean.parseBoolean(str);
ENABLE_FALLING_DAMAGE = "auto".equalsIgnoreCase(str) ? PATHFINDING > 0 : Boolean.parseBoolean(str);
ALLOW_WAREHOUSE = Boolean.valueOf(optionsSettings.getProperty("AllowWarehouse", "True"));
WAREHOUSE_CACHE = Boolean.valueOf(optionsSettings.getProperty("WarehouseCache", "False"));
@@ -1511,31 +1553,6 @@ public final class Config
GRID_NEIGHBOR_TURNON_TIME = Integer.parseInt(optionsSettings.getProperty("GridNeighborTurnOnTime", "1"));
GRID_NEIGHBOR_TURNOFF_TIME = Integer.parseInt(optionsSettings.getProperty("GridNeighborTurnOffTime", "90"));
GEODATA = Integer.parseInt(optionsSettings.getProperty("GeoData", "0"));
GEODATA_DRIVER = optionsSettings.getProperty("GeoDataDriver", "com.l2j.geodriver.GeoDriver");
GEODATA_CELLFINDING = Boolean.parseBoolean(optionsSettings.getProperty("CellPathFinding", "False"));
try
{
PATHNODE_DIR = new File(optionsSettings.getProperty("PathnodeDirectory", "./data/pathnode").replaceAll("\\\\", "/")).getCanonicalFile();
}
catch (final Exception e)
{
_log.warning("Error setting pathnode directory!");
PATHNODE_DIR = new File("./data/pathnode");
}
PATHFIND_BUFFERS = optionsSettings.getProperty("PathFindBuffers", "100x6;128x6;192x6;256x4;320x4;384x4;500x2");
LOW_WEIGHT = Float.parseFloat(optionsSettings.getProperty("LowWeight", "0.5"));
MEDIUM_WEIGHT = Float.parseFloat(optionsSettings.getProperty("MediumWeight", "2"));
HIGH_WEIGHT = Float.parseFloat(optionsSettings.getProperty("HighWeight", "3"));
ADVANCED_DIAGONAL_STRATEGY = Boolean.parseBoolean(optionsSettings.getProperty("AdvancedDiagonalStrategy", "True"));
DIAGONAL_WEIGHT = Float.parseFloat(optionsSettings.getProperty("DiagonalWeight", "0.707"));
MAX_POSTFILTER_PASSES = Integer.parseInt(optionsSettings.getProperty("MaxPostfilterPasses", "3"));
DEBUG_PATH = Boolean.parseBoolean(optionsSettings.getProperty("DebugPath", "False"));
FORCE_GEODATA = Boolean.parseBoolean(optionsSettings.getProperty("ForceGeoData", "True"));
COORD_SYNCHRONIZE = Integer.parseInt(optionsSettings.getProperty("CoordSynchronize", "-1"));
// ---------------------------------------------------
// Configuration values not found in config files
// ---------------------------------------------------

View File

@@ -63,7 +63,8 @@ import com.l2jmobius.gameserver.datatables.StaticObjects;
import com.l2jmobius.gameserver.datatables.SummonItemsData;
import com.l2jmobius.gameserver.datatables.TeleportLocationTable;
import com.l2jmobius.gameserver.datatables.ZoneTable;
import com.l2jmobius.gameserver.geoeditorcon.GeoEditorListener;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geodata.pathfinding.PathFinding;
import com.l2jmobius.gameserver.handler.AdminCommandHandler;
import com.l2jmobius.gameserver.handler.ItemHandler;
import com.l2jmobius.gameserver.handler.SkillHandler;
@@ -87,7 +88,6 @@ import com.l2jmobius.gameserver.handler.admincommandhandlers.AdminEnchant;
import com.l2jmobius.gameserver.handler.admincommandhandlers.AdminEventEngine;
import com.l2jmobius.gameserver.handler.admincommandhandlers.AdminExpSp;
import com.l2jmobius.gameserver.handler.admincommandhandlers.AdminFightCalculator;
import com.l2jmobius.gameserver.handler.admincommandhandlers.AdminGeoEditor;
import com.l2jmobius.gameserver.handler.admincommandhandlers.AdminGeodata;
import com.l2jmobius.gameserver.handler.admincommandhandlers.AdminGm;
import com.l2jmobius.gameserver.handler.admincommandhandlers.AdminGmChat;
@@ -223,7 +223,6 @@ import com.l2jmobius.gameserver.model.entity.AutoRewarder;
import com.l2jmobius.gameserver.model.entity.Hero;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.L2GamePacketHandler;
import com.l2jmobius.gameserver.pathfinding.PathFinding;
import com.l2jmobius.gameserver.script.faenor.FaenorScriptEngine;
import com.l2jmobius.gameserver.scripting.L2ScriptEngineManager;
import com.l2jmobius.gameserver.taskmanager.AutoAnnounceTaskManager;
@@ -359,7 +358,7 @@ public class GameServer
ClanTable.getInstance();
GeoData.getInstance();
if (Config.GEODATA == 2)
if (Config.PATHFINDING > 0)
{
PathFinding.getInstance();
}
@@ -588,7 +587,6 @@ public class GameServer
_adminCommandHandler.registerAdminCommandHandler(new AdminQuest());
_adminCommandHandler.registerAdminCommandHandler(new AdminZone());
_adminCommandHandler.registerAdminCommandHandler(new AdminGeodata());
_adminCommandHandler.registerAdminCommandHandler(new AdminGeoEditor());
_adminCommandHandler.registerAdminCommandHandler(new AdminManor());
// _adminCommandHandler.registerAdminCommandHandler(new AdminRadar());
@@ -630,11 +628,6 @@ public class GameServer
// read pet stats from db
L2PetDataTable.getInstance().loadPetsData();
if (Config.ACCEPT_GEOEDITOR_CONN)
{
GeoEditorListener.getInstance();
}
_shutdownHandler = Shutdown.getInstance();
Runtime.getRuntime().addShutdownHook(_shutdownHandler);

View File

@@ -1,577 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* 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.l2jmobius.gameserver;
import java.io.FileInputStream;
import java.lang.reflect.Constructor;
import java.nio.file.Paths;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.datatables.DoorTable;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.actor.instance.L2DoorInstance;
import com.l2jmobius.gameserver.util.GeoUtils;
import com.l2jmobius.gameserver.util.LinePointIterator;
import com.l2jmobius.gameserver.util.LinePointIterator3D;
import com.l2jserver.gameserver.geoengine.Direction;
import com.l2jserver.gameserver.geoengine.NullDriver;
import com.l2jserver.gameserver.geoengine.abstraction.IGeoDriver;
/**
* @author -Nemesiss-, FBIagent
*/
public class GeoData implements IGeoDriver
{
private static Logger LOGGER = Logger.getLogger(GeoData.class.getName());
private static final int ELEVATED_SEE_OVER_DISTANCE = 2;
private static final int MAX_SEE_OVER_HEIGHT = 48;
private final IGeoDriver _driver;
private static GeoData _instance;
public static GeoData getInstance()
{
if (_instance == null)
{
_instance = new GeoData();
}
return _instance;
}
protected GeoData()
{
if (Config.GEODATA > 0)
{
IGeoDriver driver = null;
try
{
final Class<?> cls = Class.forName(Config.GEODATA_DRIVER);
if (!IGeoDriver.class.isAssignableFrom(cls))
{
throw new ClassCastException("Geodata driver class needs to implement IGeoDriver!");
}
final Constructor<?> ctor = cls.getConstructor(Properties.class);
final Properties props = new Properties();
try (FileInputStream fis = new FileInputStream(Paths.get("config", "GeoDriver.ini").toString()))
{
props.load(fis);
}
driver = (IGeoDriver) ctor.newInstance(props);
}
catch (final Exception ex)
{
LOGGER.log(Level.SEVERE, "Failed to load geodata driver!", ex);
System.exit(1);
}
// we do it this way so it's predictable for the compiler
_driver = driver;
}
else
{
_driver = new NullDriver(null);
}
}
public boolean isNullDriver()
{
return _driver instanceof NullDriver;
}
@Override
public int getGeoX(int worldX)
{
return _driver.getGeoX(worldX);
}
@Override
public int getGeoY(int worldY)
{
return _driver.getGeoY(worldY);
}
@Override
public int getWorldX(int geoX)
{
return _driver.getWorldX(geoX);
}
@Override
public int getWorldY(int geoY)
{
return _driver.getWorldY(geoY);
}
@Override
public boolean hasGeoPos(int geoX, int geoY)
{
return _driver.hasGeoPos(geoX, geoY);
}
@Override
public int getNearestZ(int geoX, int geoY, int worldZ)
{
return _driver.getNearestZ(geoX, geoY, worldZ);
}
@Override
public int getNextLowerZ(int geoX, int geoY, int worldZ)
{
return _driver.getNextLowerZ(geoX, geoY, worldZ);
}
@Override
public int getNextHigherZ(int geoX, int geoY, int worldZ)
{
return _driver.getNextHigherZ(geoX, geoY, worldZ);
}
@Override
public boolean canEnterNeighbors(int geoX, int geoY, int worldZ, Direction first, Direction... more)
{
return _driver.canEnterNeighbors(geoX, geoY, worldZ, first, more);
}
@Override
public boolean canEnterAllNeighbors(int geoX, int geoY, int worldZ)
{
return _driver.canEnterAllNeighbors(geoX, geoY, worldZ);
}
/**
* @param x
* @param y
* @param z
* @return Nearles Z
*/
public int getHeight(int x, int y, int z)
{
return getNearestZ(getGeoX(x), getGeoY(y), z);
}
/**
* @param x
* @param y
* @param zmin
* @param zmax
* @return
*/
public int getSpawnHeight(int x, int y, int zmin, int zmax)
{
// + 30, defend against defective geodata and invalid spawn z :(
return getNextLowerZ(getGeoX(x), getGeoY(y), zmax + 30);
}
private int getLosGeoZ(int prevX, int prevY, int prevGeoZ, int curX, int curY, Direction dir)
{
boolean can = true;
switch (dir)
{
case NORTH_EAST:
can = canEnterNeighbors(prevX, prevY - 1, prevGeoZ, Direction.EAST) && canEnterNeighbors(prevX + 1, prevY, prevGeoZ, Direction.NORTH);
break;
case NORTH_WEST:
can = canEnterNeighbors(prevX, prevY - 1, prevGeoZ, Direction.WEST) && canEnterNeighbors(prevX - 1, prevY, prevGeoZ, Direction.NORTH);
break;
case SOUTH_EAST:
can = canEnterNeighbors(prevX, prevY + 1, prevGeoZ, Direction.EAST) && canEnterNeighbors(prevX + 1, prevY, prevGeoZ, Direction.SOUTH);
break;
case SOUTH_WEST:
can = canEnterNeighbors(prevX, prevY + 1, prevGeoZ, Direction.WEST) && canEnterNeighbors(prevX - 1, prevY, prevGeoZ, Direction.SOUTH);
break;
}
if (can && canEnterNeighbors(prevX, prevY, prevGeoZ, dir))
{
return getNearestZ(curX, curY, prevGeoZ);
}
return getNextHigherZ(curX, curY, prevGeoZ);
}
/**
* Can see target. Doors as target always return true. Checks doors between.
* @param cha
* @param target
* @return True if cha can see target (LOS)
*/
public boolean canSeeTarget(L2Object cha, L2Object target)
{
if (target instanceof L2DoorInstance)
{
// can always see doors :o
return true;
}
if (DoorTable.getInstance().checkIfDoorsBetween(cha.getX(), cha.getY(), cha.getZ(), target.getX(), target.getY(), target.getZ()))
{
return false;
}
return canSeeTarget(cha.getX(), cha.getY(), cha.getZ(), target.getX(), target.getY(), target.getZ());
}
/**
* 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);
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;
}
final 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();
final int prevZ = pointIter.z();
int prevGeoZ = prevZ;
int ptIndex = 0;
while (pointIter.next())
{
final int curX = pointIter.x();
final int curY = pointIter.y();
if ((curX == prevX) && (curY == prevY))
{
continue;
}
final int beeCurZ = pointIter.z();
int curGeoZ = prevGeoZ;
// the current position has geodata
if (hasGeoPos(curX, curY))
{
final int beeCurGeoZ = getNearestZ(curX, curY, beeCurZ);
final Direction dir = GeoUtils.computeDirection(prevX, prevY, curX, curY);
curGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, curX, curY, dir);
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))
{
switch (dir)
{
case NORTH_EAST:
{
final int northGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX, prevY - 1, Direction.EAST);
final int eastGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX + 1, prevY, Direction.NORTH);
canSeeThrough = (northGeoZ <= maxHeight) && (eastGeoZ <= maxHeight) && (northGeoZ <= getNearestZ(prevX, prevY - 1, beeCurZ)) && (eastGeoZ <= getNearestZ(prevX + 1, prevY, beeCurZ));
break;
}
case NORTH_WEST:
{
final int northGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX, prevY - 1, Direction.WEST);
final int westGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX - 1, prevY, Direction.NORTH);
canSeeThrough = (northGeoZ <= maxHeight) && (westGeoZ <= maxHeight) && (northGeoZ <= getNearestZ(prevX, prevY - 1, beeCurZ)) && (westGeoZ <= getNearestZ(prevX - 1, prevY, beeCurZ));
break;
}
case SOUTH_EAST:
{
final int southGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX, prevY + 1, Direction.EAST);
final int eastGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX + 1, prevY, Direction.SOUTH);
canSeeThrough = (southGeoZ <= maxHeight) && (eastGeoZ <= maxHeight) && (southGeoZ <= getNearestZ(prevX, prevY + 1, beeCurZ)) && (eastGeoZ <= getNearestZ(prevX + 1, prevY, beeCurZ));
break;
}
case SOUTH_WEST:
{
final int southGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX, prevY + 1, Direction.WEST);
final int westGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX - 1, prevY, Direction.SOUTH);
canSeeThrough = (southGeoZ <= maxHeight) && (westGeoZ <= maxHeight) && (southGeoZ <= getNearestZ(prevX, prevY + 1, beeCurZ)) && (westGeoZ <= getNearestZ(prevX - 1, prevY, beeCurZ));
break;
}
default:
{
canSeeThrough = true;
break;
}
}
}
if (!canSeeThrough)
{
return false;
}
}
prevX = curX;
prevY = curY;
prevGeoZ = curGeoZ;
++ptIndex;
}
return true;
}
/**
* @param x
* @param y
* @param z
* @param tx
* @param ty
* @param tz
* @return 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)
{
final int geoX = getGeoX(x);
final int geoY = getGeoY(y);
z = getNearestZ(geoX, geoY, z);
final int tGeoX = getGeoX(tx);
final int tGeoY = getGeoY(ty);
tz = getNearestZ(tGeoX, tGeoY, tz);
if (DoorTable.getInstance().checkIfDoorsBetween(x, y, z, tx, ty, tz))
{
return new Location(x, y, getHeight(x, y, z));
}
final 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())
{
final int curX = pointIter.x();
final int curY = pointIter.y();
final int curZ = getNearestZ(curX, curY, prevZ);
if (hasGeoPos(prevX, prevY))
{
final Direction dir = GeoUtils.computeDirection(prevX, prevY, curX, curY);
boolean canEnter = false;
if (canEnterNeighbors(prevX, prevY, prevZ, dir))
{
// check diagonal movement
switch (dir)
{
case NORTH_EAST:
canEnter = canEnterNeighbors(prevX, prevY - 1, prevZ, Direction.EAST) && canEnterNeighbors(prevX + 1, prevY, prevZ, Direction.NORTH);
break;
case NORTH_WEST:
canEnter = canEnterNeighbors(prevX, prevY - 1, prevZ, Direction.WEST) && canEnterNeighbors(prevX - 1, prevY, prevZ, Direction.NORTH);
break;
case SOUTH_EAST:
canEnter = canEnterNeighbors(prevX, prevY + 1, prevZ, Direction.EAST) && canEnterNeighbors(prevX + 1, prevY, prevZ, Direction.SOUTH);
break;
case SOUTH_WEST:
canEnter = canEnterNeighbors(prevX, prevY + 1, prevZ, Direction.WEST) && canEnterNeighbors(prevX - 1, prevY, prevZ, Direction.SOUTH);
break;
default:
canEnter = true;
break;
}
}
if (!canEnter)
{
// 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);
}
public int traceTerrainZ(int x, int y, int z, int tx, int ty)
{
final int geoX = getGeoX(x);
final int geoY = getGeoY(y);
z = getNearestZ(geoX, geoY, z);
final int tGeoX = getGeoX(tx);
final int tGeoY = getGeoY(ty);
final LinePointIterator pointIter = new LinePointIterator(geoX, geoY, tGeoX, tGeoY);
// first point is guaranteed to be available
pointIter.next();
int prevZ = z;
while (pointIter.next())
{
final int curX = pointIter.x();
final int curY = pointIter.y();
final int curZ = getNearestZ(curX, curY, prevZ);
prevZ = curZ;
}
return prevZ;
}
/**
* 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
* @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)
{
final int geoX = getGeoX(fromX);
final int geoY = getGeoY(fromY);
fromZ = getNearestZ(geoX, geoY, fromZ);
final int tGeoX = getGeoX(toX);
final int tGeoY = getGeoY(toY);
toZ = getNearestZ(tGeoX, tGeoY, toZ);
if (DoorTable.getInstance().checkIfDoorsBetween(fromX, fromY, fromZ, toX, toY, toZ))
{
return false;
}
final 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())
{
final int curX = pointIter.x();
final int curY = pointIter.y();
final int curZ = getNearestZ(curX, curY, prevZ);
if (hasGeoPos(prevX, prevY))
{
final Direction dir = GeoUtils.computeDirection(prevX, prevY, curX, curY);
boolean canEnter = false;
if (canEnterNeighbors(prevX, prevY, prevZ, dir))
{
// check diagonal movement
switch (dir)
{
case NORTH_EAST:
canEnter = canEnterNeighbors(prevX, prevY - 1, prevZ, Direction.EAST) && canEnterNeighbors(prevX + 1, prevY, prevZ, Direction.NORTH);
break;
case NORTH_WEST:
canEnter = canEnterNeighbors(prevX, prevY - 1, prevZ, Direction.WEST) && canEnterNeighbors(prevX - 1, prevY, prevZ, Direction.NORTH);
break;
case SOUTH_EAST:
canEnter = canEnterNeighbors(prevX, prevY + 1, prevZ, Direction.EAST) && canEnterNeighbors(prevX + 1, prevY, prevZ, Direction.SOUTH);
break;
case SOUTH_WEST:
canEnter = canEnterNeighbors(prevX, prevY + 1, prevZ, Direction.WEST) && canEnterNeighbors(prevX - 1, prevY, prevZ, Direction.SOUTH);
break;
default:
canEnter = true;
break;
}
}
if (!canEnter)
{
return false;
}
}
prevX = curX;
prevY = curY;
prevZ = curZ;
}
if (hasGeoPos(prevX, prevY) && (prevZ != toZ))
{
// different floors
return false;
}
return true;
}
public boolean hasGeo(int x, int y)
{
return hasGeoPos(getGeoX(x), getGeoY(y));
}
}

View File

@@ -25,9 +25,9 @@ import java.util.concurrent.Future;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.GameTimeController;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.Territory;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.instancemanager.DimensionalRiftManager;
import com.l2jmobius.gameserver.model.L2Attackable;
import com.l2jmobius.gameserver.model.L2CharPosition;
@@ -976,7 +976,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
}
// Considering, if bigger range will be attempted
if ((dist2 < (10000 + (combinedCollision * combinedCollision))) && !_selfAnalysis.isFighter && !_selfAnalysis.isBalanced && (_selfAnalysis.hasLongRangeSkills || _selfAnalysis.isArcher) && (_mostHatedAnalysis.isBalanced || _mostHatedAnalysis.isFighter) && (_mostHatedAnalysis.character.isRooted() || _mostHatedAnalysis.isSlower) && ((Config.GEODATA == 2 ? 20 : 12) >= Rnd.get(100))) // chance
if ((dist2 < (10000 + (combinedCollision * combinedCollision))) && !_selfAnalysis.isFighter && !_selfAnalysis.isBalanced && (_selfAnalysis.hasLongRangeSkills || _selfAnalysis.isArcher) && (_mostHatedAnalysis.isBalanced || _mostHatedAnalysis.isFighter) && (_mostHatedAnalysis.character.isRooted() || _mostHatedAnalysis.isSlower) && ((Config.PATHFINDING == 2 ? 20 : 12) >= Rnd.get(100))) // chance
{
int posX = _actor.getX();
int posY = _actor.getY();

View File

@@ -24,8 +24,8 @@ import java.util.concurrent.Future;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.GameTimeController;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.model.L2Attackable;
import com.l2jmobius.gameserver.model.L2Character;
import com.l2jmobius.gameserver.model.L2Effect;

View File

@@ -27,11 +27,11 @@ import java.util.StringTokenizer;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNodeLoc;
import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.instancemanager.ClanHallManager;
import com.l2jmobius.gameserver.model.actor.instance.L2DoorInstance;
import com.l2jmobius.gameserver.model.entity.ClanHall;
import com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc;
import com.l2jmobius.gameserver.templates.L2CharTemplate;
import com.l2jmobius.gameserver.templates.StatsSet;

View File

@@ -0,0 +1,559 @@
/*
* This file is part of the L2J Mobius project.
*
* 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.l2jmobius.gameserver.geodata;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.datatables.DoorTable;
import com.l2jmobius.gameserver.geodata.geodriver.Cell;
import com.l2jmobius.gameserver.geodata.geodriver.GeoDriver;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.actor.instance.L2DoorInstance;
import com.l2jmobius.gameserver.util.GeoUtils;
import com.l2jmobius.gameserver.util.LinePointIterator;
import com.l2jmobius.gameserver.util.LinePointIterator3D;
/**
* @author -Nemesiss-, HorridoJoho
*/
public class GeoData
{
private static final Logger LOGGER = Logger.getLogger(GeoData.class.getName());
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(getClass().getSimpleName() + ": Loading " + geoFilePath.getFileName() + "...");
_driver.loadRegion(geoFilePath, regionX, regionY);
loadedRegions++;
}
}
else if (Config.TRY_LOAD_UNSPECIFIED_REGIONS && Files.exists(geoFilePath))
{
try
{
LOGGER.info(getClass().getSimpleName() + ": Loading " + geoFilePath.getFileName() + "...");
_driver.loadRegion(geoFilePath, regionX, regionY);
loadedRegions++;
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Failed to load " + geoFilePath.getFileName() + "!", e);
}
}
}
}
}
catch (Exception e)
{
LOGGER.log(Level.SEVERE, getClass().getSimpleName() + ": Failed to load geodata!", e);
System.exit(1);
}
LOGGER.info(getClass().getSimpleName() + ": Loaded " + loadedRegions + " regions.");
}
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 getGeoZ(int worldZ)
{
return _driver.getGeoZ(worldZ);
}
public int getWorldX(int geoX)
{
return _driver.getWorldX(geoX);
}
public int getWorldY(int geoY)
{
return _driver.getWorldY(geoY);
}
public int getWorldZ(int geoZ)
{
return _driver.getWorldZ(geoZ);
}
// ///////////////////
// 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;
}
final int nextLowerZ = getNextLowerZ(geoX, geoY, z + 100);
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 instanceof L2DoorInstance)
{
// can always see doors :o
return true;
}
return canSeeTarget(cha.getX(), cha.getY(), cha.getZ(), target.getX(), target.getY(), target.getZ());
}
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;
}
final 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();
final int prevZ = pointIter.z();
int prevGeoZ = prevZ;
int ptIndex = 0;
while (pointIter.next())
{
final int curX = pointIter.x();
final int curY = pointIter.y();
if ((curX == prevX) && (curY == prevY))
{
continue;
}
final int beeCurZ = pointIter.z();
int curGeoZ = prevGeoZ;
// check if the position has geodata
if (hasGeoPos(curX, curY))
{
final int beeCurGeoZ = getNearestZ(curX, curY, beeCurZ);
final 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)
{
final int northGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX, prevY - 1, Cell.NSWE_EAST);
final 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)
{
final int northGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX, prevY - 1, Cell.NSWE_WEST);
final 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)
{
final int southGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX, prevY + 1, Cell.NSWE_EAST);
final 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)
{
final int southGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX, prevY + 1, Cell.NSWE_WEST);
final 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;
}
/**
* 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
* @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)
{
final int geoX = getGeoX(x);
final int geoY = getGeoY(y);
z = getNearestZ(geoX, geoY, z);
final int tGeoX = getGeoX(tx);
final int tGeoY = getGeoY(ty);
tz = getNearestZ(tGeoX, tGeoY, tz);
if (DoorTable.getInstance().checkIfDoorsBetween(x, y, z, tx, ty, tz))
{
return new Location(x, y, getHeight(x, y, z));
}
final 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())
{
final int curX = pointIter.x();
final int curY = pointIter.y();
final int curZ = getNearestZ(curX, curY, prevZ);
if (hasGeoPos(prevX, prevY))
{
final 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
* @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)
{
final int geoX = getGeoX(fromX);
final int geoY = getGeoY(fromY);
fromZ = getNearestZ(geoX, geoY, fromZ);
final int tGeoX = getGeoX(toX);
final int tGeoY = getGeoY(toY);
toZ = getNearestZ(tGeoX, tGeoY, toZ);
if (DoorTable.getInstance().checkIfDoorsBetween(fromX, fromY, fromZ, toX, toY, toZ))
{
return false;
}
final 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())
{
final int curX = pointIter.x();
final int curY = pointIter.y();
final int curZ = getNearestZ(curX, curY, prevZ);
if (hasGeoPos(prevX, prevY))
{
final 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;
}
/**
* Checks if its possible to move from one location to another.
* @param from the {@code WorldObject} 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(L2Object from, int toX, int toY, int toZ)
{
return canMove(from.getX(), from.getY(), from.getZ(), toX, toY, toZ);
}
/**
* Checks if its possible to move from one location to another.
* @param from the {@code WorldObject} to start checking from
* @param to the {@code WorldObject} to end checking at
* @return {@code true} if the character at start coordinates can move to end coordinates, {@code false} otherwise
*/
public boolean canMove(L2Object from, L2Object 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 static final GeoData _instance = new GeoData();
}
}

View File

@@ -0,0 +1,48 @@
/*
* This file is part of the L2J Mobius project.
*
* 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.l2jmobius.gameserver.geodata.geodriver;
/**
* @author HorridoJoho
*/
public final class Cell
{
/** East NSWE flag */
public static final byte NSWE_EAST = 1 << 0;
/** West NSWE flag */
public static final byte NSWE_WEST = 1 << 1;
/** South NSWE flag */
public static final byte NSWE_SOUTH = 1 << 2;
/** North NSWE flag */
public static final byte NSWE_NORTH = 1 << 3;
/** North-East NSWE flags */
public static final byte NSWE_NORTH_EAST = NSWE_NORTH | NSWE_EAST;
/** North-West NSWE flags */
public static final byte NSWE_NORTH_WEST = NSWE_NORTH | NSWE_WEST;
/** South-East NSWE flags */
public static final byte NSWE_SOUTH_EAST = NSWE_SOUTH | NSWE_EAST;
/** South-West NSWE flags */
public static final byte NSWE_SOUTH_WEST = NSWE_SOUTH | NSWE_WEST;
/** All directions NSWE flags */
public static final byte NSWE_ALL = NSWE_EAST | NSWE_WEST | NSWE_SOUTH | NSWE_NORTH;
private Cell()
{
}
}

View File

@@ -0,0 +1,189 @@
/*
* This file is part of the L2J Mobius project.
*
* 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.l2jmobius.gameserver.geodata.geodriver;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel.MapMode;
import java.nio.file.Path;
import java.util.concurrent.atomic.AtomicReferenceArray;
import com.l2jmobius.gameserver.geodata.geodriver.regions.NullRegion;
import com.l2jmobius.gameserver.geodata.geodriver.regions.Region;
/**
* @author HorridoJoho
*/
public final class GeoDriver
{
// world dimensions: 1048576 * 1048576 = 1099511627776
private static final int WORLD_MIN_X = -655360;
private static final int WORLD_MAX_X = 393215;
private static final int WORLD_MIN_Y = -589824;
private static final int WORLD_MAX_Y = 458751;
private static final int WORLD_MIN_Z = -16384;
private static final int WORLD_MAX_Z = 16384;
/** Regions in the world on the x axis */
public static final int GEO_REGIONS_X = 32;
/** Regions in the world on the y axis */
public static final int GEO_REGIONS_Y = 32;
/** Region in the world */
public static final int GEO_REGIONS = GEO_REGIONS_X * GEO_REGIONS_Y;
/** Blocks in the world on the x axis */
public static final int GEO_BLOCKS_X = GEO_REGIONS_X * IRegion.REGION_BLOCKS_X;
/** Blocks in the world on the y axis */
public static final int GEO_BLOCKS_Y = GEO_REGIONS_Y * IRegion.REGION_BLOCKS_Y;
/** Blocks in the world */
public static final int GEO_BLOCKS = GEO_REGIONS * IRegion.REGION_BLOCKS;
/** Cells in the world on the x axis */
public static final int GEO_CELLS_X = GEO_BLOCKS_X * IBlock.BLOCK_CELLS_X;
/** Cells in the world in the y axis */
public static final int GEO_CELLS_Y = GEO_BLOCKS_Y * IBlock.BLOCK_CELLS_Y;
/** Cells in the world in the z axis */
public static final int GEO_CELLS_Z = (Math.abs(WORLD_MIN_Z) + Math.abs(WORLD_MAX_Z)) / 16;
/** The regions array */
private final AtomicReferenceArray<IRegion> _regions = new AtomicReferenceArray<>(GEO_REGIONS);
public GeoDriver()
{
for (int i = 0; i < _regions.length(); i++)
{
_regions.set(i, NullRegion.INSTANCE);
}
}
private void checkGeoX(int geoX)
{
if ((geoX < 0) || (geoX >= GEO_CELLS_X))
{
throw new IllegalArgumentException();
}
}
private void checkGeoY(int geoY)
{
if ((geoY < 0) || (geoY >= GEO_CELLS_Y))
{
throw new IllegalArgumentException();
}
}
private void checkGeoZ(int geoZ)
{
if ((geoZ < 0) || (geoZ >= GEO_CELLS_Z))
{
throw new IllegalArgumentException();
}
}
private IRegion getRegion(int geoX, int geoY)
{
checkGeoX(geoX);
checkGeoY(geoY);
return _regions.get(((geoX / IRegion.REGION_CELLS_X) * GEO_REGIONS_Y) + (geoY / IRegion.REGION_CELLS_Y));
}
public void loadRegion(Path filePath, int regionX, int regionY) throws IOException
{
final int regionOffset = (regionX * GEO_REGIONS_Y) + regionY;
try (RandomAccessFile raf = new RandomAccessFile(filePath.toFile(), "r"))
{
_regions.set(regionOffset, new Region(raf.getChannel().map(MapMode.READ_ONLY, 0, raf.length()).load().order(ByteOrder.LITTLE_ENDIAN)));
}
}
public void unloadRegion(int regionX, int regionY)
{
_regions.set((regionX * GEO_REGIONS_Y) + regionY, NullRegion.INSTANCE);
}
public boolean hasGeoPos(int geoX, int geoY)
{
return getRegion(geoX, geoY).hasGeo();
}
public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe)
{
return getRegion(geoX, geoY).checkNearestNswe(geoX, geoY, worldZ, nswe);
}
public int getNearestZ(int geoX, int geoY, int worldZ)
{
return getRegion(geoX, geoY).getNearestZ(geoX, geoY, worldZ);
}
public int getNextLowerZ(int geoX, int geoY, int worldZ)
{
return getRegion(geoX, geoY).getNextLowerZ(geoX, geoY, worldZ);
}
public int getNextHigherZ(int geoX, int geoY, int worldZ)
{
return getRegion(geoX, geoY).getNextHigherZ(geoX, geoY, worldZ);
}
public int getGeoX(int worldX)
{
if ((worldX < WORLD_MIN_X) || (worldX > WORLD_MAX_X))
{
throw new IllegalArgumentException();
}
return (worldX - WORLD_MIN_X) / 16;
}
public int getGeoY(int worldY)
{
if ((worldY < WORLD_MIN_Y) || (worldY > WORLD_MAX_Y))
{
throw new IllegalArgumentException();
}
return (worldY - WORLD_MIN_Y) / 16;
}
public int getGeoZ(int worldZ)
{
if ((worldZ < WORLD_MIN_Z) || (worldZ > WORLD_MAX_Z))
{
throw new IllegalArgumentException();
}
return (worldZ - WORLD_MIN_Z) / 16;
}
public int getWorldX(int geoX)
{
checkGeoX(geoX);
return (geoX * 16) + WORLD_MIN_X + 8;
}
public int getWorldY(int geoY)
{
checkGeoY(geoY);
return (geoY * 16) + WORLD_MIN_Y + 8;
}
public int getWorldZ(int geoZ)
{
checkGeoZ(geoZ);
return (geoZ * 16) + WORLD_MIN_Z + 8;
}
}

View File

@@ -0,0 +1,42 @@
/*
* This file is part of the L2J Mobius project.
*
* 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.l2jmobius.gameserver.geodata.geodriver;
/**
* @author HorridoJoho
*/
public interface IBlock
{
int TYPE_FLAT = 0;
int TYPE_COMPLEX = 1;
int TYPE_MULTILAYER = 2;
/** Cells in a block on the x axis */
int BLOCK_CELLS_X = 8;
/** Cells in a block on the y axis */
int BLOCK_CELLS_Y = 8;
/** Cells in a block */
int BLOCK_CELLS = BLOCK_CELLS_X * BLOCK_CELLS_Y;
boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe);
int getNearestZ(int geoX, int geoY, int worldZ);
int getNextLowerZ(int geoX, int geoY, int worldZ);
int getNextHigherZ(int geoX, int geoY, int worldZ);
}

View File

@@ -0,0 +1,47 @@
/*
* This file is part of the L2J Mobius project.
*
* 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.l2jmobius.gameserver.geodata.geodriver;
/**
* @author HorridoJoho
*/
public interface IRegion
{
/** Blocks in a region on the x axis. */
int REGION_BLOCKS_X = 256;
/** Blocks in a region on the y axis. */
int REGION_BLOCKS_Y = 256;
/** Blocks in a region. */
int REGION_BLOCKS = REGION_BLOCKS_X * REGION_BLOCKS_Y;
/** Cells in a region on the x axis. */
int REGION_CELLS_X = REGION_BLOCKS_X * IBlock.BLOCK_CELLS_X;
/** Cells in a regioin on the y axis. */
int REGION_CELLS_Y = REGION_BLOCKS_Y * IBlock.BLOCK_CELLS_Y;
/** Cells in a region. */
int REGION_CELLS = REGION_CELLS_X * REGION_CELLS_Y;
boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe);
int getNearestZ(int geoX, int geoY, int worldZ);
int getNextLowerZ(int geoX, int geoY, int worldZ);
int getNextHigherZ(int geoX, int geoY, int worldZ);
boolean hasGeo();
}

View File

@@ -0,0 +1,79 @@
/*
* This file is part of the L2J Mobius project.
*
* 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.l2jmobius.gameserver.geodata.geodriver.blocks;
import java.nio.ByteBuffer;
import com.l2jmobius.gameserver.geodata.geodriver.IBlock;
/**
* @author HorridoJoho
*/
public final class ComplexBlock implements IBlock
{
private final short[] _data;
public ComplexBlock(ByteBuffer bb)
{
_data = new short[IBlock.BLOCK_CELLS];
for (int cellOffset = 0; cellOffset < IBlock.BLOCK_CELLS; cellOffset++)
{
_data[cellOffset] = bb.getShort();
}
}
private short _getCellData(int geoX, int geoY)
{
return _data[((geoX % IBlock.BLOCK_CELLS_X) * IBlock.BLOCK_CELLS_Y) + (geoY % IBlock.BLOCK_CELLS_Y)];
}
private byte _getCellNSWE(int geoX, int geoY)
{
return (byte) (_getCellData(geoX, geoY) & 0x000F);
}
private int _getCellHeight(int geoX, int geoY)
{
return (short) (_getCellData(geoX, geoY) & 0x0FFF0) >> 1;
}
@Override
public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe)
{
return (_getCellNSWE(geoX, geoY) & nswe) == nswe;
}
@Override
public int getNearestZ(int geoX, int geoY, int worldZ)
{
return _getCellHeight(geoX, geoY);
}
@Override
public int getNextLowerZ(int geoX, int geoY, int worldZ)
{
final int cellHeight = _getCellHeight(geoX, geoY);
return cellHeight <= worldZ ? cellHeight : worldZ;
}
@Override
public int getNextHigherZ(int geoX, int geoY, int worldZ)
{
final int cellHeight = _getCellHeight(geoX, geoY);
return cellHeight >= worldZ ? cellHeight : worldZ;
}
}

View File

@@ -0,0 +1,58 @@
/*
* This file is part of the L2J Mobius project.
*
* 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.l2jmobius.gameserver.geodata.geodriver.blocks;
import java.nio.ByteBuffer;
import com.l2jmobius.gameserver.geodata.geodriver.IBlock;
/**
* @author HorridoJoho
*/
public class FlatBlock implements IBlock
{
private final short _height;
public FlatBlock(ByteBuffer bb)
{
_height = bb.getShort();
}
@Override
public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe)
{
return true;
}
@Override
public int getNearestZ(int geoX, int geoY, int worldZ)
{
return _height;
}
@Override
public int getNextLowerZ(int geoX, int geoY, int worldZ)
{
return _height <= worldZ ? _height : worldZ;
}
@Override
public int getNextHigherZ(int geoX, int geoY, int worldZ)
{
return _height >= worldZ ? _height : worldZ;
}
}

View File

@@ -0,0 +1,186 @@
/*
* This file is part of the L2J Mobius project.
*
* 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.l2jmobius.gameserver.geodata.geodriver.blocks;
import java.nio.ByteBuffer;
import com.l2jmobius.gameserver.geodata.geodriver.IBlock;
/**
* @author HorridoJoho
*/
public class MultilayerBlock implements IBlock
{
private final byte[] _data;
/**
* Initializes a new instance of this block reading the specified buffer.
* @param bb the buffer
*/
public MultilayerBlock(ByteBuffer bb)
{
final int start = bb.position();
for (int blockCellOffset = 0; blockCellOffset < IBlock.BLOCK_CELLS; blockCellOffset++)
{
final byte nLayers = bb.get();
if ((nLayers <= 0) || (nLayers > 125))
{
throw new RuntimeException("L2JGeoDriver: Geo file corrupted! Invalid layers count!");
}
bb.position(bb.position() + (nLayers * 2));
}
_data = new byte[bb.position() - start];
bb.position(start);
bb.get(_data);
}
private short _getNearestLayer(int geoX, int geoY, int worldZ)
{
final int startOffset = _getCellDataOffset(geoX, geoY);
final byte nLayers = _data[startOffset];
final int endOffset = startOffset + 1 + (nLayers * 2);
// 1 layer at least was required on loading so this is set at least once on the loop below
int nearestDZ = 0;
short nearestData = 0;
for (int offset = startOffset + 1; offset < endOffset; offset += 2)
{
final short layerData = _extractLayerData(offset);
final int layerZ = _extractLayerHeight(layerData);
if (layerZ == worldZ)
{
// exact z
return layerData;
}
final int layerDZ = Math.abs(layerZ - worldZ);
if ((offset == (startOffset + 1)) || (layerDZ < nearestDZ))
{
nearestDZ = layerDZ;
nearestData = layerData;
}
}
return nearestData;
}
private int _getCellDataOffset(int geoX, int geoY)
{
final int cellLocalOffset = ((geoX % IBlock.BLOCK_CELLS_X) * IBlock.BLOCK_CELLS_Y) + (geoY % IBlock.BLOCK_CELLS_Y);
int cellDataOffset = 0;
// move index to cell, we need to parse on each request, OR we parse on creation and save indexes
for (int i = 0; i < cellLocalOffset; i++)
{
cellDataOffset += 1 + (_data[cellDataOffset] * 2);
}
// now the index points to the cell we need
return cellDataOffset;
}
private short _extractLayerData(int dataOffset)
{
return (short) ((_data[dataOffset] & 0xFF) | (_data[dataOffset + 1] << 8));
}
private int _getNearestNSWE(int geoX, int geoY, int worldZ)
{
return _extractLayerNswe(_getNearestLayer(geoX, geoY, worldZ));
}
private int _extractLayerNswe(short layer)
{
return (byte) (layer & 0x000F);
}
private int _extractLayerHeight(short layer)
{
layer = (short) (layer & 0x0fff0);
return layer >> 1;
}
@Override
public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe)
{
return (_getNearestNSWE(geoX, geoY, worldZ) & nswe) == nswe;
}
@Override
public int getNearestZ(int geoX, int geoY, int worldZ)
{
return _extractLayerHeight(_getNearestLayer(geoX, geoY, worldZ));
}
@Override
public int getNextLowerZ(int geoX, int geoY, int worldZ)
{
final int startOffset = _getCellDataOffset(geoX, geoY);
final byte nLayers = _data[startOffset];
final int endOffset = startOffset + 1 + (nLayers * 2);
int lowerZ = Integer.MIN_VALUE;
for (int offset = startOffset + 1; offset < endOffset; offset += 2)
{
final short layerData = _extractLayerData(offset);
final int layerZ = _extractLayerHeight(layerData);
if (layerZ == worldZ)
{
// exact z
return layerZ;
}
if ((layerZ < worldZ) && (layerZ > lowerZ))
{
lowerZ = layerZ;
}
}
return lowerZ == Integer.MIN_VALUE ? worldZ : lowerZ;
}
@Override
public int getNextHigherZ(int geoX, int geoY, int worldZ)
{
final int startOffset = _getCellDataOffset(geoX, geoY);
final byte nLayers = _data[startOffset];
final int endOffset = startOffset + 1 + (nLayers * 2);
int higherZ = Integer.MAX_VALUE;
for (int offset = startOffset + 1; offset < endOffset; offset += 2)
{
final short layerData = _extractLayerData(offset);
final int layerZ = _extractLayerHeight(layerData);
if (layerZ == worldZ)
{
// exact z
return layerZ;
}
if ((layerZ > worldZ) && (layerZ < higherZ))
{
higherZ = layerZ;
}
}
return higherZ == Integer.MAX_VALUE ? worldZ : higherZ;
}
}

View File

@@ -14,50 +14,44 @@
* 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.l2jmobius.gameserver.pathfinding.utils;
package com.l2jmobius.gameserver.geodata.geodriver.regions;
import com.l2jmobius.gameserver.pathfinding.AbstractNode;
import com.l2jmobius.gameserver.geodata.geodriver.IRegion;
/**
* @author -Nemesiss-
* @author HorridoJoho
*/
public class FastNodeList
public final class NullRegion implements IRegion
{
private final AbstractNode[] _list;
private int _size;
public static final NullRegion INSTANCE = new NullRegion();
public FastNodeList(int size)
{
_list = new AbstractNode[size];
}
public void add(AbstractNode n)
{
_list[_size] = n;
_size++;
}
public boolean contains(AbstractNode n)
{
for (int i = 0; i < _size; i++)
{
if (_list[i].equals(n))
@Override
public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe)
{
return true;
}
}
return false;
@Override
public int getNearestZ(int geoX, int geoY, int worldZ)
{
return worldZ;
}
public boolean containsRev(AbstractNode n)
@Override
public int getNextLowerZ(int geoX, int geoY, int worldZ)
{
for (int i = _size - 1; i >= 0; i--)
{
if (_list[i].equals(n))
{
return true;
return worldZ;
}
@Override
public int getNextHigherZ(int geoX, int geoY, int worldZ)
{
return worldZ;
}
@Override
public boolean hasGeo()
{
return false;
}
}

View File

@@ -0,0 +1,98 @@
/*
* This file is part of the L2J Mobius project.
*
* 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.l2jmobius.gameserver.geodata.geodriver.regions;
import java.nio.ByteBuffer;
import com.l2jmobius.gameserver.geodata.geodriver.IBlock;
import com.l2jmobius.gameserver.geodata.geodriver.IRegion;
import com.l2jmobius.gameserver.geodata.geodriver.blocks.ComplexBlock;
import com.l2jmobius.gameserver.geodata.geodriver.blocks.FlatBlock;
import com.l2jmobius.gameserver.geodata.geodriver.blocks.MultilayerBlock;
/**
* @author HorridoJoho
*/
public final class Region implements IRegion
{
private final IBlock[] _blocks = new IBlock[IRegion.REGION_BLOCKS];
public Region(ByteBuffer bb)
{
for (int blockOffset = 0; blockOffset < IRegion.REGION_BLOCKS; blockOffset++)
{
final int blockType = bb.get();
switch (blockType)
{
case IBlock.TYPE_FLAT:
{
_blocks[blockOffset] = new FlatBlock(bb);
break;
}
case IBlock.TYPE_COMPLEX:
{
_blocks[blockOffset] = new ComplexBlock(bb);
break;
}
case IBlock.TYPE_MULTILAYER:
{
_blocks[blockOffset] = new MultilayerBlock(bb);
break;
}
default:
{
throw new RuntimeException("Invalid block type " + blockType + "!");
}
}
}
}
private IBlock getBlock(int geoX, int geoY)
{
return _blocks[(((geoX / IBlock.BLOCK_CELLS_X) % IRegion.REGION_BLOCKS_X) * IRegion.REGION_BLOCKS_Y) + ((geoY / IBlock.BLOCK_CELLS_Y) % IRegion.REGION_BLOCKS_Y)];
}
@Override
public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe)
{
return getBlock(geoX, geoY).checkNearestNswe(geoX, geoY, worldZ, nswe);
}
@Override
public int getNearestZ(int geoX, int geoY, int worldZ)
{
return getBlock(geoX, geoY).getNearestZ(geoX, geoY, worldZ);
}
@Override
public int getNextLowerZ(int geoX, int geoY, int worldZ)
{
return getBlock(geoX, geoY).getNextLowerZ(geoX, geoY, worldZ);
}
@Override
public int getNextHigherZ(int geoX, int geoY, int worldZ)
{
return getBlock(geoX, geoY).getNextHigherZ(geoX, geoY, worldZ);
}
@Override
public boolean hasGeo()
{
return true;
}
}

View File

@@ -14,41 +14,38 @@
* 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.l2jmobius.gameserver.pathfinding;
package com.l2jmobius.gameserver.geodata.pathfinding;
public abstract class AbstractNode
public abstract class AbstractNode<T extends AbstractNodeLoc>
{
private AbstractNodeLoc _loc;
private AbstractNode _parent;
private T _loc;
private AbstractNode<T> _parent;
public AbstractNode(AbstractNodeLoc loc)
public AbstractNode(T loc)
{
_loc = loc;
}
public void setParent(AbstractNode p)
public void setParent(AbstractNode<T> p)
{
_parent = p;
}
public AbstractNode getParent()
public AbstractNode<T> getParent()
{
return _parent;
}
public AbstractNodeLoc getLoc()
public T getLoc()
{
return _loc;
}
public void setLoc(AbstractNodeLoc l)
public void setLoc(T l)
{
_loc = l;
}
/**
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode()
{
@@ -58,9 +55,6 @@ public abstract class AbstractNode
return result;
}
/**
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj)
{
@@ -76,7 +70,7 @@ public abstract class AbstractNode
{
return false;
}
final AbstractNode other = (AbstractNode) obj;
final AbstractNode<?> other = (AbstractNode<?>) obj;
if (_loc == null)
{
if (other._loc != null)

View File

@@ -14,7 +14,7 @@
* 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.l2jmobius.gameserver.pathfinding;
package com.l2jmobius.gameserver.geodata.pathfinding;
/**
* @author -Nemesiss-
@@ -27,8 +27,6 @@ public abstract class AbstractNodeLoc
public abstract int getZ();
public abstract void setZ(short z);
public abstract int getNodeX();
public abstract int getNodeY();

View File

@@ -0,0 +1,210 @@
/*
* This file is part of the L2J Mobius project.
*
* 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.l2jmobius.gameserver.geodata.pathfinding;
import java.util.List;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.geodata.pathfinding.cellnodes.CellPathFinding;
import com.l2jmobius.gameserver.geodata.pathfinding.geonodes.GeoPathFinding;
import com.l2jmobius.gameserver.model.L2World;
/**
* @author -Nemesiss-
*/
public abstract class PathFinding
{
public static PathFinding getInstance()
{
if (Config.PATHFINDING == 1)
{
// Higher Memory Usage, Smaller Cpu Usage
return GeoPathFinding.getInstance();
}
// Cell pathfinding, calculated directly from geodata files
return CellPathFinding.getInstance();
}
public abstract boolean pathNodesExist(short regionoffset);
public abstract List<AbstractNodeLoc> findPath(int x, int y, int z, int tx, int ty, int tz, boolean playable);
// @formatter:off
/*
public List<AbstractNodeLoc> search(AbstractNode start, AbstractNode end, int instanceId)
{
// The simplest grid-based pathfinding.
// Drawback is not having higher cost for diagonal movement (means funny routes)
// Could be optimized e.g. not to calculate backwards as far as forwards.
// List of Visited Nodes
LinkedList<AbstractNode> visited = new LinkedList<AbstractNode>();
// List of Nodes to Visit
LinkedList<AbstractNode> to_visit = new LinkedList<AbstractNode>();
to_visit.add(start);
int i = 0;
while (i < 800)
{
AbstractNode node;
try
{
node = to_visit.removeFirst();
}
catch (Exception e)
{
// No Path found
return null;
}
if (node.equals(end)) //path found!
return constructPath(node, instanceId);
else
{
i++;
visited.add(node);
node.attachNeighbors();
Node[] neighbors = node.getNeighbors();
if (neighbors == null)
continue;
for (Node n : neighbors)
{
if (!visited.contains(n) && !to_visit.contains(n))
{
n.setParent(node);
to_visit.add(n);
}
}
}
}
//No Path found
return null;
}
*/
/*
public List<AbstractNodeLoc> searchAStar(Node start, Node end, int instanceId)
{
// Not operational yet?
int start_x = start.getLoc().getX();
int start_y = start.getLoc().getY();
int end_x = end.getLoc().getX();
int end_y = end.getLoc().getY();
//List of Visited Nodes
FastNodeList visited = new FastNodeList(800);//TODO! Add limit to cfg
// List of Nodes to Visit
BinaryNodeHeap to_visit = new BinaryNodeHeap(800);
to_visit.add(start);
int i = 0;
while (i < 800)//TODO! Add limit to cfg
{
AbstractNode node;
try
{
node = to_visit.removeFirst();
}
catch (Exception e)
{
// No Path found
return null;
}
if (node.equals(end)) //path found!
return constructPath(node, instanceId);
else
{
visited.add(node);
node.attachNeighbors();
for (Node n : node.getNeighbors())
{
if (!visited.contains(n) && !to_visit.contains(n))
{
i++;
n.setParent(node);
n.setCost(Math.abs(start_x - n.getLoc().getNodeX()) + Math.abs(start_y - n.getLoc().getNodeY())
+ Math.abs(end_x - n.getLoc().getNodeX()) + Math.abs(end_y - n.getLoc().getNodeY()));
to_visit.add(n);
}
}
}
}
//No Path found
return null;
}
*/
// @formatter:on
/**
* Convert geodata position to pathnode position
* @param geo_pos
* @return pathnode position
*/
public short getNodePos(int geo_pos)
{
return (short) (geo_pos >> 3); // OK?
}
/**
* Convert node position to pathnode block position
* @param node_pos
* @return pathnode block position (0...255)
*/
public short getNodeBlock(int node_pos)
{
return (short) (node_pos % 256);
}
public byte getRegionX(int node_pos)
{
return (byte) ((node_pos >> 8) + L2World.TILE_X_MIN);
}
public byte getRegionY(int node_pos)
{
return (byte) ((node_pos >> 8) + L2World.TILE_Y_MIN);
}
public short getRegionOffset(byte rx, byte ry)
{
return (short) ((rx << 5) + ry);
}
/**
* Convert pathnode x to World x position
* @param node_x rx
* @return
*/
public int calculateWorldX(short node_x)
{
return L2World.MAP_MIN_X + (node_x * 128) + 48;
}
/**
* Convert pathnode y to World y position
* @param node_y
* @return
*/
public int calculateWorldY(short node_y)
{
return L2World.MAP_MIN_Y + (node_y * 128) + 48;
}
public String[] getStat()
{
return null;
}
}

View File

@@ -14,18 +14,17 @@
* 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.l2jmobius.gameserver.pathfinding.cellnodes;
package com.l2jmobius.gameserver.geodata.pathfinding.cellnodes;
import com.l2jmobius.gameserver.pathfinding.AbstractNode;
import com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc;
import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNode;
public class CellNode extends AbstractNode
public class CellNode extends AbstractNode<NodeLoc>
{
private CellNode _next = null;
private boolean _isInUse = true;
private float _cost = -1000;
public CellNode(AbstractNodeLoc loc)
public CellNode(NodeLoc loc)
{
super(loc);
}

View File

@@ -14,14 +14,14 @@
* 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.l2jmobius.gameserver.pathfinding.cellnodes;
package com.l2jmobius.gameserver.geodata.pathfinding.cellnodes;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import com.l2jmobius.Config;
import javolution.util.FastList;
/**
* @author DS Credits to Diamond
*/
@@ -111,9 +111,9 @@ public class CellNodeBuffer
return _lastElapsedTime;
}
public final FastList<CellNode> debugPath()
public final List<CellNode> debugPath()
{
final FastList<CellNode> result = new FastList<>();
final List<CellNode> result = new LinkedList<>();
for (CellNode n = _current; n.getParent() != null; n = (CellNode) n.getParent())
{
@@ -138,9 +138,9 @@ public class CellNodeBuffer
return result;
}
private final void getNeighbors()
private void getNeighbors()
{
if (((NodeLoc) _current.getLoc()).canGoNone())
if (!_current.getLoc().canGoAll())
{
return;
}
@@ -155,25 +155,25 @@ public class CellNodeBuffer
CellNode nodeN = null;
// East
if (((NodeLoc) _current.getLoc()).canGoEast())
if (_current.getLoc().canGoEast())
{
nodeE = addNode(x + 1, y, z, false);
}
// South
if (((NodeLoc) _current.getLoc()).canGoSouth())
if (_current.getLoc().canGoSouth())
{
nodeS = addNode(x, y + 1, z, false);
}
// West
if (((NodeLoc) _current.getLoc()).canGoWest())
if (_current.getLoc().canGoWest())
{
nodeW = addNode(x - 1, y, z, false);
}
// North
if (((NodeLoc) _current.getLoc()).canGoNorth())
if (_current.getLoc().canGoNorth())
{
nodeN = addNode(x, y - 1, z, false);
}
@@ -183,7 +183,7 @@ public class CellNodeBuffer
// SouthEast
if ((nodeE != null) && (nodeS != null))
{
if (((NodeLoc) nodeE.getLoc()).canGoSouth() && ((NodeLoc) nodeS.getLoc()).canGoEast())
if (nodeE.getLoc().canGoSouth() && nodeS.getLoc().canGoEast())
{
addNode(x + 1, y + 1, z, true);
}
@@ -192,7 +192,7 @@ public class CellNodeBuffer
// SouthWest
if ((nodeS != null) && (nodeW != null))
{
if (((NodeLoc) nodeW.getLoc()).canGoSouth() && ((NodeLoc) nodeS.getLoc()).canGoWest())
if (nodeW.getLoc().canGoSouth() && nodeS.getLoc().canGoWest())
{
addNode(x - 1, y + 1, z, true);
}
@@ -201,7 +201,7 @@ public class CellNodeBuffer
// NorthEast
if ((nodeN != null) && (nodeE != null))
{
if (((NodeLoc) nodeE.getLoc()).canGoNorth() && ((NodeLoc) nodeN.getLoc()).canGoEast())
if (nodeE.getLoc().canGoNorth() && nodeN.getLoc().canGoEast())
{
addNode(x + 1, y - 1, z, true);
}
@@ -210,7 +210,7 @@ public class CellNodeBuffer
// NorthWest
if ((nodeN != null) && (nodeW != null))
{
if (((NodeLoc) nodeW.getLoc()).canGoNorth() && ((NodeLoc) nodeN.getLoc()).canGoWest())
if (nodeW.getLoc().canGoNorth() && nodeN.getLoc().canGoWest())
{
addNode(x - 1, y - 1, z, true);
}
@@ -218,7 +218,7 @@ public class CellNodeBuffer
}
}
private final CellNode getNode(int x, int y, int z)
private CellNode getNode(int x, int y, int z)
{
final int aX = x - _baseX;
if ((aX < 0) || (aX >= _mapSize))
@@ -244,7 +244,7 @@ public class CellNodeBuffer
// reinit node if needed
if (result.getLoc() != null)
{
((NodeLoc) result.getLoc()).set(x, y, z);
result.getLoc().set(x, y, z);
}
else
{
@@ -255,7 +255,7 @@ public class CellNodeBuffer
return result;
}
private final CellNode addNode(int x, int y, int z, boolean diagonal)
private CellNode addNode(int x, int y, int z, boolean diagonal)
{
final CellNode newNode = getNode(x, y, z);
if (newNode == null)
@@ -272,13 +272,11 @@ public class CellNodeBuffer
final int stepZ = Math.abs(geoZ - _current.getLoc().getZ());
float weight = diagonal ? Config.DIAGONAL_WEIGHT : Config.LOW_WEIGHT;
if (!((NodeLoc) newNode.getLoc()).canGoAll() || (stepZ > 16))
if (!newNode.getLoc().canGoAll() || (stepZ > 16))
{
weight = Config.HIGH_WEIGHT;
}
else
{
if (isHighWeight(x + 1, y, geoZ))
else if (isHighWeight(x + 1, y, geoZ))
{
weight = Config.MEDIUM_WEIGHT;
}
@@ -294,7 +292,6 @@ public class CellNodeBuffer
{
weight = Config.MEDIUM_WEIGHT;
}
}
newNode.setParent(_current);
newNode.setCost(getCost(x, y, geoZ, weight));
@@ -322,7 +319,7 @@ public class CellNodeBuffer
return newNode;
}
private final boolean isHighWeight(int x, int y, int z)
private boolean isHighWeight(int x, int y, int z)
{
final CellNode result = getNode(x, y, z);
if (result == null)
@@ -330,7 +327,7 @@ public class CellNodeBuffer
return true;
}
if (!((NodeLoc) result.getLoc()).canGoAll())
if (!result.getLoc().canGoAll())
{
return true;
}
@@ -342,13 +339,13 @@ public class CellNodeBuffer
return false;
}
private final double getCost(int x, int y, int z, float weight)
private double getCost(int x, int y, int z, float weight)
{
final int dX = x - _targetX;
final int dY = y - _targetY;
final int dZ = z - _targetZ;
// Math.abs(dx) + Math.abs(dy) + Math.abs(dz) / 16
double result = Math.sqrt((dX * dX) + (dY * dY) + ((dZ * dZ) / 256));
double result = Math.sqrt((dX * dX) + (dY * dY) + ((dZ * dZ) / 256.0));
if (result > weight)
{
result += weight;

View File

@@ -14,23 +14,24 @@
* 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.l2jmobius.gameserver.pathfinding.cellnodes;
package com.l2jmobius.gameserver.geodata.pathfinding.cellnodes;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNode;
import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNodeLoc;
import com.l2jmobius.gameserver.geodata.pathfinding.PathFinding;
import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.model.Inventory;
import com.l2jmobius.gameserver.model.L2ItemInstance;
import com.l2jmobius.gameserver.pathfinding.AbstractNode;
import com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc;
import com.l2jmobius.gameserver.pathfinding.PathFinding;
import com.l2jmobius.util.StringUtil;
import javolution.util.FastList;
/**
* @author Sami, DS Credits to Diamond
@@ -46,20 +47,14 @@ public class CellPathFinding extends PathFinding
private int _postFilterPasses = 0;
private long _postFilterElapsed = 0;
private FastList<L2ItemInstance> _debugItems = null;
private static CellPathFinding _instance;
private List<L2ItemInstance> _debugItems = null;
public static CellPathFinding getInstance()
{
if (_instance == null)
{
_instance = new CellPathFinding();
}
return _instance;
return SingletonHolder._instance;
}
private CellPathFinding()
protected CellPathFinding()
{
try
{
@@ -81,16 +76,13 @@ public class CellPathFinding extends PathFinding
_allBuffers[i] = new BufferInfo(Integer.parseInt(args[0]), Integer.parseInt(args[1]));
}
}
catch (final Exception e)
catch (Exception e)
{
_log.warning("CellPathFinding: Problem during buffer init: " + e.getMessage());
_log.log(Level.WARNING, "CellPathFinding: Problem during buffer init: " + e.getMessage(), e);
throw new Error("CellPathFinding: load aborted");
}
}
/**
* @see com.l2jmobius.gameserver.pathfinding.PathFinding#pathNodesExist(short)
*/
@Override
public boolean pathNodesExist(short regionoffset)
{
@@ -126,11 +118,11 @@ public class CellPathFinding extends PathFinding
{
if (_debugItems == null)
{
_debugItems = new FastList<>();
_debugItems = new CopyOnWriteArrayList<>();
}
else
{
for (final L2ItemInstance item : _debugItems)
for (L2ItemInstance item : _debugItems)
{
if (item == null)
{
@@ -143,14 +135,14 @@ public class CellPathFinding extends PathFinding
}
}
FastList<AbstractNodeLoc> path = null;
List<AbstractNodeLoc> path = null;
try
{
final CellNode result = buffer.findPath(gx, gy, gz, gtx, gty, gtz);
if (debug)
{
for (final CellNode n : buffer.debugPath())
for (CellNode n : buffer.debugPath())
{
if (n.getCost() < 0)
{
@@ -158,7 +150,8 @@ public class CellPathFinding extends PathFinding
}
else
{
dropDebugItem(57, (int) (n.getCost() * 10), n.getLoc());
// known nodes
dropDebugItem(Inventory.ADENA_ID, (int) (n.getCost() * 10), n.getLoc());
}
}
}
@@ -171,9 +164,9 @@ public class CellPathFinding extends PathFinding
path = constructPath(result);
}
catch (final Exception e)
catch (Exception e)
{
e.printStackTrace();
_log.log(Level.WARNING, "", e);
return null;
}
finally
@@ -195,8 +188,7 @@ public class CellPathFinding extends PathFinding
}
int currentX, currentY, currentZ;
ListIterator<AbstractNodeLoc> middlePoint, endPoint;
AbstractNodeLoc locMiddle, locEnd;
ListIterator<AbstractNodeLoc> middlePoint;
boolean remove;
int pass = 0;
do
@@ -206,16 +198,19 @@ public class CellPathFinding extends PathFinding
remove = false;
middlePoint = path.listIterator();
endPoint = path.listIterator(1);
locEnd = null;
currentX = x;
currentY = y;
currentZ = z;
while (endPoint.hasNext())
while (middlePoint.hasNext())
{
locEnd = endPoint.next();
locMiddle = middlePoint.next();
final AbstractNodeLoc locMiddle = middlePoint.next();
if (!middlePoint.hasNext())
{
break;
}
final AbstractNodeLoc locEnd = path.get(middlePoint.nextIndex());
if (GeoData.getInstance().canMove(currentX, currentY, currentZ, locEnd.getX(), locEnd.getY(), locEnd.getZ()))
{
middlePoint.remove();
@@ -238,12 +233,7 @@ public class CellPathFinding extends PathFinding
if (debug)
{
middlePoint = path.listIterator();
while (middlePoint.hasNext())
{
locMiddle = middlePoint.next();
dropDebugItem(65, 1, locMiddle);
}
path.forEach(n -> dropDebugItem(65, 1, n));
}
_findSuccess++;
@@ -251,9 +241,9 @@ public class CellPathFinding extends PathFinding
return path;
}
private FastList<AbstractNodeLoc> constructPath(AbstractNode node)
private List<AbstractNodeLoc> constructPath(AbstractNode<NodeLoc> node)
{
final FastList<AbstractNodeLoc> path = new FastList<>();
final LinkedList<AbstractNodeLoc> path = new LinkedList<>();
int previousDirectionX = Integer.MIN_VALUE;
int previousDirectionY = Integer.MIN_VALUE;
int directionX, directionY;
@@ -297,14 +287,14 @@ public class CellPathFinding extends PathFinding
return path;
}
private final CellNodeBuffer alloc(int size, boolean playable)
private CellNodeBuffer alloc(int size, boolean playable)
{
CellNodeBuffer current = null;
for (final BufferInfo i : _allBuffers)
for (BufferInfo i : _allBuffers)
{
if (i.mapSize >= size)
{
for (final CellNodeBuffer buf : i.bufs)
for (CellNodeBuffer buf : i.bufs)
{
if (buf.lock())
{
@@ -341,6 +331,7 @@ public class CellPathFinding extends PathFinding
if (playable)
{
i.playableOverflows++;
// System.err.println("Overflow, size requested: " + size + " playable:"+playable);
}
}
}
@@ -348,7 +339,7 @@ public class CellPathFinding extends PathFinding
return current;
}
private final void dropDebugItem(int itemId, int num, AbstractNodeLoc loc)
private void dropDebugItem(int itemId, int num, AbstractNodeLoc loc)
{
final L2ItemInstance item = new L2ItemInstance(IdFactory.getInstance().getNextId(), itemId);
item.setCount(num);
@@ -377,16 +368,32 @@ public class CellPathFinding extends PathFinding
@Override
public String toString()
{
final StringBuilder stat = new StringBuilder(100);
StringUtil.append(stat, String.valueOf(mapSize), "x", String.valueOf(mapSize), " num:", String.valueOf(bufs.size()), "/", String.valueOf(count), " uses:", String.valueOf(uses), "/", String.valueOf(playableUses));
final StringBuilder sb = new StringBuilder(100);
sb.append(mapSize);
sb.append("x");
sb.append(mapSize);
sb.append(" num:");
sb.append(bufs.size());
sb.append("/");
sb.append(count);
sb.append(" uses:");
sb.append(uses);
sb.append("/");
sb.append(playableUses);
if (uses > 0)
{
StringUtil.append(stat, " total/avg(ms):", String.valueOf(elapsed), "/", String.format("%1.2f", (double) elapsed / uses));
sb.append(" total/avg(ms):");
sb.append(elapsed);
sb.append("/");
sb.append(String.format("%1.2f", (double) elapsed / uses));
}
StringUtil.append(stat, " ovf:", String.valueOf(overflows), "/", String.valueOf(playableOverflows));
sb.append(" ovf:");
sb.append(overflows);
sb.append("/");
sb.append(playableOverflows);
return stat.toString();
return sb.toString();
}
}
@@ -399,15 +406,34 @@ public class CellPathFinding extends PathFinding
result[i] = _allBuffers[i].toString();
}
final StringBuilder stat = new StringBuilder(100);
StringUtil.append(stat, "LOS postfilter uses:", String.valueOf(_postFilterUses), "/", String.valueOf(_postFilterPlayableUses));
final StringBuilder sb = new StringBuilder(128);
sb.append("LOS postfilter uses:");
sb.append(_postFilterUses);
sb.append("/");
sb.append(_postFilterPlayableUses);
if (_postFilterUses > 0)
{
StringUtil.append(stat, " total/avg(ms):", String.valueOf(_postFilterElapsed), "/", String.format("%1.2f", (double) _postFilterElapsed / _postFilterUses), " passes total/avg:", String.valueOf(_postFilterPasses), "/", String.format("%1.1f", (double) _postFilterPasses / _postFilterUses), "\r\n");
sb.append(" total/avg(ms):");
sb.append(_postFilterElapsed);
sb.append("/");
sb.append(String.format("%1.2f", (double) _postFilterElapsed / _postFilterUses));
sb.append(" passes total/avg:");
sb.append(_postFilterPasses);
sb.append("/");
sb.append(String.format("%1.1f", (double) _postFilterPasses / _postFilterUses));
sb.append(Config.EOL);
}
StringUtil.append(stat, "Pathfind success/fail:", String.valueOf(_findSuccess), "/", String.valueOf(_findFails));
result[result.length - 1] = stat.toString();
sb.append("Pathfind success/fail:");
sb.append(_findSuccess);
sb.append("/");
sb.append(_findFails);
result[result.length - 1] = sb.toString();
return result;
}
private static class SingletonHolder
{
protected static final CellPathFinding _instance = new CellPathFinding();
}
}

View File

@@ -14,14 +14,14 @@
* 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.l2jmobius.gameserver.pathfinding.cellnodes;
package com.l2jmobius.gameserver.geodata.pathfinding.cellnodes;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc;
import com.l2jserver.gameserver.geoengine.Direction;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geodata.geodriver.Cell;
import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNodeLoc;
/**
* @author -Nemesiss-, FBIagent
* @author -Nemesiss-, HorridoJoho
*/
public class NodeLoc extends AbstractNodeLoc
{
@@ -42,10 +42,10 @@ public class NodeLoc extends AbstractNodeLoc
{
_x = x;
_y = y;
_goNorth = GeoData.getInstance().canEnterNeighbors(x, y, z, Direction.NORTH);
_goEast = GeoData.getInstance().canEnterNeighbors(x, y, z, Direction.EAST);
_goSouth = GeoData.getInstance().canEnterNeighbors(x, y, z, Direction.SOUTH);
_goWest = GeoData.getInstance().canEnterNeighbors(x, y, z, Direction.WEST);
_goNorth = GeoData.getInstance().checkNearestNswe(x, y, z, Cell.NSWE_NORTH);
_goEast = GeoData.getInstance().checkNearestNswe(x, y, z, Cell.NSWE_EAST);
_goSouth = GeoData.getInstance().checkNearestNswe(x, y, z, Cell.NSWE_SOUTH);
_goWest = GeoData.getInstance().checkNearestNswe(x, y, z, Cell.NSWE_WEST);
_geoHeight = GeoData.getInstance().getNearestZ(x, y, z);
}
@@ -69,70 +69,41 @@ public class NodeLoc extends AbstractNodeLoc
return _goWest;
}
public boolean canGoNone()
{
return !canGoNorth() && !canGoEast() && !canGoSouth() && !canGoWest();
}
public boolean canGoAll()
{
return canGoNorth() && canGoEast() && canGoSouth() && canGoWest();
}
/**
* @see com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc#getX()
*/
@Override
public int getX()
{
return GeoData.getInstance().getWorldX(_x);
}
/**
* @see com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc#getY()
*/
@Override
public int getY()
{
return GeoData.getInstance().getWorldY(_y);
}
/**
* @see com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc#getZ()
*/
@Override
public int getZ()
{
return _geoHeight;
}
@Override
public void setZ(short z)
{
// do nothing here
}
/**
* @see com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc#getNodeX()
*/
@Override
public int getNodeX()
{
return _x;
}
/**
* @see com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc#getNodeY()
*/
@Override
public int getNodeY()
{
return _y;
}
/**
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode()
{
@@ -141,31 +112,29 @@ public class NodeLoc extends AbstractNodeLoc
result = (prime * result) + _x;
result = (prime * result) + _y;
byte nswe = 0;
int nswe = 0;
if (canGoNorth())
{
nswe |= 1;
nswe |= Cell.NSWE_NORTH;
}
if (canGoEast())
{
nswe |= 1 << 1;
nswe |= Cell.NSWE_EAST;
}
if (canGoSouth())
{
nswe |= 1 << 2;
nswe |= Cell.NSWE_SOUTH;
}
if (canGoEast())
if (canGoWest())
{
nswe |= 1 << 3;
nswe |= Cell.NSWE_WEST;
}
result = (prime * result) + (((_geoHeight & 0xFFFF) << 1) | nswe);
return result;
// return super.hashCode();
}
/**
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj)
{

View File

@@ -14,21 +14,20 @@
* 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.l2jmobius.gameserver.pathfinding.geonodes;
package com.l2jmobius.gameserver.geodata.pathfinding.geonodes;
import com.l2jmobius.gameserver.pathfinding.AbstractNode;
import com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc;
import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNode;
/**
* @author -Nemesiss-
*/
public class GeoNode extends AbstractNode
public class GeoNode extends AbstractNode<GeoNodeLoc>
{
private final int _neighborsIdx;
private short _cost;
private GeoNode[] _neighbors;
public GeoNode(AbstractNodeLoc Loc, int Neighbors_idx)
public GeoNode(GeoNodeLoc Loc, int Neighbors_idx)
{
super(Loc);
_neighborsIdx = Neighbors_idx;

View File

@@ -14,10 +14,10 @@
* 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.l2jmobius.gameserver.pathfinding.geonodes;
package com.l2jmobius.gameserver.geodata.pathfinding.geonodes;
import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNodeLoc;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc;
/**
* @author -Nemesiss-
@@ -35,39 +35,24 @@ public class GeoNodeLoc extends AbstractNodeLoc
_z = z;
}
/**
* @see com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc#getX()
*/
@Override
public int getX()
{
return L2World.MAP_MIN_X + (_x * 128) + 48;
}
/**
* @see com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc#getY()
*/
@Override
public int getY()
{
return L2World.MAP_MIN_Y + (_y * 128) + 48;
}
/**
* @see com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc#getZ()
*/
@Override
public int getZ()
{
return _z;
}
@Override
public void setZ(short z)
{
// Overriden
}
@Override
public int getNodeX()
{
@@ -80,9 +65,6 @@ public class GeoNodeLoc extends AbstractNodeLoc
return _y;
}
/**
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode()
{
@@ -94,9 +76,6 @@ public class GeoNodeLoc extends AbstractNodeLoc
return result;
}
/**
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj)
{

View File

@@ -14,34 +14,34 @@
* 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.l2jmobius.gameserver.pathfinding.geonodes;
package com.l2jmobius.gameserver.geodata.pathfinding.geonodes;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.LineNumberReader;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNode;
import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNodeLoc;
import com.l2jmobius.gameserver.geodata.pathfinding.PathFinding;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.pathfinding.AbstractNode;
import com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc;
import com.l2jmobius.gameserver.pathfinding.PathFinding;
import com.l2jmobius.gameserver.pathfinding.utils.FastNodeList;
import javolution.util.FastList;
import javolution.util.FastMap;
import com.l2jmobius.gameserver.util.Util;
/**
* @author -Nemesiss-
@@ -49,26 +49,18 @@ import javolution.util.FastMap;
public class GeoPathFinding extends PathFinding
{
private static Logger _log = Logger.getLogger(GeoPathFinding.class.getName());
private static GeoPathFinding _instance;
private static Map<Short, ByteBuffer> pathNodes = new FastMap<>();
private static Map<Short, IntBuffer> pathNodes_index = new FastMap<>();
private static Map<Short, ByteBuffer> _pathNodes = new ConcurrentHashMap<>();
private static Map<Short, IntBuffer> _pathNodesIndex = new ConcurrentHashMap<>();
public static GeoPathFinding getInstance()
{
if (_instance == null)
{
_instance = new GeoPathFinding();
}
return _instance;
return SingletonHolder._instance;
}
/**
* @see com.l2jmobius.gameserver.pathfinding.PathFinding#pathNodesExist(short)
*/
@Override
public boolean pathNodesExist(short regionoffset)
{
return pathNodes_index.containsKey(regionoffset);
return _pathNodesIndex.containsKey(regionoffset);
}
@Override
@@ -83,7 +75,6 @@ public class GeoPathFinding extends PathFinding
final GeoNode start = readNode(gx, gy, gz);
final GeoNode end = readNode(gtx, gty, gtz);
if ((start == null) || (end == null))
{
return null;
@@ -100,18 +91,22 @@ public class GeoPathFinding extends PathFinding
{
return null;
}
// TODO: Find closest path node we CAN access. Now only checks if we can not reach the closest
Location temp = GeoData.getInstance().moveCheck(x, y, z, start.getLoc().getX(), start.getLoc().getY(), start.getLoc().getZ());
if ((temp.getX() != start.getLoc().getX()) || (temp.getY() != start.getLoc().getY()))
{
return null; // cannot reach closest...
}
// TODO: Find closest path node around target, now only checks if final location can be reached
temp = GeoData.getInstance().moveCheck(tx, ty, tz, end.getLoc().getX(), end.getLoc().getY(), end.getLoc().getZ());
if ((temp.getX() != end.getLoc().getX()) || (temp.getY() != end.getLoc().getY()))
{
return null; // cannot reach closest...
}
// return searchAStar(start, end);
return searchByClosest2(start, end);
}
@@ -127,7 +122,7 @@ public class GeoPathFinding extends PathFinding
// load) level of intelligence though.
// List of Visited Nodes
final FastNodeList visited = new FastNodeList(550);
final List<GeoNode> visited = new ArrayList<>(550);
// List of Nodes to Visit
final LinkedList<GeoNode> to_visit = new LinkedList<>();
@@ -145,12 +140,11 @@ public class GeoPathFinding extends PathFinding
{
node = to_visit.removeFirst();
}
catch (final Exception e)
catch (Exception e)
{
// No Path found
return null;
}
if (node.equals(end))
{
return constructPath2(node);
@@ -164,9 +158,9 @@ public class GeoPathFinding extends PathFinding
{
continue;
}
for (final GeoNode n : neighbors)
for (GeoNode n : neighbors)
{
if (!visited.containsRev(n) && !to_visit.contains(n))
if ((visited.lastIndexOf(n) == -1) && !to_visit.contains(n))
{
added = false;
n.setParent(node);
@@ -194,7 +188,7 @@ public class GeoPathFinding extends PathFinding
return null;
}
public List<AbstractNodeLoc> constructPath2(AbstractNode node)
public List<AbstractNodeLoc> constructPath2(AbstractNode<GeoNodeLoc> node)
{
final LinkedList<AbstractNodeLoc> path = new LinkedList<>();
int previousDirectionX = -1000;
@@ -223,18 +217,17 @@ public class GeoPathFinding extends PathFinding
{
final int node_x = n.getLoc().getNodeX();
final int node_y = n.getLoc().getNodeY();
// short node_z = n.getLoc().getZ();
final short regoffset = getRegionOffset(getRegionX(node_x), getRegionY(node_y));
final ByteBuffer pn = pathNodes.get(regoffset);
final List<AbstractNode> Neighbors = new FastList<>(8);
final ByteBuffer pn = _pathNodes.get(regoffset);
final List<AbstractNode<GeoNodeLoc>> Neighbors = new ArrayList<>(8);
GeoNode newNode;
short new_node_x, new_node_y;
// Region for sure will change, we must read from correct file
byte neighbor = pn.get(idx); // N
idx++;
byte neighbor = pn.get(idx++); // N
if (neighbor > 0)
{
neighbor--;
@@ -246,8 +239,7 @@ public class GeoPathFinding extends PathFinding
Neighbors.add(newNode);
}
}
neighbor = pn.get(idx); // NE
idx++;
neighbor = pn.get(idx++); // NE
if (neighbor > 0)
{
neighbor--;
@@ -259,8 +251,7 @@ public class GeoPathFinding extends PathFinding
Neighbors.add(newNode);
}
}
neighbor = pn.get(idx); // E
idx++;
neighbor = pn.get(idx++); // E
if (neighbor > 0)
{
neighbor--;
@@ -272,8 +263,7 @@ public class GeoPathFinding extends PathFinding
Neighbors.add(newNode);
}
}
neighbor = pn.get(idx); // SE
idx++;
neighbor = pn.get(idx++); // SE
if (neighbor > 0)
{
neighbor--;
@@ -285,8 +275,7 @@ public class GeoPathFinding extends PathFinding
Neighbors.add(newNode);
}
}
neighbor = pn.get(idx); // S
idx++;
neighbor = pn.get(idx++); // S
if (neighbor > 0)
{
neighbor--;
@@ -298,8 +287,7 @@ public class GeoPathFinding extends PathFinding
Neighbors.add(newNode);
}
}
neighbor = pn.get(idx); // SW
idx++;
neighbor = pn.get(idx++); // SW
if (neighbor > 0)
{
neighbor--;
@@ -311,8 +299,7 @@ public class GeoPathFinding extends PathFinding
Neighbors.add(newNode);
}
}
neighbor = pn.get(idx); // W
idx++;
neighbor = pn.get(idx++); // W
if (neighbor > 0)
{
neighbor--;
@@ -324,8 +311,7 @@ public class GeoPathFinding extends PathFinding
Neighbors.add(newNode);
}
}
neighbor = pn.get(idx); // NW
idx++;
neighbor = pn.get(idx++); // NW
if (neighbor > 0)
{
neighbor--;
@@ -341,6 +327,8 @@ public class GeoPathFinding extends PathFinding
return Neighbors.toArray(result);
}
// Private
private GeoNode readNode(short node_x, short node_y, byte layer)
{
final short regoffset = getRegionOffset(getRegionX(node_x), getRegionY(node_y));
@@ -350,11 +338,11 @@ public class GeoPathFinding extends PathFinding
}
final short nbx = getNodeBlock(node_x);
final short nby = getNodeBlock(node_y);
int idx = pathNodes_index.get(regoffset).get((nby << 8) + nbx);
final ByteBuffer pn = pathNodes.get(regoffset);
int idx = _pathNodesIndex.get(regoffset).get((nby << 8) + nbx);
final ByteBuffer pn = _pathNodes.get(regoffset);
// reading
final byte nodes = pn.get(idx);
idx += (layer * 10) + 1;// byte + layer*10byte
idx += (layer * 10) + 1; // byte + layer*10byte
if (nodes < layer)
{
_log.warning("SmthWrong!");
@@ -375,11 +363,10 @@ public class GeoPathFinding extends PathFinding
}
final short nbx = getNodeBlock(node_x);
final short nby = getNodeBlock(node_y);
int idx = pathNodes_index.get(regoffset).get((nby << 8) + nbx);
final ByteBuffer pn = pathNodes.get(regoffset);
int idx = _pathNodesIndex.get(regoffset).get((nby << 8) + nbx);
final ByteBuffer pn = _pathNodes.get(regoffset);
// reading
byte nodes = pn.get(idx);
idx++;// byte
byte nodes = pn.get(idx++);
int idx2 = 0; // create index to nearlest node by z
short last_z = Short.MIN_VALUE;
while (nodes > 0)
@@ -396,49 +383,58 @@ public class GeoPathFinding extends PathFinding
return new GeoNode(new GeoNodeLoc(node_x, node_y, last_z), idx2);
}
private GeoPathFinding()
protected GeoPathFinding()
{
final File Data = new File(Config.PATHNODE_DIR, "pn_index.txt");
try (FileReader fr = new FileReader(Data);
BufferedReader br = new BufferedReader(fr);
LineNumberReader lnr = new LineNumberReader(br))
try
{
_log.info("PathFinding Engine: - Loading Path Nodes...");
String line;
_log.info("Path Engine: - Loading Path Nodes...");
//@formatter:off
Files.lines(Paths.get(Config.PATHNODE_DIR.getPath(), "pn_index.txt"), StandardCharsets.UTF_8)
.map(String::trim)
.filter(l -> !l.isEmpty())
.forEach(line -> {
final String[] parts = line.split("_");
while ((line = lnr.readLine()) != null)
if ((parts.length < 2)
|| !Util.isDigit(parts[0])
|| !Util.isDigit(parts[1]))
{
if (line.trim().length() == 0)
{
continue;
_log.warning("Invalid pathnode entry: '" + line + "', must be in format 'XX_YY', where X and Y - integers");
return;
}
final StringTokenizer st = new StringTokenizer(line, "_");
final byte rx = Byte.parseByte(st.nextToken());
final byte ry = Byte.parseByte(st.nextToken());
final byte rx = Byte.parseByte(parts[0]);
final byte ry = Byte.parseByte(parts[1]);
LoadPathNodeFile(rx, ry);
});
//@formatter:on
}
}
catch (final Exception e)
catch (IOException e)
{
e.printStackTrace();
throw new Error("Failed to Read pn_index File.");
_log.log(Level.WARNING, "", e);
throw new Error("Failed to read pn_index file.");
}
}
private void LoadPathNodeFile(byte rx, byte ry)
{
if ((rx < L2World.TILE_X_MIN) || (rx > L2World.TILE_X_MAX) || (ry < L2World.TILE_Y_MIN) || (ry > L2World.TILE_Y_MAX))
{
_log.warning("Failed to Load PathNode File: invalid region " + rx + "," + ry + Config.EOL);
return;
}
final short regionoffset = getRegionOffset(rx, ry);
final File pn = new File(Config.PATHNODE_DIR, rx + "_" + ry + ".pn");
_log.info("PathFinding Engine: - Loading: " + pn.getName() + " -> region offset: " + regionoffset + "X: " + rx + " Y: " + ry);
final File file = new File(Config.PATHNODE_DIR, rx + "_" + ry + ".pn");
_log.info("Path Engine: - Loading: " + file.getName() + " -> region offset: " + regionoffset + " X: " + rx + " Y: " + ry);
int node = 0, size, index = 0;
// Create a read-only memory-mapped file
try (RandomAccessFile raf = new RandomAccessFile(pn, "r");
try (RandomAccessFile raf = new RandomAccessFile(file, "r");
FileChannel roChannel = raf.getChannel())
{
size = (int) roChannel.size();
MappedByteBuffer nodes;
if (Config.FORCE_GEODATA) // Force O/S to Loads this buffer's content into physical memory.
if (Config.FORCE_GEODATA)
{
// it is not guarantee, because the underlying operating system may have paged out some of the buffer's data
nodes = roChannel.map(FileChannel.MapMode.READ_ONLY, 0, size).load();
@@ -454,17 +450,20 @@ public class GeoPathFinding extends PathFinding
while (node < 65536)
{
final byte layer = nodes.get(index);
indexs.put(node, index);
node++;
indexs.put(node++, index);
index += (layer * 10) + 1;
}
pathNodes_index.put(regionoffset, indexs);
pathNodes.put(regionoffset, nodes);
_pathNodesIndex.put(regionoffset, indexs);
_pathNodes.put(regionoffset, nodes);
}
catch (final Exception e)
catch (Exception e)
{
e.printStackTrace();
_log.warning("Failed to Load PathNode File: " + pn.getAbsolutePath() + "\n");
_log.log(Level.WARNING, "Failed to Load PathNode File: " + file.getAbsolutePath() + " : " + e.getMessage(), e);
}
}
private static class SingletonHolder
{
protected static final GeoPathFinding _instance = new GeoPathFinding();
}
}

View File

@@ -14,9 +14,9 @@
* 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.l2jmobius.gameserver.pathfinding.utils;
package com.l2jmobius.gameserver.geodata.pathfinding.utils;
import com.l2jmobius.gameserver.pathfinding.geonodes.GeoNode;
import com.l2jmobius.gameserver.geodata.pathfinding.geonodes.GeoNode;
/**
* @author -Nemesiss-

View File

@@ -1,111 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* 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.l2jmobius.gameserver.geoeditorcon;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* @author Dezmond
*/
public class GeoEditorListener extends Thread
{
private static GeoEditorListener _instance;
private static final int PORT = 9011;
private static Logger _log = Logger.getLogger(GeoEditorListener.class.getName());
private final ServerSocket _serverSocket;
private static GeoEditorThread _geoEditor;
public static GeoEditorListener getInstance()
{
if (_instance == null)
{
try
{
_instance = new GeoEditorListener();
_instance.start();
_log.info("GeoEditorListener Initialized.");
}
catch (final IOException e)
{
_log.severe("Error creating geoeditor listener! " + e.getMessage());
System.exit(1);
}
}
return _instance;
}
private GeoEditorListener() throws IOException
{
_serverSocket = new ServerSocket(PORT);
}
public GeoEditorThread getThread()
{
return _geoEditor;
}
public String getStatus()
{
if ((_geoEditor != null) && _geoEditor.isWorking())
{
return "Geoeditor connected.";
}
return "Geoeditor not connected.";
}
@Override
public void run()
{
try (Socket connection = _serverSocket.accept())
{
while (true)
{
if ((_geoEditor != null) && _geoEditor.isWorking())
{
_log.warning("Geoeditor already connected!");
connection.close();
continue;
}
_log.info("Received geoeditor connection from: " + connection.getInetAddress().getHostAddress());
_geoEditor = new GeoEditorThread(connection);
_geoEditor.start();
}
}
catch (final Exception e)
{
_log.info("GeoEditorListener: " + e.getMessage());
}
finally
{
try
{
_serverSocket.close();
}
catch (final IOException io)
{
_log.log(Level.INFO, "", io);
}
_log.warning("GeoEditorListener Closed!");
}
}
}

View File

@@ -1,300 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* 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.l2jmobius.gameserver.geoeditorcon;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketException;
import java.util.logging.Logger;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import javolution.util.FastList;
/**
* @author Luno, Dezmond
*/
public class GeoEditorThread extends Thread
{
private static Logger _log = Logger.getLogger(GeoEditorThread.class.getName());
private boolean _working = false;
private int _mode = 0; // 0 - don't send coords, 1 - send each
// validateposition from client, 2 - send in
// intervals of _sendDelay ms.
private int _sendDelay = 1000; // default - once in second
private final Socket _geSocket;
private OutputStream _out;
private final FastList<L2PcInstance> _gms;
public GeoEditorThread(Socket ge)
{
_geSocket = ge;
_working = true;
_gms = new FastList<>();
}
@Override
public void interrupt()
{
try
{
_geSocket.close();
}
catch (final Exception e)
{
}
super.interrupt();
}
@Override
public void run()
{
try
{
_out = _geSocket.getOutputStream();
int timer = 0;
while (_working)
{
if (!isConnected())
{
_working = false;
}
if ((_mode == 2) && (timer > _sendDelay))
{
for (final L2PcInstance gm : _gms)
{
if (gm == null)
{
continue;
}
if (!gm.getClient().getConnection().isClosed())
{
sendGmPosition(gm);
}
else
{
_gms.remove(gm);
}
}
timer = 0;
}
try
{
sleep(100);
if (_mode == 2)
{
timer += 100;
}
}
catch (final Exception e)
{
}
}
}
catch (final SocketException e)
{
_log.warning("GeoEditor disconnected. " + e.getMessage());
}
catch (final Exception e)
{
e.printStackTrace();
}
finally
{
try
{
_geSocket.close();
}
catch (final Exception e)
{
}
_working = false;
}
}
public void sendGmPosition(int gx, int gy, short z)
{
if (!isConnected())
{
return;
}
try
{
synchronized (_out)
{
writeC(0x0b); // length 11 bytes!
writeC(0x01); // Cmd = save cell;
writeD(gx); // Global coord X;
writeD(gy); // Global coord Y;
writeH(z); // Coord Z;
_out.flush();
}
}
catch (final SocketException e)
{
_log.warning("GeoEditor disconnected. " + e.getMessage());
_working = false;
}
catch (final Exception e)
{
e.printStackTrace();
try
{
_geSocket.close();
}
catch (final Exception ex)
{
}
_working = false;
}
}
public void sendGmPosition(L2PcInstance _gm)
{
sendGmPosition(_gm.getX(), _gm.getY(), (short) _gm.getZ());
}
public void sendPing()
{
if (!isConnected())
{
return;
}
try
{
synchronized (_out)
{
writeC(0x01); // length 1 byte!
writeC(0x02); // Cmd = ping (dummy packet for connection
_out.flush();
}
}
catch (final SocketException e)
{
_log.warning("GeoEditor disconnected. " + e.getMessage());
_working = false;
}
catch (final Exception e)
{
e.printStackTrace();
try
{
_geSocket.close();
}
catch (final Exception ex)
{
}
_working = false;
}
}
private void writeD(int value) throws IOException
{
_out.write(value & 0xff);
_out.write((value >> 8) & 0xff);
_out.write((value >> 16) & 0xff);
_out.write((value >> 24) & 0xff);
}
private void writeH(int value) throws IOException
{
_out.write(value & 0xff);
_out.write((value >> 8) & 0xff);
}
private void writeC(int value) throws IOException
{
_out.write(value & 0xff);
}
public void setMode(int value)
{
_mode = value;
}
public void setTimer(int value)
{
if (value < 500)
{
_sendDelay = 500; // maximum - 2 times per second!
}
else if (value > 60000)
{
_sendDelay = 60000; // Minimum - 1 time per minute.
}
else
{
_sendDelay = value;
}
}
public void addGM(L2PcInstance gm)
{
if (!_gms.contains(gm))
{
_gms.add(gm);
}
}
public void removeGM(L2PcInstance gm)
{
if (_gms.contains(gm))
{
_gms.remove(gm);
}
}
public boolean isSend(L2PcInstance gm)
{
if ((_mode == 1) && _gms.contains(gm))
{
return true;
}
return false;
}
private boolean isConnected()
{
return _geSocket.isConnected() && !_geSocket.isClosed();
}
public boolean isWorking()
{
sendPing();
return _working;
}
public int getMode()
{
return _mode;
}
}

View File

@@ -1,134 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* 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.l2jmobius.gameserver.handler.admincommandhandlers;
import java.util.StringTokenizer;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.geoeditorcon.GeoEditorListener;
import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
import com.l2jmobius.gameserver.model.GMAudit;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
/**
* @author Luno, Dezmond
*/
public class AdminGeoEditor implements IAdminCommandHandler
{
private static String[] _adminCommands =
{
"admin_ge_status",
"admin_ge_mode",
"admin_ge_join",
"admin_ge_leave"
};
private static final int REQUIRED_LEVEL = Config.GM_MIN;
@Override
public boolean useAdminCommand(String command, L2PcInstance activeChar)
{
if (!Config.ALT_PRIVILEGES_ADMIN)
{
if (!(checkLevel(activeChar.getAccessLevel()) && activeChar.isGM()))
{
return false;
}
}
final String target = (activeChar.getTarget() != null) ? activeChar.getTarget().getName() : "no-target";
GMAudit.auditGMAction(activeChar.getName(), command, target, "");
if (!Config.ACCEPT_GEOEDITOR_CONN)
{
activeChar.sendMessage("Server does not accept geoeditor connections now.");
return true;
}
if (command.startsWith("admin_ge_status"))
{
activeChar.sendMessage(GeoEditorListener.getInstance().getStatus());
}
else if (command.startsWith("admin_ge_mode"))
{
if (GeoEditorListener.getInstance().getThread() == null)
{
activeChar.sendMessage("Geoeditor is not connected.");
return true;
}
try
{
final String val = command.substring("admin_ge_mode".length());
final StringTokenizer st = new StringTokenizer(val);
if (st.countTokens() < 1)
{
activeChar.sendMessage("Usage: //ge_mode X");
activeChar.sendMessage("Mode 0: Don't send coordinates to geoeditor.");
activeChar.sendMessage("Mode 1: Send coordinates at ValidatePosition from clients.");
activeChar.sendMessage("Mode 2: Send coordinates each second.");
return true;
}
final int m = Integer.parseInt(st.nextToken());
GeoEditorListener.getInstance().getThread().setMode(m);
activeChar.sendMessage("Geoeditor connection mode set to " + m + ".");
}
catch (final Exception e)
{
activeChar.sendMessage("Usage: //ge_mode X");
activeChar.sendMessage("Mode 0: Don't send coordinates to geoeditor.");
activeChar.sendMessage("Mode 1: Send coordinates at ValidatePosition from clients.");
activeChar.sendMessage("Mode 2: Send coordinates each second.");
e.printStackTrace();
}
}
else if (command.equals("admin_ge_join"))
{
if (GeoEditorListener.getInstance().getThread() == null)
{
activeChar.sendMessage("Geoeditor is not connected.");
return true;
}
GeoEditorListener.getInstance().getThread().addGM(activeChar);
activeChar.sendMessage("You have been added to geoeditor's list.");
}
else if (command.equals("admin_ge_leave"))
{
if (GeoEditorListener.getInstance().getThread() == null)
{
activeChar.sendMessage("Geoeditor is not connected.");
return true;
}
GeoEditorListener.getInstance().getThread().removeGM(activeChar);
activeChar.sendMessage("You have been removed from geoeditor's list.");
}
return true;
}
@Override
public String[] getAdminCommandList()
{
return _adminCommands;
}
private boolean checkLevel(int level)
{
return (level >= REQUIRED_LEVEL);
}
}

View File

@@ -17,10 +17,12 @@
package com.l2jmobius.gameserver.handler.admincommandhandlers;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.util.GeoUtils;
/**
* @author -Nemesiss-
@@ -32,7 +34,9 @@ public class AdminGeodata implements IAdminCommandHandler
"admin_geo_pos",
"admin_geo_spawn_pos",
"admin_geo_can_move",
"admin_geo_can_see"
"admin_geo_can_see",
"admin_geogrid",
"admin_geomap"
};
private static final int REQUIRED_LEVEL = Config.GM_MIN;
@@ -75,7 +79,7 @@ public class AdminGeodata implements IAdminCommandHandler
if (GeoData.getInstance().hasGeoPos(geoX, geoY))
{
activeChar.sendMessage("WorldX: " + worldX + ", WorldY: " + worldY + ", WorldZ: " + worldZ + ", GeoX: " + geoX + ", GeoY: " + geoY + ", GeoZ: " + GeoData.getInstance().getSpawnHeight(worldX, worldY, worldZ, worldZ));
activeChar.sendMessage("WorldX: " + worldX + ", WorldY: " + worldY + ", WorldZ: " + worldZ + ", GeoX: " + geoX + ", GeoY: " + geoY + ", GeoZ: " + GeoData.getInstance().getSpawnHeight(worldX, worldY, worldZ));
}
else
{
@@ -120,6 +124,16 @@ public class AdminGeodata implements IAdminCommandHandler
activeChar.sendMessage("Incorrect Target.");
}
}
else if (command.equals("admin_geogrid"))
{
GeoUtils.debugGrid(activeChar);
}
else if (command.equals("admin_geomap"))
{
final int x = ((activeChar.getX() - L2World.MAP_MIN_X) >> 15) + L2World.TILE_X_MIN;
final int y = ((activeChar.getY() - L2World.MAP_MIN_Y) >> 15) + L2World.TILE_Y_MIN;
activeChar.sendMessage("GeoMap: " + x + "_" + y);
}
else
{
return false;

View File

@@ -19,10 +19,10 @@ package com.l2jmobius.gameserver.handler.admincommandhandlers;
import java.util.List;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNodeLoc;
import com.l2jmobius.gameserver.geodata.pathfinding.PathFinding;
import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc;
import com.l2jmobius.gameserver.pathfinding.PathFinding;
public class AdminPathNode implements IAdminCommandHandler
{
@@ -79,7 +79,7 @@ public class AdminPathNode implements IAdminCommandHandler
}
else if (command.equals("admin_find_path"))
{
if (Config.GEODATA < 2)
if (Config.PATHFINDING < 2)
{
activeChar.sendMessage("PathFinding has not been enabled.");
return true;

View File

@@ -17,8 +17,8 @@
package com.l2jmobius.gameserver.handler.skillhandlers;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.datatables.ZoneTable;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.handler.ISkillHandler;
import com.l2jmobius.gameserver.model.Inventory;
import com.l2jmobius.gameserver.model.L2Character;
@@ -169,7 +169,7 @@ public class Fishing implements ISkillHandler
if (aimingTo != null)
{
// fishing zone found, we can fish here
if (Config.GEODATA > 0)
if (Config.PATHFINDING > 0)
{
// geodata enabled, checking if we can see end of the pole
if (GeoData.getInstance().canSeeTarget(player.getX(), player.getY(), z, x, y, z))

View File

@@ -72,6 +72,8 @@ public abstract class Inventory extends ItemContainer
// Speed percentage mods
public static final double MAX_ARMOR_WEIGHT = 12000;
public static final int ADENA_ID = 57;
private final L2ItemInstance[] _paperdoll;
private final List<PaperdollListener> _paperdollListeners;

View File

@@ -26,7 +26,6 @@ import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.GameTimeController;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.ai.CtrlEvent;
import com.l2jmobius.gameserver.ai.CtrlIntention;
@@ -36,6 +35,9 @@ import com.l2jmobius.gameserver.datatables.DoorTable;
import com.l2jmobius.gameserver.datatables.MapRegionTable;
import com.l2jmobius.gameserver.datatables.MapRegionTable.TeleportWhereType;
import com.l2jmobius.gameserver.datatables.SkillTable;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNodeLoc;
import com.l2jmobius.gameserver.geodata.pathfinding.PathFinding;
import com.l2jmobius.gameserver.handler.ISkillHandler;
import com.l2jmobius.gameserver.handler.SkillHandler;
import com.l2jmobius.gameserver.instancemanager.TownManager;
@@ -80,8 +82,6 @@ import com.l2jmobius.gameserver.network.serverpackets.StatusUpdate;
import com.l2jmobius.gameserver.network.serverpackets.StopMove;
import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import com.l2jmobius.gameserver.network.serverpackets.TeleportToLocation;
import com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc;
import com.l2jmobius.gameserver.pathfinding.PathFinding;
import com.l2jmobius.gameserver.skills.Calculator;
import com.l2jmobius.gameserver.skills.Formulas;
import com.l2jmobius.gameserver.skills.Stats;
@@ -4407,10 +4407,10 @@ public abstract class L2Character extends L2Object
final boolean isFloating = isFlying() || isInsideZone(L2Character.ZONE_WATER);
// Z coordinate will follow geodata or client values
if ((Config.GEODATA > 0) && (Config.COORD_SYNCHRONIZE == 2) && !isFloating && !m.disregardingGeodata && !(this instanceof L2BoatInstance) && ((GameTimeController.getGameTicks() % 10) == 0 // once a second to reduce possible cpu load
if ((Config.PATHFINDING > 0) && (Config.COORD_SYNCHRONIZE == 2) && !isFloating && !m.disregardingGeodata && !(this instanceof L2BoatInstance) && ((GameTimeController.getGameTicks() % 10) == 0 // once a second to reduce possible cpu load
) && GeoData.getInstance().hasGeo(xPrev, yPrev))
{
final int geoHeight = GeoData.getInstance().getSpawnHeight(xPrev, yPrev, zPrev - 30, zPrev + 30);
final int geoHeight = GeoData.getInstance().getSpawnHeight(xPrev, yPrev, zPrev - 30);
dz = m._zDestination - geoHeight;
// quite a big difference, compare to validatePosition packet
if ((this instanceof L2PcInstance) && (Math.abs(((L2PcInstance) this).getClientZ() - geoHeight) > 200) && (Math.abs(((L2PcInstance) this).getClientZ() - geoHeight) < 1500))
@@ -4650,7 +4650,7 @@ public abstract class L2Character extends L2Object
// make water move short and use no geodata checks for swimming chars
// distance in a click can easily be over 3000
if ((Config.GEODATA > 0) && !(this instanceof L2BoatInstance) && isInsideZone(ZONE_WATER) && (distance > 700))
if ((Config.PATHFINDING > 0) && !(this instanceof L2BoatInstance) && isInsideZone(ZONE_WATER) && (distance > 700))
{
final double divider = 700 / distance;
x = curX + (int) (divider * dx);
@@ -4728,7 +4728,7 @@ public abstract class L2Character extends L2Object
m.onGeodataPathIndex = -1; // Initialize not on geodata path
m.disregardingGeodata = false;
if ((Config.GEODATA > 0) && !isFlying() // currently flying characters not checked
if ((Config.PATHFINDING > 0) && !isFlying() // currently flying characters not checked
&& !(this instanceof L2NpcWalkerInstance) && !(this instanceof L2BoatInstance) && (!isInsideZone(ZONE_WATER) || isInsideZone(ZONE_SIEGE))) // swimming also not checked - but distance is limited
{
final boolean isInBoat = (this instanceof L2PcInstance) && ((L2PcInstance) this).isInBoat();
@@ -4747,12 +4747,7 @@ public abstract class L2Character extends L2Object
// Movement checks:
// when geodata == 2, for all characters except mobs returning home (could be changed later to teleport if pathfinding fails)
// when geodata == 1, for l2playableinstance and l2riftinvaderinstance
if (((Config.GEODATA == 2) && !((this instanceof L2Attackable) && ((L2Attackable) this).isReturningToSpawnPoint())) || ((this instanceof L2PcInstance) && !(isInBoat && (distance > 1500))) || isAfraid() || (this instanceof L2RiftInvaderInstance) || ((this instanceof L2Summon) && !(getAI().getIntention() == CtrlIntention.AI_INTENTION_FOLLOW))) // assuming
// intention_follow
// only
// when
// following
// owner
if (((Config.PATHFINDING == 2) && !((this instanceof L2Attackable) && ((L2Attackable) this).isReturningToSpawnPoint())) || ((this instanceof L2PcInstance) && !(isInBoat && (distance > 1500))) || isAfraid() || (this instanceof L2RiftInvaderInstance) || ((this instanceof L2Summon) && !(getAI().getIntention() == CtrlIntention.AI_INTENTION_FOLLOW))) // assuming
{
if (isOnGeodataPath())
{
@@ -4806,7 +4801,7 @@ public abstract class L2Character extends L2Object
// Pathfinding checks. Only when geodata setting is 2, the LoS check gives shorter result
// than the original movement was and the LoS gives a shorter distance than 2000
// This way of detecting need for pathfinding could be changed.
if ((Config.GEODATA == 2) && ((originalDistance - distance) > 30) && (distance < 2000) && !isAfraid())
if ((Config.PATHFINDING == 2) && ((originalDistance - distance) > 30) && (distance < 2000) && !isAfraid())
{
// Path calculation
// Overrides previous movement check
@@ -4876,7 +4871,7 @@ public abstract class L2Character extends L2Object
}
// If no distance to go through, the movement is cancelled
if ((distance < 1) && ((Config.GEODATA == 2) || (this instanceof L2PlayableInstance) || isAfraid() || (this instanceof L2RiftInvaderInstance)))
if ((distance < 1) && ((Config.PATHFINDING == 2) || (this instanceof L2PlayableInstance) || isAfraid() || (this instanceof L2RiftInvaderInstance)))
{
if (this instanceof L2Summon)
{

View File

@@ -27,10 +27,10 @@ import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.L2DatabaseFactory;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.datatables.ItemTable;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import com.l2jmobius.gameserver.instancemanager.MercTicketManager;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
@@ -931,7 +931,7 @@ public final class L2ItemInstance extends L2Object
assert getPosition().getWorldRegion() == null;
}
if ((Config.GEODATA > 0) && (dropper != null))
if ((Config.PATHFINDING > 0) && (dropper != null))
{
final Location dropDest = GeoData.getInstance().moveCheck(dropper.getX(), dropper.getY(), dropper.getZ(), x, y, z);
x = dropDest.getX();

View File

@@ -23,8 +23,8 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.datatables.SkillTreeTable;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.model.actor.instance.L2ArtefactInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2ChestInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2DoorInstance;

View File

@@ -22,9 +22,9 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.Territory;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.model.actor.instance.L2MonsterInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2NpcInstance;
@@ -581,7 +581,7 @@ public class L2Spawn
// don't correct z of flying npc's
if (!mob.isFlying())
{
newlocz = GeoData.getInstance().getSpawnHeight(newlocx, newlocy, newlocz, newlocz);
newlocz = GeoData.getInstance().getSpawnHeight(newlocx, newlocy, newlocz);
}
for (final L2Effect f : mob.getAllEffects())

View File

@@ -17,11 +17,11 @@
package com.l2jmobius.gameserver.model;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.ai.L2CharacterAI;
import com.l2jmobius.gameserver.ai.L2SummonAI;
import com.l2jmobius.gameserver.datatables.SkillTable;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.model.L2Attackable.AggroInfo;
import com.l2jmobius.gameserver.model.L2Skill.SkillTargetType;
import com.l2jmobius.gameserver.model.actor.instance.L2DoorInstance;
@@ -213,7 +213,7 @@ public abstract class L2Summon extends L2PlayableInstance
player.sendPacket(new ValidateLocation(this));
if (isAutoAttackable(player))
{
if (Config.GEODATA > 0)
if (Config.PATHFINDING > 0)
{
if (GeoData.getInstance().canSeeTarget(player, this))
{
@@ -231,7 +231,7 @@ public abstract class L2Summon extends L2PlayableInstance
{
// This Action Failed packet avoids player getting stuck when clicking three or more times
player.sendPacket(new ActionFailed());
if (Config.GEODATA > 0)
if (Config.PATHFINDING > 0)
{
if (GeoData.getInstance().canSeeTarget(player, this))
{

View File

@@ -47,6 +47,10 @@ public final class L2World
public static final int SHIFT_BY = 12;
/** Map dimensions */
public static final int TILE_X_MIN = 11;
public static final int TILE_Y_MIN = 10;
public static final int TILE_X_MAX = 28;
public static final int TILE_Y_MAX = 26;
public static final int MAP_MIN_X = -131072;
public static final int MAP_MAX_X = 228608;
public static final int MAP_MIN_Y = -262144;

View File

@@ -18,8 +18,8 @@ package com.l2jmobius.gameserver.model.actor.instance;
import java.util.List;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.model.L2Character;
import com.l2jmobius.gameserver.model.L2Spawn;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;

View File

@@ -35,7 +35,6 @@ import java.util.logging.Level;
import com.l2jmobius.Config;
import com.l2jmobius.L2DatabaseFactory;
import com.l2jmobius.gameserver.GameTimeController;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.ItemsAutoDestroy;
import com.l2jmobius.gameserver.LoginServerThread;
import com.l2jmobius.gameserver.Olympiad;
@@ -63,6 +62,7 @@ import com.l2jmobius.gameserver.datatables.NobleSkillTable;
import com.l2jmobius.gameserver.datatables.NpcTable;
import com.l2jmobius.gameserver.datatables.SkillTable;
import com.l2jmobius.gameserver.datatables.SkillTreeTable;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.handler.IItemHandler;
import com.l2jmobius.gameserver.handler.ItemHandler;
import com.l2jmobius.gameserver.instancemanager.CastleManager;
@@ -3996,7 +3996,7 @@ public final class L2PcInstance extends L2PlayableInstance
{
if (Config.GEODATA > 0)
if (Config.PATHFINDING > 0)
{
@@ -4030,7 +4030,7 @@ public final class L2PcInstance extends L2PlayableInstance
// This Action Failed packet avoids player getting stuck when clicking three or more times
player.sendPacket(new ActionFailed());
if (Config.GEODATA > 0)
if (Config.PATHFINDING > 0)
{

View File

@@ -24,10 +24,10 @@ import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.L2DatabaseFactory;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.datatables.SkillTable;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.handler.IItemHandler;
import com.l2jmobius.gameserver.handler.ItemHandler;
import com.l2jmobius.gameserver.idfactory.IdFactory;
@@ -316,7 +316,7 @@ public class L2PetInstance extends L2Summon
// Check if the pet is attackable (without a forced attack) and isn't dead
if (isAutoAttackable(player) && !isOwner)
{
if (Config.GEODATA > 0)
if (Config.PATHFINDING > 0)
{
if (GeoData.getInstance().canSeeTarget(player, this))
{
@@ -333,7 +333,7 @@ public class L2PetInstance extends L2Summon
}
else if (!isInsideRadius(player, 150, false, false))
{
if (Config.GEODATA > 0)
if (Config.PATHFINDING > 0)
{
if (GeoData.getInstance().canSeeTarget(player, this))
{

View File

@@ -104,7 +104,7 @@ public class MoveBackwardToLocation extends L2GameClientPacket
}
// Disable keyboard movement when geodata is not enabled and player is not flying.
if ((_moveMovement == 0) && (Config.GEODATA < 1) && !activeChar.isFlying())
if ((_moveMovement == 0) && (Config.PATHFINDING < 1) && !activeChar.isFlying())
{
activeChar.sendPacket(new ActionFailed());
}

View File

@@ -19,7 +19,6 @@ package com.l2jmobius.gameserver.network.clientpackets;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.geoeditorcon.GeoEditorListener;
import com.l2jmobius.gameserver.model.L2Character;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.serverpackets.GetOnVehicle;
@@ -113,14 +112,6 @@ public class ValidatePosition extends L2GameClientPacket
activeChar.getParty().broadcastToPartyMembers(activeChar, new PartyMemberPosition(activeChar));
}
if (Config.ACCEPT_GEOEDITOR_CONN)
{
if ((GeoEditorListener.getInstance().getThread() != null) && GeoEditorListener.getInstance().getThread().isWorking() && GeoEditorListener.getInstance().getThread().isSend(activeChar))
{
GeoEditorListener.getInstance().getThread().sendGmPosition(_x, _y, (short) _z);
}
}
if (activeChar.isFlying() || activeChar.isInsideZone(L2Character.ZONE_WATER))
{
activeChar.setXYZ(realX, realY, _z);
@@ -165,7 +156,7 @@ public class ValidatePosition extends L2GameClientPacket
// intended for geodata. Sends a validation packet to client
// when too far from server calculated true coordinate.
// Due to geodata "holes", some Z axis checks are made.
if ((Config.GEODATA > 0) && ((diffSq > 250000) || (Math.abs(dz) > 200)))
if ((Config.PATHFINDING > 0) && ((diffSq > 250000) || (Math.abs(dz) > 200)))
{
if ((Math.abs(dz) > 200) && (Math.abs(dz) < 1500) && (Math.abs(_z - activeChar.getClientZ()) < 800))
{

View File

@@ -0,0 +1,327 @@
/*
* This file is part of the L2J Mobius project.
*
* 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.l2jmobius.gameserver.network.serverpackets;
import java.awt.Color;
import java.util.ArrayList;
import java.util.List;
/**
* A packet used to draw points and lines on client.<br/>
* <b>Note:</b> Names in points and lines are bugged they will appear even when not looking at them.
* @author NosBit
*/
public class ExServerPrimitive extends L2GameServerPacket
{
private static final String _SM_EX_SERVER_PRIMITIVE = "[S] FE:24 ExServerPrimitive";
private final String _name;
private final int _x;
private final int _y;
private final int _z;
private final List<Point> _points = new ArrayList<>();
private final List<Line> _lines = new ArrayList<>();
/**
* @param name A unique name this will be used to replace lines if second packet is sent
* @param x the x coordinate usually middle of drawing area
* @param y the y coordinate usually middle of drawing area
* @param z the z coordinate usually middle of drawing area
*/
public ExServerPrimitive(String name, int x, int y, int z)
{
_name = name;
_x = x;
_y = y;
_z = z;
}
/**
* Adds a point to be displayed on client.
* @param name the name that will be displayed over the point
* @param color the color
* @param isNameColored if {@code true} name will be colored as well.
* @param x the x coordinate for this point
* @param y the y coordinate for this point
* @param z the z coordinate for this point
*/
public void addPoint(String name, int color, boolean isNameColored, int x, int y, int z)
{
_points.add(new Point(name, color, isNameColored, x, y, z));
}
/**
* Adds a point to be displayed on client.
* @param color the color
* @param x the x coordinate for this point
* @param y the y coordinate for this point
* @param z the z coordinate for this point
*/
public void addPoint(int color, int x, int y, int z)
{
addPoint("", color, false, x, y, z);
}
/**
* Adds a point to be displayed on client.
* @param name the name that will be displayed over the point
* @param color the color
* @param isNameColored if {@code true} name will be colored as well.
* @param x the x coordinate for this point
* @param y the y coordinate for this point
* @param z the z coordinate for this point
*/
public void addPoint(String name, Color color, boolean isNameColored, int x, int y, int z)
{
addPoint(name, color.getRGB(), isNameColored, x, y, z);
}
/**
* Adds a point to be displayed on client.
* @param color the color
* @param x the x coordinate for this point
* @param y the y coordinate for this point
* @param z the z coordinate for this point
*/
public void addPoint(Color color, int x, int y, int z)
{
addPoint("", color, false, x, y, z);
}
/**
* Adds a line to be displayed on client
* @param name the name that will be displayed over the middle of line
* @param color the color
* @param isNameColored if {@code true} name will be colored as well.
* @param x the x coordinate for this line start point
* @param y the y coordinate for this line start point
* @param z the z coordinate for this line start point
* @param x2 the x coordinate for this line end point
* @param y2 the y coordinate for this line end point
* @param z2 the z coordinate for this line end point
*/
public void addLine(String name, int color, boolean isNameColored, int x, int y, int z, int x2, int y2, int z2)
{
_lines.add(new Line(name, color, isNameColored, x, y, z, x2, y2, z2));
}
/**
* Adds a line to be displayed on client
* @param color the color
* @param x the x coordinate for this line start point
* @param y the y coordinate for this line start point
* @param z the z coordinate for this line start point
* @param x2 the x coordinate for this line end point
* @param y2 the y coordinate for this line end point
* @param z2 the z coordinate for this line end point
*/
public void addLine(int color, int x, int y, int z, int x2, int y2, int z2)
{
addLine("", color, false, x, y, z, x2, y2, z2);
}
/**
* Adds a line to be displayed on client
* @param name the name that will be displayed over the middle of line
* @param color the color
* @param isNameColored if {@code true} name will be colored as well.
* @param x the x coordinate for this line start point
* @param y the y coordinate for this line start point
* @param z the z coordinate for this line start point
* @param x2 the x coordinate for this line end point
* @param y2 the y coordinate for this line end point
* @param z2 the z coordinate for this line end point
*/
public void addLine(String name, Color color, boolean isNameColored, int x, int y, int z, int x2, int y2, int z2)
{
addLine(name, color.getRGB(), isNameColored, x, y, z, x2, y2, z2);
}
/**
* Adds a line to be displayed on client
* @param color the color
* @param x the x coordinate for this line start point
* @param y the y coordinate for this line start point
* @param z the z coordinate for this line start point
* @param x2 the x coordinate for this line end point
* @param y2 the y coordinate for this line end point
* @param z2 the z coordinate for this line end point
*/
public void addLine(Color color, int x, int y, int z, int x2, int y2, int z2)
{
addLine("", color, false, x, y, z, x2, y2, z2);
}
@Override
protected void writeImpl()
{
writeC(0xFE);
writeH(0x24); // Changed at Kamael to 11
writeS(_name);
writeD(_x);
writeD(_y);
writeD(_z);
writeD(65535); // has to do something with display range and angle
writeD(65535); // has to do something with display range and angle
writeD(_points.size() + _lines.size());
for (Point point : _points)
{
writeC(1); // Its the type in this case Point
writeS(point.getName());
final int color = point.getColor();
writeD((color >> 16) & 0xFF); // R
writeD((color >> 8) & 0xFF); // G
writeD(color & 0xFF); // B
writeD(point.isNameColored() ? 1 : 0);
writeD(point.getX());
writeD(point.getY());
writeD(point.getZ());
}
for (Line line : _lines)
{
writeC(2); // Its the type in this case Line
writeS(line.getName());
final int color = line.getColor();
writeD((color >> 16) & 0xFF); // R
writeD((color >> 8) & 0xFF); // G
writeD(color & 0xFF); // B
writeD(line.isNameColored() ? 1 : 0);
writeD(line.getX());
writeD(line.getY());
writeD(line.getZ());
writeD(line.getX2());
writeD(line.getY2());
writeD(line.getZ2());
}
}
private static class Point
{
private final String _name;
private final int _color;
private final boolean _isNameColored;
private final int _x;
private final int _y;
private final int _z;
public Point(String name, int color, boolean isNameColored, int x, int y, int z)
{
_name = name;
_color = color;
_isNameColored = isNameColored;
_x = x;
_y = y;
_z = z;
}
/**
* @return the name
*/
public String getName()
{
return _name;
}
/**
* @return the color
*/
public int getColor()
{
return _color;
}
/**
* @return the isNameColored
*/
public boolean isNameColored()
{
return _isNameColored;
}
/**
* @return the x
*/
public int getX()
{
return _x;
}
/**
* @return the y
*/
public int getY()
{
return _y;
}
/**
* @return the z
*/
public int getZ()
{
return _z;
}
}
private static class Line extends Point
{
private final int _x2;
private final int _y2;
private final int _z2;
public Line(String name, int color, boolean isNameColored, int x, int y, int z, int x2, int y2, int z2)
{
super(name, color, isNameColored, x, y, z);
_x2 = x2;
_y2 = y2;
_z2 = z2;
}
/**
* @return the x2
*/
public int getX2()
{
return _x2;
}
/**
* @return the y2
*/
public int getY2()
{
return _y2;
}
/**
* @return the z2
*/
public int getZ2()
{
return _z2;
}
}
@Override
public String getType()
{
return _SM_EX_SERVER_PRIMITIVE;
}
}

View File

@@ -1,110 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* 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.l2jmobius.gameserver.pathfinding;
import java.util.List;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.pathfinding.cellnodes.CellPathFinding;
import com.l2jmobius.gameserver.pathfinding.geonodes.GeoPathFinding;
/**
* @author -Nemesiss-
*/
public abstract class PathFinding
{
private static PathFinding _instance;
public static PathFinding getInstance()
{
if (_instance == null)
{
if (!Config.GEODATA_CELLFINDING)
{
// Higher Memory Usage, Smaller Cpu Usage
return GeoPathFinding.getInstance();
}
return CellPathFinding.getInstance();
}
return _instance;
}
public abstract boolean pathNodesExist(short regionoffset);
public abstract List<AbstractNodeLoc> findPath(int x, int y, int z, int tx, int ty, int tz, boolean playable);
/**
* Convert geodata position to pathnode position
* @param geo_pos
* @return pathnode position
*/
public short getNodePos(int geo_pos)
{
return (short) (geo_pos >> 3); // OK?
}
/**
* Convert node position to pathnode block position
* @param node_pos
* @return pathnode block position (0...255)
*/
public short getNodeBlock(int node_pos)
{
return (short) (node_pos % 256);
}
public byte getRegionX(int node_pos)
{
return (byte) ((node_pos >> 8) + 16);
}
public byte getRegionY(int node_pos)
{
return (byte) ((node_pos >> 8) + 10);
}
public short getRegionOffset(byte rx, byte ry)
{
return (short) ((rx << 5) + ry);
}
/**
* Convert pathnode x to World x position
* @param node_x
* @return
*/
public int calculateWorldX(short node_x)
{
return L2World.MAP_MIN_X + (node_x * 128) + 48;
}
/**
* Convert pathnode y to World y position
* @param node_y
* @return
*/
public int CalculateWorldY(short node_y)
{
return L2World.MAP_MIN_Y + (node_y * 128) + 48;
}
public String[] getStat()
{
return null;
}
}

View File

@@ -17,8 +17,8 @@
package com.l2jmobius.gameserver.skills.effects;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.model.L2CharPosition;
import com.l2jmobius.gameserver.model.L2Effect;
import com.l2jmobius.gameserver.model.Location;
@@ -110,7 +110,7 @@ final class EffectFear extends L2Effect
posX += _dX * FEAR_RANGE;
posY += _dY * FEAR_RANGE;
if (Config.GEODATA > 0)
if (Config.PATHFINDING > 0)
{
final Location destiny = GeoData.getInstance().moveCheck(getEffected().getX(), getEffected().getY(), getEffected().getZ(), posX, posY, posZ);
posX = destiny.getX();

View File

@@ -19,7 +19,7 @@ package com.l2jmobius.gameserver.skills.effects;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.model.L2Effect;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.network.serverpackets.FlyToLocation;
@@ -92,7 +92,7 @@ final class EffectThrowUp extends L2Effect
_y = getEffector().getY() - (int) (offset * sin);
_z = getEffected().getZ();
if (Config.GEODATA > 0)
if (Config.PATHFINDING > 0)
{
final Location destiny = GeoData.getInstance().moveCheck(getEffected().getX(), getEffected().getY(), getEffected().getZ(), _x, _y, _z);
_x = destiny.getX();

View File

@@ -16,25 +16,165 @@
*/
package com.l2jmobius.gameserver.util;
import com.l2jserver.gameserver.geoengine.Direction;
import java.awt.Color;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geodata.geodriver.Cell;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.serverpackets.ExServerPrimitive;
/**
* @author FBIagent
* @author HorridoJoho
*/
public final class GeoUtils
{
public interface PointListener
public static void debug2DLine(L2PcInstance player, int x, int y, int tx, int ty, int z)
{
/**
* @param x
* @param y
* @return true proceed, false abort
*/
boolean onPoint(int x, int y);
final int gx = GeoData.getInstance().getGeoX(x);
final int gy = GeoData.getInstance().getGeoY(y);
final int tgx = GeoData.getInstance().getGeoX(tx);
final int tgy = GeoData.getInstance().getGeoY(ty);
final ExServerPrimitive prim = new ExServerPrimitive("Debug2DLine", x, y, z);
prim.addLine(Color.BLUE, GeoData.getInstance().getWorldX(gx), GeoData.getInstance().getWorldY(gy), z, GeoData.getInstance().getWorldX(tgx), GeoData.getInstance().getWorldY(tgy), z);
final LinePointIterator iter = new LinePointIterator(gx, gy, tgx, tgy);
while (iter.next())
{
final int wx = GeoData.getInstance().getWorldX(iter.x());
final int wy = GeoData.getInstance().getWorldY(iter.y());
prim.addPoint(Color.RED, wx, wy, z);
}
player.sendPacket(prim);
}
public static void debug3DLine(L2PcInstance player, int x, int y, int z, int tx, int ty, int tz)
{
final int gx = GeoData.getInstance().getGeoX(x);
final int gy = GeoData.getInstance().getGeoY(y);
final int tgx = GeoData.getInstance().getGeoX(tx);
final int tgy = GeoData.getInstance().getGeoY(ty);
final ExServerPrimitive prim = new ExServerPrimitive("Debug3DLine", x, y, z);
prim.addLine(Color.BLUE, GeoData.getInstance().getWorldX(gx), GeoData.getInstance().getWorldY(gy), z, GeoData.getInstance().getWorldX(tgx), GeoData.getInstance().getWorldY(tgy), tz);
final LinePointIterator3D iter = new LinePointIterator3D(gx, gy, z, tgx, tgy, tz);
iter.next();
int prevX = iter.x();
int prevY = iter.y();
int wx = GeoData.getInstance().getWorldX(prevX);
int wy = GeoData.getInstance().getWorldY(prevY);
int wz = iter.z();
prim.addPoint(Color.RED, wx, wy, wz);
while (iter.next())
{
final int curX = iter.x();
final int curY = iter.y();
if ((curX != prevX) || (curY != prevY))
{
wx = GeoData.getInstance().getWorldX(curX);
wy = GeoData.getInstance().getWorldY(curY);
wz = iter.z();
prim.addPoint(Color.RED, wx, wy, wz);
prevX = curX;
prevY = curY;
}
}
player.sendPacket(prim);
}
private static Color getDirectionColor(int x, int y, int z, int nswe)
{
if (GeoData.getInstance().checkNearestNswe(x, y, z, nswe))
{
return Color.GREEN;
}
return Color.RED;
}
public static void debugGrid(L2PcInstance player)
{
final int geoRadius = 20;
final int blocksPerPacket = 40;
int iBlock = blocksPerPacket;
int iPacket = 0;
ExServerPrimitive exsp = null;
final GeoData gd = GeoData.getInstance();
final int playerGx = gd.getGeoX(player.getX());
final int playerGy = gd.getGeoY(player.getY());
for (int dx = -geoRadius; dx <= geoRadius; ++dx)
{
for (int dy = -geoRadius; dy <= geoRadius; ++dy)
{
if (iBlock >= blocksPerPacket)
{
iBlock = 0;
if (exsp != null)
{
++iPacket;
player.sendPacket(exsp);
}
exsp = new ExServerPrimitive("DebugGrid_" + iPacket, player.getX(), player.getY(), -16000);
}
if (exsp == null)
{
throw new IllegalStateException();
}
final int gx = playerGx + dx;
final int gy = playerGy + dy;
final int x = gd.getWorldX(gx);
final int y = gd.getWorldY(gy);
final int z = gd.getNearestZ(gx, gy, player.getZ());
// north arrow
Color col = getDirectionColor(gx, gy, z, Cell.NSWE_NORTH);
exsp.addLine(col, x - 1, y - 7, z, x + 1, y - 7, z);
exsp.addLine(col, x - 2, y - 6, z, x + 2, y - 6, z);
exsp.addLine(col, x - 3, y - 5, z, x + 3, y - 5, z);
exsp.addLine(col, x - 4, y - 4, z, x + 4, y - 4, z);
// east arrow
col = getDirectionColor(gx, gy, z, Cell.NSWE_EAST);
exsp.addLine(col, x + 7, y - 1, z, x + 7, y + 1, z);
exsp.addLine(col, x + 6, y - 2, z, x + 6, y + 2, z);
exsp.addLine(col, x + 5, y - 3, z, x + 5, y + 3, z);
exsp.addLine(col, x + 4, y - 4, z, x + 4, y + 4, z);
// south arrow
col = getDirectionColor(gx, gy, z, Cell.NSWE_SOUTH);
exsp.addLine(col, x - 1, y + 7, z, x + 1, y + 7, z);
exsp.addLine(col, x - 2, y + 6, z, x + 2, y + 6, z);
exsp.addLine(col, x - 3, y + 5, z, x + 3, y + 5, z);
exsp.addLine(col, x - 4, y + 4, z, x + 4, y + 4, z);
col = getDirectionColor(gx, gy, z, Cell.NSWE_WEST);
exsp.addLine(col, x - 7, y - 1, z, x - 7, y + 1, z);
exsp.addLine(col, x - 6, y - 2, z, x - 6, y + 2, z);
exsp.addLine(col, x - 5, y - 3, z, x - 5, y + 3, z);
exsp.addLine(col, x - 4, y - 4, z, x - 4, y + 4, z);
++iBlock;
}
}
player.sendPacket(exsp);
}
/**
* difference between x values: never abover 1<br>
* difference between x values: never above 1<br>
* difference between y values: never above 1
* @param lastX
* @param lastY
@@ -42,36 +182,36 @@ public final class GeoUtils
* @param y
* @return
*/
public static Direction computeDirection(int lastX, int lastY, int x, int y)
public static int computeNswe(int lastX, int lastY, int x, int y)
{
if (x > lastX) // east
{
if (y > lastY)
{
return Direction.SOUTH_EAST;
return Cell.NSWE_SOUTH_EAST; // Direction.SOUTH_EAST;
}
else if (y < lastY)
{
return Direction.NORTH_EAST;
return Cell.NSWE_NORTH_EAST; // Direction.NORTH_EAST;
}
else
{
return Direction.EAST;
return Cell.NSWE_EAST; // Direction.EAST;
}
}
else if (x < lastX) // west
{
if (y > lastY)
{
return Direction.SOUTH_WEST;
return Cell.NSWE_SOUTH_WEST; // Direction.SOUTH_WEST;
}
else if (y < lastY)
{
return Direction.NORTH_WEST;
return Cell.NSWE_NORTH_WEST; // Direction.NORTH_WEST;
}
else
{
return Direction.WEST;
return Cell.NSWE_WEST; // Direction.WEST;
}
}
else
@@ -79,15 +219,15 @@ public final class GeoUtils
{
if (y > lastY)
{
return Direction.SOUTH;
return Cell.NSWE_SOUTH; // Direction.SOUTH;
}
else if (y < lastY)
{
return Direction.NORTH;
return Cell.NSWE_NORTH; // Direction.NORTH;
}
else
{
return null;// error, should never happen, TODO: Logging
throw new RuntimeException();
}
}
}

View File

@@ -325,4 +325,24 @@ public final class Util
}
return result;
}
/**
* @param text - the text to check
* @return {@code true} if {@code text} contains only numbers, {@code false} otherwise
*/
public static boolean isDigit(String text)
{
if ((text == null) || text.isEmpty())
{
return false;
}
for (char c : text.toCharArray())
{
if (!Character.isDigit(c))
{
return false;
}
}
return true;
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long