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/javolution-5.5.1.jar"/>
<classpathentry kind="lib" path="dist/libs/jython-engine-2.2.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/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/mchange-commons-0.2.jar"/>
<classpathentry kind="lib" path="dist/libs/mmocore.jar"/> <classpathentry kind="lib" path="dist/libs/mmocore.jar"/>
<classpathentry kind="lib" path="dist/libs/mysql-connector-java-5.1.23-bin.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_spawn_pos = 100
admin_geo_can_see = 100 admin_geo_can_see = 100
admin_geo_can_move = 100 admin_geo_can_move = 100
admin_geoeditor_connect = 100 admin_geogrid = 100
admin_geoeditor_join = 100 admin_geomap =100
admin_geoeditor_leave = 100
############### ###############
### MANOR ### ### MANOR ###

View File

@@ -5,7 +5,6 @@
Debug = False Debug = False
Assert = False Assert = False
Developer = False Developer = False
AcceptGeoeditorConn = False
# if true the server will be a test server (listed by clients setted up to list testserver) # if true the server will be a test server (listed by clients setted up to list testserver)
TestServer = False TestServer = False
@@ -253,77 +252,6 @@ GridsAlwaysOn = False
GridNeighborTurnOnTime = 1 GridNeighborTurnOnTime = 1
GridNeighborTurnOffTime = 90 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 # Falling Damage
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Allow characters to receive damage from falling. # Allow characters to receive damage from falling.

View File

@@ -23,9 +23,9 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.datatables.SkillTable; import com.l2jmobius.gameserver.datatables.SkillTable;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.instancemanager.GrandBossManager; import com.l2jmobius.gameserver.instancemanager.GrandBossManager;
import com.l2jmobius.gameserver.model.L2Character; import com.l2jmobius.gameserver.model.L2Character;
import com.l2jmobius.gameserver.model.L2Effect; import com.l2jmobius.gameserver.model.L2Effect;
@@ -165,24 +165,20 @@ public class Baium extends Quest
final L2GrandBossInstance baium = (L2GrandBossInstance) addSpawn(LIVE_BAIUM, loc_x, loc_y, loc_z, heading, false, 0); final L2GrandBossInstance baium = (L2GrandBossInstance) addSpawn(LIVE_BAIUM, loc_x, loc_y, loc_z, heading, false, 0);
GrandBossManager.getInstance().addBoss(baium); GrandBossManager.getInstance().addBoss(baium);
final L2NpcInstance _baium = baium; final L2NpcInstance _baium = baium;
ThreadPoolManager.getInstance().scheduleGeneral(new Runnable() ThreadPoolManager.getInstance().scheduleGeneral(() ->
{ {
@Override try
public void run()
{ {
try _baium.setCurrentHpMp(hp, mp);
{ _baium.setIsInvul(true);
_baium.setCurrentHpMp(hp, mp); _baium.setIsImmobilized(true);
_baium.setIsInvul(true); _baium.setRunning();
_baium.setIsImmobilized(true); _baium.broadcastPacket(new SocialAction(_baium.getObjectId(), 2));
_baium.setRunning(); startQuestTimer("baium_wakeup", 15000, _baium, null);
_baium.broadcastPacket(new SocialAction(_baium.getObjectId(), 2)); }
startQuestTimer("baium_wakeup", 15000, _baium, null); catch (final Exception e)
} {
catch (final Exception e) e.printStackTrace();
{
e.printStackTrace();
}
} }
}, 100L); }, 100L);
} }
@@ -219,20 +215,16 @@ public class Baium extends Quest
startQuestTimer("baium_despawn", 60000, npc, null, true); startQuestTimer("baium_despawn", 60000, npc, null, true);
startQuestTimer("skill_range", 500, npc, null, true); startQuestTimer("skill_range", 500, npc, null, true);
final L2NpcInstance baium = npc; final L2NpcInstance baium = npc;
ThreadPoolManager.getInstance().scheduleGeneral(new Runnable() ThreadPoolManager.getInstance().scheduleGeneral(() ->
{ {
@Override try
public void run()
{ {
try baium.setIsInvul(false);
{ baium.setIsImmobilized(false);
baium.setIsInvul(false); }
baium.setIsImmobilized(false); catch (final Exception e)
} {
catch (final Exception e) e.printStackTrace();
{
e.printStackTrace();
}
} }
}, 11100L); }, 11100L);
@@ -313,23 +305,19 @@ public class Baium extends Quest
final L2GrandBossInstance baium = (L2GrandBossInstance) addSpawn(LIVE_BAIUM, npc); final L2GrandBossInstance baium = (L2GrandBossInstance) addSpawn(LIVE_BAIUM, npc);
GrandBossManager.getInstance().addBoss(baium); GrandBossManager.getInstance().addBoss(baium);
final L2NpcInstance _baium = baium; final L2NpcInstance _baium = baium;
ThreadPoolManager.getInstance().scheduleGeneral(new Runnable() ThreadPoolManager.getInstance().scheduleGeneral(() ->
{ {
@Override try
public void run()
{ {
try _baium.setIsInvul(true);
{ _baium.setIsImmobilized(true);
_baium.setIsInvul(true); _baium.setRunning();
_baium.setIsImmobilized(true); _baium.broadcastPacket(new SocialAction(_baium.getObjectId(), 2));
_baium.setRunning(); startQuestTimer("baium_wakeup", 15000, _baium, null);
_baium.broadcastPacket(new SocialAction(_baium.getObjectId(), 2)); }
startQuestTimer("baium_wakeup", 15000, _baium, null); catch (final Exception e)
} {
catch (final Exception e) e.printStackTrace();
{
e.printStackTrace();
}
} }
}, 100L); }, 100L);
} }

View File

@@ -16,8 +16,8 @@
*/ */
package ai.individual; package ai.individual;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.ai.CtrlIntention; import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.model.L2CharPosition; import com.l2jmobius.gameserver.model.L2CharPosition;
import com.l2jmobius.gameserver.model.L2Character; import com.l2jmobius.gameserver.model.L2Character;
import com.l2jmobius.gameserver.model.L2Summon; 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.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.math.BigInteger; 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.List;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import java.util.logging.Logger; import java.util.logging.Logger;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.base.Experience; import com.l2jmobius.gameserver.model.base.Experience;
import com.l2jmobius.gameserver.util.FloodProtectorConfig; import com.l2jmobius.gameserver.util.FloodProtectorConfig;
import com.l2jmobius.util.StringUtil; import com.l2jmobius.util.StringUtil;
@@ -46,6 +50,9 @@ import javolution.util.FastMap;
public final class Config public final class Config
{ {
protected static Logger _log = Logger.getLogger(Config.class.getName()); protected static Logger _log = Logger.getLogger(Config.class.getName());
public static final String EOL = System.lineSeparator();
/** Debug/release mode */ /** Debug/release mode */
public static boolean DEBUG; public static boolean DEBUG;
/** Enable/disable assertions */ /** Enable/disable assertions */
@@ -578,8 +585,6 @@ public final class Config
/** Accept multi-items drop ? */ /** Accept multi-items drop ? */
public static boolean MULTIPLE_ITEM_DROP; public static boolean MULTIPLE_ITEM_DROP;
/** Coord Synchronization */
public static int COORD_SYNCHRONIZE;
/** Falling Damage */ /** Falling Damage */
public static boolean ENABLE_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"; public static final String OLYMPIAD_CONFIGURATION_FILE = "config/olympiad.ini";
/** Properties file for extensions configurations */ /** Properties file for extensions configurations */
public static final String EXTENSIONS_CONFIGURATION_FILE = "config/extensions.ini"; 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 */ /** Text file containing hexadecimal value of server ID */
public static final String HEXID_FILE = "./config/hexid.txt"; 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_SUPPORT3_FEE;
public static int CS_SUPPORT4_FEE; public static int CS_SUPPORT4_FEE;
/** GeoData 0/1/2 */ /** GeoData Settings */
public static int GEODATA; public static int PATHFINDING;
public static String GEODATA_DRIVER;
/** Cell PathFinding */
public static boolean GEODATA_CELLFINDING;
public static File PATHNODE_DIR; public static File PATHNODE_DIR;
public static String PATHFIND_BUFFERS; public static String PATHFIND_BUFFERS;
public static float LOW_WEIGHT; public static float LOW_WEIGHT;
@@ -1284,10 +1287,11 @@ public final class Config
public static float DIAGONAL_WEIGHT; public static float DIAGONAL_WEIGHT;
public static int MAX_POSTFILTER_PASSES; public static int MAX_POSTFILTER_PASSES;
public static boolean DEBUG_PATH; public static boolean DEBUG_PATH;
/** Force loading GeoData to physical memory */
public static boolean FORCE_GEODATA; 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 */ /** Max number of buffs */
public static byte BUFFS_MAX_AMOUNT; 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."); 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(); final Properties optionsSettings = new Properties();
try (InputStream is = new FileInputStream(new File(OPTIONS_FILE))) try (InputStream is = new FileInputStream(new File(OPTIONS_FILE)))
{ {
@@ -1392,7 +1435,6 @@ public final class Config
DEBUG = Boolean.parseBoolean(optionsSettings.getProperty("Debug", "false")); DEBUG = Boolean.parseBoolean(optionsSettings.getProperty("Debug", "false"));
ASSERT = Boolean.parseBoolean(optionsSettings.getProperty("Assert", "false")); ASSERT = Boolean.parseBoolean(optionsSettings.getProperty("Assert", "false"));
DEVELOPER = Boolean.parseBoolean(optionsSettings.getProperty("Developer", "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")); TEST_SERVER = Boolean.parseBoolean(optionsSettings.getProperty("TestServer", "false"));
SERVER_LIST_TESTSERVER = 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")); MULTIPLE_ITEM_DROP = Boolean.valueOf(optionsSettings.getProperty("MultipleItemDrop", "True"));
final String str = optionsSettings.getProperty("EnableFallingDamage", "auto"); 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")); ALLOW_WAREHOUSE = Boolean.valueOf(optionsSettings.getProperty("AllowWarehouse", "True"));
WAREHOUSE_CACHE = Boolean.valueOf(optionsSettings.getProperty("WarehouseCache", "False")); 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_TURNON_TIME = Integer.parseInt(optionsSettings.getProperty("GridNeighborTurnOnTime", "1"));
GRID_NEIGHBOR_TURNOFF_TIME = Integer.parseInt(optionsSettings.getProperty("GridNeighborTurnOffTime", "90")); 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 // 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.SummonItemsData;
import com.l2jmobius.gameserver.datatables.TeleportLocationTable; import com.l2jmobius.gameserver.datatables.TeleportLocationTable;
import com.l2jmobius.gameserver.datatables.ZoneTable; 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.AdminCommandHandler;
import com.l2jmobius.gameserver.handler.ItemHandler; import com.l2jmobius.gameserver.handler.ItemHandler;
import com.l2jmobius.gameserver.handler.SkillHandler; 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.AdminEventEngine;
import com.l2jmobius.gameserver.handler.admincommandhandlers.AdminExpSp; import com.l2jmobius.gameserver.handler.admincommandhandlers.AdminExpSp;
import com.l2jmobius.gameserver.handler.admincommandhandlers.AdminFightCalculator; 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.AdminGeodata;
import com.l2jmobius.gameserver.handler.admincommandhandlers.AdminGm; import com.l2jmobius.gameserver.handler.admincommandhandlers.AdminGm;
import com.l2jmobius.gameserver.handler.admincommandhandlers.AdminGmChat; 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.model.entity.Hero;
import com.l2jmobius.gameserver.network.L2GameClient; import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.L2GamePacketHandler; import com.l2jmobius.gameserver.network.L2GamePacketHandler;
import com.l2jmobius.gameserver.pathfinding.PathFinding;
import com.l2jmobius.gameserver.script.faenor.FaenorScriptEngine; import com.l2jmobius.gameserver.script.faenor.FaenorScriptEngine;
import com.l2jmobius.gameserver.scripting.L2ScriptEngineManager; import com.l2jmobius.gameserver.scripting.L2ScriptEngineManager;
import com.l2jmobius.gameserver.taskmanager.AutoAnnounceTaskManager; import com.l2jmobius.gameserver.taskmanager.AutoAnnounceTaskManager;
@@ -359,7 +358,7 @@ public class GameServer
ClanTable.getInstance(); ClanTable.getInstance();
GeoData.getInstance(); GeoData.getInstance();
if (Config.GEODATA == 2) if (Config.PATHFINDING > 0)
{ {
PathFinding.getInstance(); PathFinding.getInstance();
} }
@@ -588,7 +587,6 @@ public class GameServer
_adminCommandHandler.registerAdminCommandHandler(new AdminQuest()); _adminCommandHandler.registerAdminCommandHandler(new AdminQuest());
_adminCommandHandler.registerAdminCommandHandler(new AdminZone()); _adminCommandHandler.registerAdminCommandHandler(new AdminZone());
_adminCommandHandler.registerAdminCommandHandler(new AdminGeodata()); _adminCommandHandler.registerAdminCommandHandler(new AdminGeodata());
_adminCommandHandler.registerAdminCommandHandler(new AdminGeoEditor());
_adminCommandHandler.registerAdminCommandHandler(new AdminManor()); _adminCommandHandler.registerAdminCommandHandler(new AdminManor());
// _adminCommandHandler.registerAdminCommandHandler(new AdminRadar()); // _adminCommandHandler.registerAdminCommandHandler(new AdminRadar());
@@ -630,11 +628,6 @@ public class GameServer
// read pet stats from db // read pet stats from db
L2PetDataTable.getInstance().loadPetsData(); L2PetDataTable.getInstance().loadPetsData();
if (Config.ACCEPT_GEOEDITOR_CONN)
{
GeoEditorListener.getInstance();
}
_shutdownHandler = Shutdown.getInstance(); _shutdownHandler = Shutdown.getInstance();
Runtime.getRuntime().addShutdownHook(_shutdownHandler); 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.Config;
import com.l2jmobius.gameserver.GameTimeController; import com.l2jmobius.gameserver.GameTimeController;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.Territory; import com.l2jmobius.gameserver.Territory;
import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.instancemanager.DimensionalRiftManager; import com.l2jmobius.gameserver.instancemanager.DimensionalRiftManager;
import com.l2jmobius.gameserver.model.L2Attackable; import com.l2jmobius.gameserver.model.L2Attackable;
import com.l2jmobius.gameserver.model.L2CharPosition; import com.l2jmobius.gameserver.model.L2CharPosition;
@@ -976,7 +976,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
} }
// Considering, if bigger range will be attempted // 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 posX = _actor.getX();
int posY = _actor.getY(); int posY = _actor.getY();

View File

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

View File

@@ -27,11 +27,11 @@ import java.util.StringTokenizer;
import java.util.logging.Logger; import java.util.logging.Logger;
import com.l2jmobius.Config; import com.l2jmobius.Config;
import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNodeLoc;
import com.l2jmobius.gameserver.idfactory.IdFactory; import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.instancemanager.ClanHallManager; import com.l2jmobius.gameserver.instancemanager.ClanHallManager;
import com.l2jmobius.gameserver.model.actor.instance.L2DoorInstance; import com.l2jmobius.gameserver.model.actor.instance.L2DoorInstance;
import com.l2jmobius.gameserver.model.entity.ClanHall; import com.l2jmobius.gameserver.model.entity.ClanHall;
import com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc;
import com.l2jmobius.gameserver.templates.L2CharTemplate; import com.l2jmobius.gameserver.templates.L2CharTemplate;
import com.l2jmobius.gameserver.templates.StatsSet; 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 * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * 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; public static final NullRegion INSTANCE = new NullRegion();
private int _size;
public FastNodeList(int size) @Override
public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe)
{ {
_list = new AbstractNode[size]; return true;
} }
public void add(AbstractNode n) @Override
public int getNearestZ(int geoX, int geoY, int worldZ)
{ {
_list[_size] = n; return worldZ;
_size++;
} }
public boolean contains(AbstractNode n) @Override
public int getNextLowerZ(int geoX, int geoY, int worldZ)
{ {
for (int i = 0; i < _size; i++) return worldZ;
{
if (_list[i].equals(n))
{
return true;
}
}
return false;
} }
public boolean containsRev(AbstractNode n) @Override
public int getNextHigherZ(int geoX, int geoY, int worldZ)
{
return worldZ;
}
@Override
public boolean hasGeo()
{ {
for (int i = _size - 1; i >= 0; i--)
{
if (_list[i].equals(n))
{
return true;
}
}
return false; 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

@@ -1,93 +1,87 @@
/* /*
* This file is part of the L2J Mobius project. * This file is part of the L2J Mobius project.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * 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 T _loc;
private AbstractNode _parent; private AbstractNode<T> _parent;
public AbstractNode(AbstractNodeLoc loc) public AbstractNode(T loc)
{ {
_loc = loc; _loc = loc;
} }
public void setParent(AbstractNode p) public void setParent(AbstractNode<T> p)
{ {
_parent = p; _parent = p;
} }
public AbstractNode getParent() public AbstractNode<T> getParent()
{ {
return _parent; return _parent;
} }
public AbstractNodeLoc getLoc() public T getLoc()
{ {
return _loc; return _loc;
} }
public void setLoc(AbstractNodeLoc l) public void setLoc(T l)
{ {
_loc = l; _loc = l;
} }
/** @Override
* @see java.lang.Object#hashCode() public int hashCode()
*/ {
@Override final int prime = 31;
public int hashCode() int result = 1;
{ result = (prime * result) + ((_loc == null) ? 0 : _loc.hashCode());
final int prime = 31; return result;
int result = 1; }
result = (prime * result) + ((_loc == null) ? 0 : _loc.hashCode());
return result; @Override
} public boolean equals(Object obj)
{
/** if (this == obj)
* @see java.lang.Object#equals(java.lang.Object) {
*/ return true;
@Override }
public boolean equals(Object obj) if (obj == null)
{ {
if (this == obj) return false;
{ }
return true; if (!(obj instanceof AbstractNode))
} {
if (obj == null) return false;
{ }
return false; final AbstractNode<?> other = (AbstractNode<?>) obj;
} if (_loc == null)
if (!(obj instanceof AbstractNode)) {
{ if (other._loc != null)
return false; {
} return false;
final AbstractNode other = (AbstractNode) obj; }
if (_loc == null) }
{ else if (!_loc.equals(other._loc))
if (other._loc != null) {
{ return false;
return false; }
} return true;
} }
else if (!_loc.equals(other._loc))
{
return false;
}
return true;
}
} }

View File

@@ -1,35 +1,33 @@
/* /*
* This file is part of the L2J Mobius project. * This file is part of the L2J Mobius project.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * 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- * @author -Nemesiss-
*/ */
public abstract class AbstractNodeLoc public abstract class AbstractNodeLoc
{ {
public abstract int getX(); public abstract int getX();
public abstract int getY(); public abstract int getY();
public abstract int getZ(); public abstract int getZ();
public abstract void setZ(short z); public abstract int getNodeX();
public abstract int getNodeX(); public abstract int getNodeY();
}
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

@@ -1,70 +1,69 @@
/* /*
* This file is part of the L2J Mobius project. * This file is part of the L2J Mobius project.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * 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.geodata.pathfinding.AbstractNode;
import com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc;
public class CellNode extends AbstractNode<NodeLoc>
public class CellNode extends AbstractNode {
{ private CellNode _next = null;
private CellNode _next = null; private boolean _isInUse = true;
private boolean _isInUse = true; private float _cost = -1000;
private float _cost = -1000;
public CellNode(NodeLoc loc)
public CellNode(AbstractNodeLoc loc) {
{ super(loc);
super(loc); }
}
public boolean isInUse()
public boolean isInUse() {
{ return _isInUse;
return _isInUse; }
}
public void setInUse()
public void setInUse() {
{ _isInUse = true;
_isInUse = true; }
}
public CellNode getNext()
public CellNode getNext() {
{ return _next;
return _next; }
}
public void setNext(CellNode next)
public void setNext(CellNode next) {
{ _next = next;
_next = next; }
}
public float getCost()
public float getCost() {
{ return _cost;
return _cost; }
}
public void setCost(double cost)
public void setCost(double cost) {
{ _cost = (float) cost;
_cost = (float) cost; }
}
public void free()
public void free() {
{ setParent(null);
setParent(null); _cost = -1000;
_cost = -1000; _isInUse = false;
_isInUse = false; _next = null;
_next = null; }
}
} }

View File

@@ -1,364 +1,361 @@
/* /*
* This file is part of the L2J Mobius project. * This file is part of the L2J Mobius project.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * 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.concurrent.locks.ReentrantLock; import java.util.LinkedList;
import java.util.List;
import com.l2jmobius.Config; import java.util.concurrent.locks.ReentrantLock;
import javolution.util.FastList; import com.l2jmobius.Config;
/** /**
* @author DS Credits to Diamond * @author DS Credits to Diamond
*/ */
public class CellNodeBuffer public class CellNodeBuffer
{ {
private static final int MAX_ITERATIONS = 3500; private static final int MAX_ITERATIONS = 3500;
private final ReentrantLock _lock = new ReentrantLock(); private final ReentrantLock _lock = new ReentrantLock();
private final int _mapSize; private final int _mapSize;
private final CellNode[][] _buffer; private final CellNode[][] _buffer;
private int _baseX = 0; private int _baseX = 0;
private int _baseY = 0; private int _baseY = 0;
private int _targetX = 0; private int _targetX = 0;
private int _targetY = 0; private int _targetY = 0;
private int _targetZ = 0; private int _targetZ = 0;
private long _timeStamp = 0; private long _timeStamp = 0;
private long _lastElapsedTime = 0; private long _lastElapsedTime = 0;
private CellNode _current = null; private CellNode _current = null;
public CellNodeBuffer(int size) public CellNodeBuffer(int size)
{ {
_mapSize = size; _mapSize = size;
_buffer = new CellNode[_mapSize][_mapSize]; _buffer = new CellNode[_mapSize][_mapSize];
} }
public final boolean lock() public final boolean lock()
{ {
return _lock.tryLock(); return _lock.tryLock();
} }
public final CellNode findPath(int x, int y, int z, int tx, int ty, int tz) public final CellNode findPath(int x, int y, int z, int tx, int ty, int tz)
{ {
_timeStamp = System.currentTimeMillis(); _timeStamp = System.currentTimeMillis();
_baseX = x + ((tx - x - _mapSize) / 2); // middle of the line (x,y) - (tx,ty) _baseX = x + ((tx - x - _mapSize) / 2); // middle of the line (x,y) - (tx,ty)
_baseY = y + ((ty - y - _mapSize) / 2); // will be in the center of the buffer _baseY = y + ((ty - y - _mapSize) / 2); // will be in the center of the buffer
_targetX = tx; _targetX = tx;
_targetY = ty; _targetY = ty;
_targetZ = tz; _targetZ = tz;
_current = getNode(x, y, z); _current = getNode(x, y, z);
_current.setCost(getCost(x, y, z, Config.HIGH_WEIGHT)); _current.setCost(getCost(x, y, z, Config.HIGH_WEIGHT));
for (int count = 0; count < MAX_ITERATIONS; count++) for (int count = 0; count < MAX_ITERATIONS; count++)
{ {
if ((_current.getLoc().getNodeX() == _targetX) && (_current.getLoc().getNodeY() == _targetY) && (Math.abs(_current.getLoc().getZ() - _targetZ) < 64)) if ((_current.getLoc().getNodeX() == _targetX) && (_current.getLoc().getNodeY() == _targetY) && (Math.abs(_current.getLoc().getZ() - _targetZ) < 64))
{ {
return _current; // found return _current; // found
} }
getNeighbors(); getNeighbors();
if (_current.getNext() == null) if (_current.getNext() == null)
{ {
return null; // no more ways return null; // no more ways
} }
_current = _current.getNext(); _current = _current.getNext();
} }
return null; return null;
} }
public final void free() public final void free()
{ {
_current = null; _current = null;
CellNode node; CellNode node;
for (int i = 0; i < _mapSize; i++) for (int i = 0; i < _mapSize; i++)
{ {
for (int j = 0; j < _mapSize; j++) for (int j = 0; j < _mapSize; j++)
{ {
node = _buffer[i][j]; node = _buffer[i][j];
if (node != null) if (node != null)
{ {
node.free(); node.free();
} }
} }
} }
_lock.unlock(); _lock.unlock();
_lastElapsedTime = System.currentTimeMillis() - _timeStamp; _lastElapsedTime = System.currentTimeMillis() - _timeStamp;
} }
public final long getElapsedTime() public final long getElapsedTime()
{ {
return _lastElapsedTime; 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()) for (CellNode n = _current; n.getParent() != null; n = (CellNode) n.getParent())
{ {
result.add(n); result.add(n);
n.setCost(-n.getCost()); n.setCost(-n.getCost());
} }
for (int i = 0; i < _mapSize; i++) for (int i = 0; i < _mapSize; i++)
{ {
for (int j = 0; j < _mapSize; j++) for (int j = 0; j < _mapSize; j++)
{ {
final CellNode n = _buffer[i][j]; final CellNode n = _buffer[i][j];
if ((n == null) || !n.isInUse() || (n.getCost() <= 0)) if ((n == null) || !n.isInUse() || (n.getCost() <= 0))
{ {
continue; continue;
} }
result.add(n); result.add(n);
} }
} }
return result; return result;
} }
private final void getNeighbors() private void getNeighbors()
{ {
if (((NodeLoc) _current.getLoc()).canGoNone()) if (!_current.getLoc().canGoAll())
{ {
return; return;
} }
final int x = _current.getLoc().getNodeX(); final int x = _current.getLoc().getNodeX();
final int y = _current.getLoc().getNodeY(); final int y = _current.getLoc().getNodeY();
final int z = _current.getLoc().getZ(); final int z = _current.getLoc().getZ();
CellNode nodeE = null; CellNode nodeE = null;
CellNode nodeS = null; CellNode nodeS = null;
CellNode nodeW = null; CellNode nodeW = null;
CellNode nodeN = null; CellNode nodeN = null;
// East // East
if (((NodeLoc) _current.getLoc()).canGoEast()) if (_current.getLoc().canGoEast())
{ {
nodeE = addNode(x + 1, y, z, false); nodeE = addNode(x + 1, y, z, false);
} }
// South // South
if (((NodeLoc) _current.getLoc()).canGoSouth()) if (_current.getLoc().canGoSouth())
{ {
nodeS = addNode(x, y + 1, z, false); nodeS = addNode(x, y + 1, z, false);
} }
// West // West
if (((NodeLoc) _current.getLoc()).canGoWest()) if (_current.getLoc().canGoWest())
{ {
nodeW = addNode(x - 1, y, z, false); nodeW = addNode(x - 1, y, z, false);
} }
// North // North
if (((NodeLoc) _current.getLoc()).canGoNorth()) if (_current.getLoc().canGoNorth())
{ {
nodeN = addNode(x, y - 1, z, false); nodeN = addNode(x, y - 1, z, false);
} }
if (Config.ADVANCED_DIAGONAL_STRATEGY) if (Config.ADVANCED_DIAGONAL_STRATEGY)
{ {
// SouthEast // SouthEast
if ((nodeE != null) && (nodeS != null)) 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); addNode(x + 1, y + 1, z, true);
} }
} }
// SouthWest // SouthWest
if ((nodeS != null) && (nodeW != null)) 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); addNode(x - 1, y + 1, z, true);
} }
} }
// NorthEast // NorthEast
if ((nodeN != null) && (nodeE != null)) 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); addNode(x + 1, y - 1, z, true);
} }
} }
// NorthWest // NorthWest
if ((nodeN != null) && (nodeW != null)) 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); addNode(x - 1, y - 1, z, true);
} }
} }
} }
} }
private final CellNode getNode(int x, int y, int z) private CellNode getNode(int x, int y, int z)
{ {
final int aX = x - _baseX; final int aX = x - _baseX;
if ((aX < 0) || (aX >= _mapSize)) if ((aX < 0) || (aX >= _mapSize))
{ {
return null; return null;
} }
final int aY = y - _baseY; final int aY = y - _baseY;
if ((aY < 0) || (aY >= _mapSize)) if ((aY < 0) || (aY >= _mapSize))
{ {
return null; return null;
} }
CellNode result = _buffer[aX][aY]; CellNode result = _buffer[aX][aY];
if (result == null) if (result == null)
{ {
result = new CellNode(new NodeLoc(x, y, z)); result = new CellNode(new NodeLoc(x, y, z));
_buffer[aX][aY] = result; _buffer[aX][aY] = result;
} }
else if (!result.isInUse()) else if (!result.isInUse())
{ {
result.setInUse(); result.setInUse();
// reinit node if needed // reinit node if needed
if (result.getLoc() != null) if (result.getLoc() != null)
{ {
((NodeLoc) result.getLoc()).set(x, y, z); result.getLoc().set(x, y, z);
} }
else else
{ {
result.setLoc(new NodeLoc(x, y, z)); result.setLoc(new NodeLoc(x, y, z));
} }
} }
return result; 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); final CellNode newNode = getNode(x, y, z);
if (newNode == null) if (newNode == null)
{ {
return null; return null;
} }
if (newNode.getCost() >= 0) if (newNode.getCost() >= 0)
{ {
return newNode; return newNode;
} }
final int geoZ = newNode.getLoc().getZ(); final int geoZ = newNode.getLoc().getZ();
final int stepZ = Math.abs(geoZ - _current.getLoc().getZ()); final int stepZ = Math.abs(geoZ - _current.getLoc().getZ());
float weight = diagonal ? Config.DIAGONAL_WEIGHT : Config.LOW_WEIGHT; 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; weight = Config.HIGH_WEIGHT;
} }
else else if (isHighWeight(x + 1, y, geoZ))
{ {
if (isHighWeight(x + 1, y, geoZ)) weight = Config.MEDIUM_WEIGHT;
{ }
weight = Config.MEDIUM_WEIGHT; else if (isHighWeight(x - 1, y, geoZ))
} {
else if (isHighWeight(x - 1, y, geoZ)) weight = Config.MEDIUM_WEIGHT;
{ }
weight = Config.MEDIUM_WEIGHT; else if (isHighWeight(x, y + 1, geoZ))
} {
else if (isHighWeight(x, y + 1, geoZ)) weight = Config.MEDIUM_WEIGHT;
{ }
weight = Config.MEDIUM_WEIGHT; else if (isHighWeight(x, y - 1, geoZ))
} {
else if (isHighWeight(x, y - 1, geoZ)) weight = Config.MEDIUM_WEIGHT;
{ }
weight = Config.MEDIUM_WEIGHT;
} newNode.setParent(_current);
} newNode.setCost(getCost(x, y, geoZ, weight));
newNode.setParent(_current); CellNode node = _current;
newNode.setCost(getCost(x, y, geoZ, weight)); int count = 0;
while ((node.getNext() != null) && (count < (MAX_ITERATIONS * 4)))
CellNode node = _current; {
int count = 0; count++;
while ((node.getNext() != null) && (count < (MAX_ITERATIONS * 4))) if (node.getNext().getCost() > newNode.getCost())
{ {
count++; // insert node into a chain
if (node.getNext().getCost() > newNode.getCost()) newNode.setNext(node.getNext());
{ break;
// insert node into a chain }
newNode.setNext(node.getNext()); node = node.getNext();
break; }
} if (count == (MAX_ITERATIONS * 4))
node = node.getNext(); {
} System.err.println("Pathfinding: too long loop detected, cost:" + newNode.getCost());
if (count == (MAX_ITERATIONS * 4)) }
{
System.err.println("Pathfinding: too long loop detected, cost:" + newNode.getCost()); node.setNext(newNode); // add last
}
return newNode;
node.setNext(newNode); // add last }
return newNode; private boolean isHighWeight(int x, int y, int z)
} {
final CellNode result = getNode(x, y, z);
private final boolean isHighWeight(int x, int y, int z) if (result == null)
{ {
final CellNode result = getNode(x, y, z); return true;
if (result == null) }
{
return true; if (!result.getLoc().canGoAll())
} {
return true;
if (!((NodeLoc) result.getLoc()).canGoAll()) }
{ if (Math.abs(result.getLoc().getZ() - z) > 16)
return true; {
} return true;
if (Math.abs(result.getLoc().getZ() - z) > 16) }
{
return true; return false;
} }
return false; private double getCost(int x, int y, int z, float weight)
} {
final int dX = x - _targetX;
private final double getCost(int x, int y, int z, float weight) final int dY = y - _targetY;
{ final int dZ = z - _targetZ;
final int dX = x - _targetX; // Math.abs(dx) + Math.abs(dy) + Math.abs(dz) / 16
final int dY = y - _targetY; double result = Math.sqrt((dX * dX) + (dY * dY) + ((dZ * dZ) / 256.0));
final int dZ = z - _targetZ; if (result > weight)
// Math.abs(dx) + Math.abs(dy) + Math.abs(dz) / 16 {
double result = Math.sqrt((dX * dX) + (dY * dY) + ((dZ * dZ) / 256)); result += weight;
if (result > weight) }
{
result += weight; if (result > Float.MAX_VALUE)
} {
result = Float.MAX_VALUE;
if (result > Float.MAX_VALUE) }
{
result = Float.MAX_VALUE; return result;
} }
return result;
}
} }

View File

@@ -1,413 +1,439 @@
/* /*
* This file is part of the L2J Mobius project. * This file is part of the L2J Mobius project.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * 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.ArrayList;
import java.util.List; import java.util.LinkedList;
import java.util.ListIterator; import java.util.List;
import java.util.logging.Logger; import java.util.ListIterator;
import java.util.concurrent.CopyOnWriteArrayList;
import com.l2jmobius.Config; import java.util.logging.Level;
import com.l2jmobius.gameserver.GeoData; import java.util.logging.Logger;
import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.model.L2ItemInstance; import com.l2jmobius.Config;
import com.l2jmobius.gameserver.pathfinding.AbstractNode; import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc; import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNode;
import com.l2jmobius.gameserver.pathfinding.PathFinding; import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNodeLoc;
import com.l2jmobius.util.StringUtil; import com.l2jmobius.gameserver.geodata.pathfinding.PathFinding;
import com.l2jmobius.gameserver.idfactory.IdFactory;
import javolution.util.FastList; import com.l2jmobius.gameserver.model.Inventory;
import com.l2jmobius.gameserver.model.L2ItemInstance;
/**
* @author Sami, DS Credits to Diamond /**
*/ * @author Sami, DS Credits to Diamond
public class CellPathFinding extends PathFinding */
{ public class CellPathFinding extends PathFinding
private static final Logger _log = Logger.getLogger(CellPathFinding.class.getName()); {
private BufferInfo[] _allBuffers; private static final Logger _log = Logger.getLogger(CellPathFinding.class.getName());
private int _findSuccess = 0; private BufferInfo[] _allBuffers;
private int _findFails = 0; private int _findSuccess = 0;
private int _postFilterUses = 0; private int _findFails = 0;
private int _postFilterPlayableUses = 0; private int _postFilterUses = 0;
private int _postFilterPasses = 0; private int _postFilterPlayableUses = 0;
private long _postFilterElapsed = 0; private int _postFilterPasses = 0;
private long _postFilterElapsed = 0;
private FastList<L2ItemInstance> _debugItems = null;
private List<L2ItemInstance> _debugItems = null;
private static CellPathFinding _instance;
public static CellPathFinding getInstance()
public static CellPathFinding getInstance() {
{ return SingletonHolder._instance;
if (_instance == null) }
{
_instance = new CellPathFinding(); protected CellPathFinding()
} {
return _instance; try
} {
final String[] array = Config.PATHFIND_BUFFERS.split(";");
private CellPathFinding()
{ _allBuffers = new BufferInfo[array.length];
try
{ String buf;
final String[] array = Config.PATHFIND_BUFFERS.split(";"); String[] args;
for (int i = 0; i < array.length; i++)
_allBuffers = new BufferInfo[array.length]; {
buf = array[i];
String buf; args = buf.split("x");
String[] args; if (args.length != 2)
for (int i = 0; i < array.length; i++) {
{ throw new Exception("Invalid buffer definition: " + buf);
buf = array[i]; }
args = buf.split("x");
if (args.length != 2) _allBuffers[i] = new BufferInfo(Integer.parseInt(args[0]), Integer.parseInt(args[1]));
{ }
throw new Exception("Invalid buffer definition: " + buf); }
} catch (Exception e)
{
_allBuffers[i] = new BufferInfo(Integer.parseInt(args[0]), Integer.parseInt(args[1])); _log.log(Level.WARNING, "CellPathFinding: Problem during buffer init: " + e.getMessage(), e);
} throw new Error("CellPathFinding: load aborted");
} }
catch (final Exception e) }
{
_log.warning("CellPathFinding: Problem during buffer init: " + e.getMessage()); @Override
throw new Error("CellPathFinding: load aborted"); public boolean pathNodesExist(short regionoffset)
} {
} return false;
}
/**
* @see com.l2jmobius.gameserver.pathfinding.PathFinding#pathNodesExist(short) @Override
*/ public List<AbstractNodeLoc> findPath(int x, int y, int z, int tx, int ty, int tz, boolean playable)
@Override {
public boolean pathNodesExist(short regionoffset) final int gx = GeoData.getInstance().getGeoX(x);
{ final int gy = GeoData.getInstance().getGeoY(y);
return false; if (!GeoData.getInstance().hasGeo(x, y))
} {
return null;
@Override }
public List<AbstractNodeLoc> findPath(int x, int y, int z, int tx, int ty, int tz, boolean playable) final int gz = GeoData.getInstance().getHeight(x, y, z);
{ final int gtx = GeoData.getInstance().getGeoX(tx);
final int gx = GeoData.getInstance().getGeoX(x); final int gty = GeoData.getInstance().getGeoY(ty);
final int gy = GeoData.getInstance().getGeoY(y); if (!GeoData.getInstance().hasGeo(tx, ty))
if (!GeoData.getInstance().hasGeo(x, y)) {
{ return null;
return null; }
} final int gtz = GeoData.getInstance().getHeight(tx, ty, tz);
final int gz = GeoData.getInstance().getHeight(x, y, z); final CellNodeBuffer buffer = alloc(64 + (2 * Math.max(Math.abs(gx - gtx), Math.abs(gy - gty))), playable);
final int gtx = GeoData.getInstance().getGeoX(tx); if (buffer == null)
final int gty = GeoData.getInstance().getGeoY(ty); {
if (!GeoData.getInstance().hasGeo(tx, ty)) return null;
{ }
return null;
} final boolean debug = playable && Config.DEBUG_PATH;
final int gtz = GeoData.getInstance().getHeight(tx, ty, tz);
final CellNodeBuffer buffer = alloc(64 + (2 * Math.max(Math.abs(gx - gtx), Math.abs(gy - gty))), playable); if (debug)
if (buffer == null) {
{ if (_debugItems == null)
return null; {
} _debugItems = new CopyOnWriteArrayList<>();
}
final boolean debug = playable && Config.DEBUG_PATH; else
{
if (debug) for (L2ItemInstance item : _debugItems)
{ {
if (_debugItems == null) if (item == null)
{ {
_debugItems = new FastList<>(); continue;
} }
else item.decayMe();
{ }
for (final L2ItemInstance item : _debugItems)
{ _debugItems.clear();
if (item == null) }
{ }
continue;
} List<AbstractNodeLoc> path = null;
item.decayMe(); try
} {
final CellNode result = buffer.findPath(gx, gy, gz, gtx, gty, gtz);
_debugItems.clear();
} if (debug)
} {
for (CellNode n : buffer.debugPath())
FastList<AbstractNodeLoc> path = null; {
try if (n.getCost() < 0)
{ {
final CellNode result = buffer.findPath(gx, gy, gz, gtx, gty, gtz); dropDebugItem(1831, (int) (-n.getCost() * 10), n.getLoc());
}
if (debug) else
{ {
for (final CellNode n : buffer.debugPath()) // known nodes
{ dropDebugItem(Inventory.ADENA_ID, (int) (n.getCost() * 10), n.getLoc());
if (n.getCost() < 0) }
{ }
dropDebugItem(1831, (int) (-n.getCost() * 10), n.getLoc()); }
}
else if (result == null)
{ {
dropDebugItem(57, (int) (n.getCost() * 10), n.getLoc()); _findFails++;
} return null;
} }
}
path = constructPath(result);
if (result == null) }
{ catch (Exception e)
_findFails++; {
return null; _log.log(Level.WARNING, "", e);
} return null;
}
path = constructPath(result); finally
} {
catch (final Exception e) buffer.free();
{ }
e.printStackTrace();
return null; if ((path.size() < 3) || (Config.MAX_POSTFILTER_PASSES <= 0))
} {
finally _findSuccess++;
{ return path;
buffer.free(); }
}
final long timeStamp = System.currentTimeMillis();
if ((path.size() < 3) || (Config.MAX_POSTFILTER_PASSES <= 0)) _postFilterUses++;
{ if (playable)
_findSuccess++; {
return path; _postFilterPlayableUses++;
} }
final long timeStamp = System.currentTimeMillis(); int currentX, currentY, currentZ;
_postFilterUses++; ListIterator<AbstractNodeLoc> middlePoint;
if (playable) boolean remove;
{ int pass = 0;
_postFilterPlayableUses++; do
} {
pass++;
int currentX, currentY, currentZ; _postFilterPasses++;
ListIterator<AbstractNodeLoc> middlePoint, endPoint;
AbstractNodeLoc locMiddle, locEnd; remove = false;
boolean remove; middlePoint = path.listIterator();
int pass = 0; currentX = x;
do currentY = y;
{ currentZ = z;
pass++;
_postFilterPasses++; while (middlePoint.hasNext())
{
remove = false; final AbstractNodeLoc locMiddle = middlePoint.next();
middlePoint = path.listIterator(); if (!middlePoint.hasNext())
endPoint = path.listIterator(1); {
locEnd = null; break;
currentX = x; }
currentY = y;
currentZ = z; final AbstractNodeLoc locEnd = path.get(middlePoint.nextIndex());
if (GeoData.getInstance().canMove(currentX, currentY, currentZ, locEnd.getX(), locEnd.getY(), locEnd.getZ()))
while (endPoint.hasNext()) {
{ middlePoint.remove();
locEnd = endPoint.next(); remove = true;
locMiddle = middlePoint.next(); if (debug)
if (GeoData.getInstance().canMove(currentX, currentY, currentZ, locEnd.getX(), locEnd.getY(), locEnd.getZ())) {
{ dropDebugItem(735, 1, locMiddle);
middlePoint.remove(); }
remove = true; }
if (debug) else
{ {
dropDebugItem(735, 1, locMiddle); currentX = locMiddle.getX();
} currentY = locMiddle.getY();
} currentZ = locMiddle.getZ();
else }
{ }
currentX = locMiddle.getX(); }
currentY = locMiddle.getY(); // only one postfilter pass for AI
currentZ = locMiddle.getZ(); while (playable && remove && (path.size() > 2) && (pass < Config.MAX_POSTFILTER_PASSES));
}
} if (debug)
} {
// only one postfilter pass for AI path.forEach(n -> dropDebugItem(65, 1, n));
while (playable && remove && (path.size() > 2) && (pass < Config.MAX_POSTFILTER_PASSES)); }
if (debug) _findSuccess++;
{ _postFilterElapsed += System.currentTimeMillis() - timeStamp;
middlePoint = path.listIterator(); return path;
while (middlePoint.hasNext()) }
{
locMiddle = middlePoint.next(); private List<AbstractNodeLoc> constructPath(AbstractNode<NodeLoc> node)
dropDebugItem(65, 1, locMiddle); {
} final LinkedList<AbstractNodeLoc> path = new LinkedList<>();
} int previousDirectionX = Integer.MIN_VALUE;
int previousDirectionY = Integer.MIN_VALUE;
_findSuccess++; int directionX, directionY;
_postFilterElapsed += System.currentTimeMillis() - timeStamp;
return path; while (node.getParent() != null)
} {
if (!Config.ADVANCED_DIAGONAL_STRATEGY && (node.getParent().getParent() != null))
private FastList<AbstractNodeLoc> constructPath(AbstractNode node) {
{ final int tmpX = node.getLoc().getNodeX() - node.getParent().getParent().getLoc().getNodeX();
final FastList<AbstractNodeLoc> path = new FastList<>(); final int tmpY = node.getLoc().getNodeY() - node.getParent().getParent().getLoc().getNodeY();
int previousDirectionX = Integer.MIN_VALUE; if (Math.abs(tmpX) == Math.abs(tmpY))
int previousDirectionY = Integer.MIN_VALUE; {
int directionX, directionY; directionX = tmpX;
directionY = tmpY;
while (node.getParent() != null) }
{ else
if (!Config.ADVANCED_DIAGONAL_STRATEGY && (node.getParent().getParent() != null)) {
{ directionX = node.getLoc().getNodeX() - node.getParent().getLoc().getNodeX();
final int tmpX = node.getLoc().getNodeX() - node.getParent().getParent().getLoc().getNodeX(); directionY = node.getLoc().getNodeY() - node.getParent().getLoc().getNodeY();
final int tmpY = node.getLoc().getNodeY() - node.getParent().getParent().getLoc().getNodeY(); }
if (Math.abs(tmpX) == Math.abs(tmpY)) }
{ else
directionX = tmpX; {
directionY = tmpY; directionX = node.getLoc().getNodeX() - node.getParent().getLoc().getNodeX();
} directionY = node.getLoc().getNodeY() - node.getParent().getLoc().getNodeY();
else }
{
directionX = node.getLoc().getNodeX() - node.getParent().getLoc().getNodeX(); // only add a new route point if moving direction changes
directionY = node.getLoc().getNodeY() - node.getParent().getLoc().getNodeY(); if ((directionX != previousDirectionX) || (directionY != previousDirectionY))
} {
} previousDirectionX = directionX;
else previousDirectionY = directionY;
{
directionX = node.getLoc().getNodeX() - node.getParent().getLoc().getNodeX(); path.addFirst(node.getLoc());
directionY = node.getLoc().getNodeY() - node.getParent().getLoc().getNodeY(); node.setLoc(null);
} }
// only add a new route point if moving direction changes node = node.getParent();
if ((directionX != previousDirectionX) || (directionY != previousDirectionY)) }
{
previousDirectionX = directionX; return path;
previousDirectionY = directionY; }
path.addFirst(node.getLoc()); private CellNodeBuffer alloc(int size, boolean playable)
node.setLoc(null); {
} CellNodeBuffer current = null;
for (BufferInfo i : _allBuffers)
node = node.getParent(); {
} if (i.mapSize >= size)
{
return path; for (CellNodeBuffer buf : i.bufs)
} {
if (buf.lock())
private final CellNodeBuffer alloc(int size, boolean playable) {
{ i.uses++;
CellNodeBuffer current = null; if (playable)
for (final BufferInfo i : _allBuffers) {
{ i.playableUses++;
if (i.mapSize >= size) }
{ i.elapsed += buf.getElapsedTime();
for (final CellNodeBuffer buf : i.bufs) current = buf;
{ break;
if (buf.lock()) }
{ }
i.uses++; if (current != null)
if (playable) {
{ break;
i.playableUses++; }
}
i.elapsed += buf.getElapsedTime(); // not found, allocate temporary buffer
current = buf; current = new CellNodeBuffer(i.mapSize);
break; current.lock();
} if (i.bufs.size() < i.count)
} {
if (current != null) i.bufs.add(current);
{ i.uses++;
break; if (playable)
} {
i.playableUses++;
// not found, allocate temporary buffer }
current = new CellNodeBuffer(i.mapSize); break;
current.lock(); }
if (i.bufs.size() < i.count)
{ i.overflows++;
i.bufs.add(current); if (playable)
i.uses++; {
if (playable) i.playableOverflows++;
{ // System.err.println("Overflow, size requested: " + size + " playable:"+playable);
i.playableUses++; }
} }
break; }
}
return current;
i.overflows++; }
if (playable)
{ private void dropDebugItem(int itemId, int num, AbstractNodeLoc loc)
i.playableOverflows++; {
} final L2ItemInstance item = new L2ItemInstance(IdFactory.getInstance().getNextId(), itemId);
} item.setCount(num);
} item.spawnMe(loc.getX(), loc.getY(), loc.getZ());
_debugItems.add(item);
return current; }
}
private static final class BufferInfo
private final void dropDebugItem(int itemId, int num, AbstractNodeLoc loc) {
{ final int mapSize;
final L2ItemInstance item = new L2ItemInstance(IdFactory.getInstance().getNextId(), itemId); final int count;
item.setCount(num); ArrayList<CellNodeBuffer> bufs;
item.spawnMe(loc.getX(), loc.getY(), loc.getZ()); int uses = 0;
_debugItems.add(item); int playableUses = 0;
} int overflows = 0;
int playableOverflows = 0;
private static final class BufferInfo long elapsed = 0;
{
final int mapSize; public BufferInfo(int size, int cnt)
final int count; {
ArrayList<CellNodeBuffer> bufs; mapSize = size;
int uses = 0; count = cnt;
int playableUses = 0; bufs = new ArrayList<>(count);
int overflows = 0; }
int playableOverflows = 0;
long elapsed = 0; @Override
public String toString()
public BufferInfo(int size, int cnt) {
{ final StringBuilder sb = new StringBuilder(100);
mapSize = size; sb.append(mapSize);
count = cnt; sb.append("x");
bufs = new ArrayList<>(count); sb.append(mapSize);
} sb.append(" num:");
sb.append(bufs.size());
@Override sb.append("/");
public String toString() sb.append(count);
{ sb.append(" uses:");
final StringBuilder stat = new StringBuilder(100); sb.append(uses);
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)); sb.append("/");
if (uses > 0) 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);
StringUtil.append(stat, " ovf:", String.valueOf(overflows), "/", String.valueOf(playableOverflows)); sb.append("/");
sb.append(String.format("%1.2f", (double) elapsed / uses));
return stat.toString(); }
}
} sb.append(" ovf:");
sb.append(overflows);
@Override sb.append("/");
public String[] getStat() sb.append(playableOverflows);
{
final String[] result = new String[_allBuffers.length + 1]; return sb.toString();
for (int i = 0; i < _allBuffers.length; i++) }
{ }
result[i] = _allBuffers[i].toString();
} @Override
public String[] getStat()
final StringBuilder stat = new StringBuilder(100); {
StringUtil.append(stat, "LOS postfilter uses:", String.valueOf(_postFilterUses), "/", String.valueOf(_postFilterPlayableUses)); final String[] result = new String[_allBuffers.length + 1];
if (_postFilterUses > 0) for (int i = 0; i < _allBuffers.length; i++)
{ {
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"); result[i] = _allBuffers[i].toString();
} }
StringUtil.append(stat, "Pathfind success/fail:", String.valueOf(_findSuccess), "/", String.valueOf(_findFails));
result[result.length - 1] = stat.toString(); final StringBuilder sb = new StringBuilder(128);
sb.append("LOS postfilter uses:");
return result; sb.append(_postFilterUses);
} sb.append("/");
} sb.append(_postFilterPlayableUses);
if (_postFilterUses > 0)
{
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);
}
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

@@ -1,215 +1,184 @@
/* /*
* This file is part of the L2J Mobius project. * This file is part of the L2J Mobius project.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * 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.geodata.GeoData;
import com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc; import com.l2jmobius.gameserver.geodata.geodriver.Cell;
import com.l2jserver.gameserver.geoengine.Direction; import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNodeLoc;
/** /**
* @author -Nemesiss-, FBIagent * @author -Nemesiss-, HorridoJoho
*/ */
public class NodeLoc extends AbstractNodeLoc public class NodeLoc extends AbstractNodeLoc
{ {
private int _x; private int _x;
private int _y; private int _y;
private boolean _goNorth; private boolean _goNorth;
private boolean _goEast; private boolean _goEast;
private boolean _goSouth; private boolean _goSouth;
private boolean _goWest; private boolean _goWest;
private int _geoHeight; private int _geoHeight;
public NodeLoc(int x, int y, int z) public NodeLoc(int x, int y, int z)
{ {
set(x, y, z); set(x, y, z);
} }
public void set(int x, int y, int z) public void set(int x, int y, int z)
{ {
_x = x; _x = x;
_y = y; _y = y;
_goNorth = GeoData.getInstance().canEnterNeighbors(x, y, z, Direction.NORTH); _goNorth = GeoData.getInstance().checkNearestNswe(x, y, z, Cell.NSWE_NORTH);
_goEast = GeoData.getInstance().canEnterNeighbors(x, y, z, Direction.EAST); _goEast = GeoData.getInstance().checkNearestNswe(x, y, z, Cell.NSWE_EAST);
_goSouth = GeoData.getInstance().canEnterNeighbors(x, y, z, Direction.SOUTH); _goSouth = GeoData.getInstance().checkNearestNswe(x, y, z, Cell.NSWE_SOUTH);
_goWest = GeoData.getInstance().canEnterNeighbors(x, y, z, Direction.WEST); _goWest = GeoData.getInstance().checkNearestNswe(x, y, z, Cell.NSWE_WEST);
_geoHeight = GeoData.getInstance().getNearestZ(x, y, z); _geoHeight = GeoData.getInstance().getNearestZ(x, y, z);
} }
public boolean canGoNorth() public boolean canGoNorth()
{ {
return _goNorth; return _goNorth;
} }
public boolean canGoEast() public boolean canGoEast()
{ {
return _goEast; return _goEast;
} }
public boolean canGoSouth() public boolean canGoSouth()
{ {
return _goSouth; return _goSouth;
} }
public boolean canGoWest() public boolean canGoWest()
{ {
return _goWest; return _goWest;
} }
public boolean canGoNone() public boolean canGoAll()
{ {
return !canGoNorth() && !canGoEast() && !canGoSouth() && !canGoWest(); return canGoNorth() && canGoEast() && canGoSouth() && canGoWest();
} }
public boolean canGoAll() @Override
{ public int getX()
return canGoNorth() && canGoEast() && canGoSouth() && canGoWest(); {
} return GeoData.getInstance().getWorldX(_x);
}
/**
* @see com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc#getX() @Override
*/ public int getY()
@Override {
public int getX() return GeoData.getInstance().getWorldY(_y);
{ }
return GeoData.getInstance().getWorldX(_x);
} @Override
public int getZ()
/** {
* @see com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc#getY() return _geoHeight;
*/ }
@Override
public int getY() @Override
{ public int getNodeX()
return GeoData.getInstance().getWorldY(_y); {
} return _x;
}
/**
* @see com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc#getZ() @Override
*/ public int getNodeY()
@Override {
public int getZ() return _y;
{ }
return _geoHeight;
} @Override
public int hashCode()
@Override {
public void setZ(short z) final int prime = 31;
{ int result = 1;
// do nothing here result = (prime * result) + _x;
} result = (prime * result) + _y;
/** int nswe = 0;
* @see com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc#getNodeX() if (canGoNorth())
*/ {
@Override nswe |= Cell.NSWE_NORTH;
public int getNodeX() }
{ if (canGoEast())
return _x; {
} nswe |= Cell.NSWE_EAST;
}
/** if (canGoSouth())
* @see com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc#getNodeY() {
*/ nswe |= Cell.NSWE_SOUTH;
@Override }
public int getNodeY() if (canGoWest())
{ {
return _y; nswe |= Cell.NSWE_WEST;
} }
/** result = (prime * result) + (((_geoHeight & 0xFFFF) << 1) | nswe);
* @see java.lang.Object#hashCode() return result;
*/ // return super.hashCode();
@Override }
public int hashCode()
{ @Override
final int prime = 31; public boolean equals(Object obj)
int result = 1; {
result = (prime * result) + _x; if (this == obj)
result = (prime * result) + _y; {
return true;
byte nswe = 0; }
if (canGoNorth()) if (obj == null)
{ {
nswe |= 1; return false;
} }
if (canGoEast()) if (!(obj instanceof NodeLoc))
{ {
nswe |= 1 << 1; return false;
} }
if (canGoSouth()) final NodeLoc other = (NodeLoc) obj;
{ if (_x != other._x)
nswe |= 1 << 2; {
} return false;
if (canGoEast()) }
{ if (_y != other._y)
nswe |= 1 << 3; {
} return false;
}
result = (prime * result) + (((_geoHeight & 0xFFFF) << 1) | nswe); if (_goNorth != other._goNorth)
return result; {
} return false;
}
/** if (_goEast != other._goEast)
* @see java.lang.Object#equals(java.lang.Object) {
*/ return false;
@Override }
public boolean equals(Object obj) if (_goSouth != other._goSouth)
{ {
if (this == obj) return false;
{ }
return true; if (_goWest != other._goWest)
} {
if (obj == null) return false;
{ }
return false; if (_geoHeight != other._geoHeight)
} {
if (!(obj instanceof NodeLoc)) return false;
{ }
return false; return true;
} }
final NodeLoc other = (NodeLoc) obj; }
if (_x != other._x)
{
return false;
}
if (_y != other._y)
{
return false;
}
if (_goNorth != other._goNorth)
{
return false;
}
if (_goEast != other._goEast)
{
return false;
}
if (_goSouth != other._goSouth)
{
return false;
}
if (_goWest != other._goWest)
{
return false;
}
if (_geoHeight != other._geoHeight)
{
return false;
}
return true;
}
}

View File

@@ -1,63 +1,62 @@
/* /*
* This file is part of the L2J Mobius project. * This file is part of the L2J Mobius project.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * 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.geodata.pathfinding.AbstractNode;
import com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc;
/**
/** * @author -Nemesiss-
* @author -Nemesiss- */
*/ public class GeoNode extends AbstractNode<GeoNodeLoc>
public class GeoNode extends AbstractNode {
{ private final int _neighborsIdx;
private final int _neighborsIdx; private short _cost;
private short _cost; private GeoNode[] _neighbors;
private GeoNode[] _neighbors;
public GeoNode(GeoNodeLoc Loc, int Neighbors_idx)
public GeoNode(AbstractNodeLoc Loc, int Neighbors_idx) {
{ super(Loc);
super(Loc); _neighborsIdx = Neighbors_idx;
_neighborsIdx = Neighbors_idx; }
}
public short getCost()
public short getCost() {
{ return _cost;
return _cost; }
}
public void setCost(int cost)
public void setCost(int cost) {
{ _cost = (short) cost;
_cost = (short) cost; }
}
public GeoNode[] getNeighbors()
public GeoNode[] getNeighbors() {
{ return _neighbors;
return _neighbors; }
}
public void attachNeighbors()
public void attachNeighbors() {
{ if (getLoc() == null)
if (getLoc() == null) {
{ _neighbors = null;
_neighbors = null; }
} else
else {
{ _neighbors = GeoPathFinding.getInstance().readNeighbors(this, _neighborsIdx);
_neighbors = GeoPathFinding.getInstance().readNeighbors(this, _neighborsIdx); }
} }
} }
}

View File

@@ -1,130 +1,109 @@
/* /*
* This file is part of the L2J Mobius project. * This file is part of the L2J Mobius project.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * 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.model.L2World; import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNodeLoc;
import com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc; import com.l2jmobius.gameserver.model.L2World;
/** /**
* @author -Nemesiss- * @author -Nemesiss-
*/ */
public class GeoNodeLoc extends AbstractNodeLoc public class GeoNodeLoc extends AbstractNodeLoc
{ {
private final short _x; private final short _x;
private final short _y; private final short _y;
private final short _z; private final short _z;
public GeoNodeLoc(short x, short y, short z) public GeoNodeLoc(short x, short y, short z)
{ {
_x = x; _x = x;
_y = y; _y = y;
_z = z; _z = z;
} }
/** @Override
* @see com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc#getX() public int getX()
*/ {
@Override return L2World.MAP_MIN_X + (_x * 128) + 48;
public int getX() }
{
return L2World.MAP_MIN_X + (_x * 128) + 48; @Override
} public int getY()
{
/** return L2World.MAP_MIN_Y + (_y * 128) + 48;
* @see com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc#getY() }
*/
@Override @Override
public int getY() public int getZ()
{ {
return L2World.MAP_MIN_Y + (_y * 128) + 48; return _z;
} }
/** @Override
* @see com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc#getZ() public int getNodeX()
*/ {
@Override return _x;
public int getZ() }
{
return _z; @Override
} public int getNodeY()
{
@Override return _y;
public void setZ(short z) }
{
// Overriden @Override
} public int hashCode()
{
@Override final int prime = 31;
public int getNodeX() int result = 1;
{ result = (prime * result) + _x;
return _x; result = (prime * result) + _y;
} result = (prime * result) + _z;
return result;
@Override }
public int getNodeY()
{ @Override
return _y; public boolean equals(Object obj)
} {
if (this == obj)
/** {
* @see java.lang.Object#hashCode() return true;
*/ }
@Override if (obj == null)
public int hashCode() {
{ return false;
final int prime = 31; }
int result = 1; if (!(obj instanceof GeoNodeLoc))
result = (prime * result) + _x; {
result = (prime * result) + _y; return false;
result = (prime * result) + _z; }
return result; final GeoNodeLoc other = (GeoNodeLoc) obj;
} if (_x != other._x)
{
/** return false;
* @see java.lang.Object#equals(java.lang.Object) }
*/ if (_y != other._y)
@Override {
public boolean equals(Object obj) return false;
{ }
if (this == obj) if (_z != other._z)
{ {
return true; return false;
} }
if (obj == null) return true;
{ }
return false; }
}
if (!(obj instanceof GeoNodeLoc))
{
return false;
}
final GeoNodeLoc other = (GeoNodeLoc) obj;
if (_x != other._x)
{
return false;
}
if (_y != other._y)
{
return false;
}
if (_z != other._z)
{
return false;
}
return true;
}
}

View File

@@ -1,470 +1,469 @@
/* /*
* This file is part of the L2J Mobius project. * This file is part of the L2J Mobius project.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * 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.File; import java.io.IOException;
import java.io.FileReader; import java.io.RandomAccessFile;
import java.io.LineNumberReader; import java.nio.ByteBuffer;
import java.io.RandomAccessFile; import java.nio.IntBuffer;
import java.nio.ByteBuffer; import java.nio.MappedByteBuffer;
import java.nio.IntBuffer; import java.nio.channels.FileChannel;
import java.nio.MappedByteBuffer; import java.nio.charset.StandardCharsets;
import java.nio.channels.FileChannel; import java.nio.file.Files;
import java.util.LinkedList; import java.nio.file.Paths;
import java.util.List; import java.util.ArrayList;
import java.util.Map; import java.util.LinkedList;
import java.util.StringTokenizer; import java.util.List;
import java.util.logging.Logger; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.l2jmobius.Config; import java.util.logging.Level;
import com.l2jmobius.gameserver.GeoData; import java.util.logging.Logger;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.Location; import com.l2jmobius.Config;
import com.l2jmobius.gameserver.pathfinding.AbstractNode; import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc; import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNode;
import com.l2jmobius.gameserver.pathfinding.PathFinding; import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNodeLoc;
import com.l2jmobius.gameserver.pathfinding.utils.FastNodeList; import com.l2jmobius.gameserver.geodata.pathfinding.PathFinding;
import com.l2jmobius.gameserver.model.L2World;
import javolution.util.FastList; import com.l2jmobius.gameserver.model.Location;
import javolution.util.FastMap; import com.l2jmobius.gameserver.util.Util;
/** /**
* @author -Nemesiss- * @author -Nemesiss-
*/ */
public class GeoPathFinding extends PathFinding public class GeoPathFinding extends PathFinding
{ {
private static Logger _log = Logger.getLogger(GeoPathFinding.class.getName()); private static Logger _log = Logger.getLogger(GeoPathFinding.class.getName());
private static GeoPathFinding _instance; private static Map<Short, ByteBuffer> _pathNodes = new ConcurrentHashMap<>();
private static Map<Short, ByteBuffer> pathNodes = new FastMap<>(); private static Map<Short, IntBuffer> _pathNodesIndex = new ConcurrentHashMap<>();
private static Map<Short, IntBuffer> pathNodes_index = new FastMap<>();
public static GeoPathFinding getInstance()
public static GeoPathFinding getInstance() {
{ return SingletonHolder._instance;
if (_instance == null) }
{
_instance = new GeoPathFinding(); @Override
} public boolean pathNodesExist(short regionoffset)
return _instance; {
} return _pathNodesIndex.containsKey(regionoffset);
}
/**
* @see com.l2jmobius.gameserver.pathfinding.PathFinding#pathNodesExist(short) @Override
*/ public List<AbstractNodeLoc> findPath(int x, int y, int z, int tx, int ty, int tz, boolean playable)
@Override {
public boolean pathNodesExist(short regionoffset) final int gx = (x - L2World.MAP_MIN_X) >> 4;
{ final int gy = (y - L2World.MAP_MIN_Y) >> 4;
return pathNodes_index.containsKey(regionoffset); final short gz = (short) z;
} final int gtx = (tx - L2World.MAP_MIN_X) >> 4;
final int gty = (ty - L2World.MAP_MIN_Y) >> 4;
@Override final short gtz = (short) tz;
public List<AbstractNodeLoc> findPath(int x, int y, int z, int tx, int ty, int tz, boolean playable)
{ final GeoNode start = readNode(gx, gy, gz);
final int gx = (x - L2World.MAP_MIN_X) >> 4; final GeoNode end = readNode(gtx, gty, gtz);
final int gy = (y - L2World.MAP_MIN_Y) >> 4; if ((start == null) || (end == null))
final short gz = (short) z; {
final int gtx = (tx - L2World.MAP_MIN_X) >> 4; return null;
final int gty = (ty - L2World.MAP_MIN_Y) >> 4; }
final short gtz = (short) tz; if (Math.abs(start.getLoc().getZ() - z) > 55)
{
final GeoNode start = readNode(gx, gy, gz); return null; // not correct layer
final GeoNode end = readNode(gtx, gty, gtz); }
if (Math.abs(end.getLoc().getZ() - tz) > 55)
if ((start == null) || (end == null)) {
{ return null; // not correct layer
return null; }
} if (start == end)
if (Math.abs(start.getLoc().getZ() - z) > 55) {
{ return null;
return null; // not correct layer }
}
if (Math.abs(end.getLoc().getZ() - tz) > 55) // 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());
return null; // not correct layer if ((temp.getX() != start.getLoc().getX()) || (temp.getY() != start.getLoc().getY()))
} {
if (start == end) return null; // cannot reach closest...
{ }
return null;
} // TODO: Find closest path node around target, now only checks if final location can be reached
Location temp = GeoData.getInstance().moveCheck(x, y, z, start.getLoc().getX(), start.getLoc().getY(), start.getLoc().getZ()); temp = GeoData.getInstance().moveCheck(tx, ty, tz, end.getLoc().getX(), end.getLoc().getY(), end.getLoc().getZ());
if ((temp.getX() != start.getLoc().getX()) || (temp.getY() != start.getLoc().getY())) if ((temp.getX() != end.getLoc().getX()) || (temp.getY() != end.getLoc().getY()))
{ {
return null; // cannot reach closest... return null; // cannot reach closest...
} }
temp = GeoData.getInstance().moveCheck(tx, ty, tz, end.getLoc().getX(), end.getLoc().getY(), end.getLoc().getZ()); // return searchAStar(start, end);
if ((temp.getX() != end.getLoc().getX()) || (temp.getY() != end.getLoc().getY())) return searchByClosest2(start, end);
{ }
return null; // cannot reach closest...
} public List<AbstractNodeLoc> searchByClosest2(GeoNode start, GeoNode end)
{
return searchByClosest2(start, end); // Always continues checking from the closest to target non-blocked
} // node from to_visit list. There's extra length in path if needed
// to go backwards/sideways but when moving generally forwards, this is extra fast
public List<AbstractNodeLoc> searchByClosest2(GeoNode start, GeoNode end) // and accurate. And can reach insane distances (try it with 800 nodes..).
{ // Minimum required node count would be around 300-400.
// Always continues checking from the closest to target non-blocked // Generally returns a bit (only a bit) more intelligent looking routes than
// node from to_visit list. There's extra length in path if needed // the basic version. Not a true distance image (which would increase CPU
// to go backwards/sideways but when moving generally forwards, this is extra fast // load) level of intelligence though.
// and accurate. And can reach insane distances (try it with 800 nodes..).
// Minimum required node count would be around 300-400. // List of Visited Nodes
// Generally returns a bit (only a bit) more intelligent looking routes than final List<GeoNode> visited = new ArrayList<>(550);
// the basic version. Not a true distance image (which would increase CPU
// load) level of intelligence though. // List of Nodes to Visit
final LinkedList<GeoNode> to_visit = new LinkedList<>();
// List of Visited Nodes to_visit.add(start);
final FastNodeList visited = new FastNodeList(550); final int targetX = end.getLoc().getNodeX();
final int targetY = end.getLoc().getNodeY();
// List of Nodes to Visit
final LinkedList<GeoNode> to_visit = new LinkedList<>(); int dx, dy;
to_visit.add(start); boolean added;
final int targetX = end.getLoc().getNodeX(); int i = 0;
final int targetY = end.getLoc().getNodeY(); while (i < 550)
{
int dx, dy; GeoNode node;
boolean added; try
int i = 0; {
while (i < 550) node = to_visit.removeFirst();
{ }
GeoNode node; catch (Exception e)
try {
{ // No Path found
node = to_visit.removeFirst(); return null;
} }
catch (final Exception e) if (node.equals(end))
{ {
// No Path found return constructPath2(node);
return null; }
}
i++;
if (node.equals(end)) visited.add(node);
{ node.attachNeighbors();
return constructPath2(node); final GeoNode[] neighbors = node.getNeighbors();
} if (neighbors == null)
{
i++; continue;
visited.add(node); }
node.attachNeighbors(); for (GeoNode n : neighbors)
final GeoNode[] neighbors = node.getNeighbors(); {
if (neighbors == null) if ((visited.lastIndexOf(n) == -1) && !to_visit.contains(n))
{ {
continue; added = false;
} n.setParent(node);
for (final GeoNode n : neighbors) dx = targetX - n.getLoc().getNodeX();
{ dy = targetY - n.getLoc().getNodeY();
if (!visited.containsRev(n) && !to_visit.contains(n)) n.setCost((dx * dx) + (dy * dy));
{ for (int index = 0; index < to_visit.size(); index++)
added = false; {
n.setParent(node); // supposed to find it quite early..
dx = targetX - n.getLoc().getNodeX(); if (to_visit.get(index).getCost() > n.getCost())
dy = targetY - n.getLoc().getNodeY(); {
n.setCost((dx * dx) + (dy * dy)); to_visit.add(index, n);
for (int index = 0; index < to_visit.size(); index++) added = true;
{ break;
// supposed to find it quite early.. }
if (to_visit.get(index).getCost() > n.getCost()) }
{ if (!added)
to_visit.add(index, n); {
added = true; to_visit.addLast(n);
break; }
} }
} }
if (!added) }
{ // No Path found
to_visit.addLast(n); return null;
} }
}
} public List<AbstractNodeLoc> constructPath2(AbstractNode<GeoNodeLoc> node)
} {
// No Path found final LinkedList<AbstractNodeLoc> path = new LinkedList<>();
return null; int previousDirectionX = -1000;
} int previousDirectionY = -1000;
int directionX;
public List<AbstractNodeLoc> constructPath2(AbstractNode node) int directionY;
{
final LinkedList<AbstractNodeLoc> path = new LinkedList<>(); while (node.getParent() != null)
int previousDirectionX = -1000; {
int previousDirectionY = -1000; // only add a new route point if moving direction changes
int directionX; directionX = node.getLoc().getNodeX() - node.getParent().getLoc().getNodeX();
int directionY; directionY = node.getLoc().getNodeY() - node.getParent().getLoc().getNodeY();
while (node.getParent() != null) if ((directionX != previousDirectionX) || (directionY != previousDirectionY))
{ {
// only add a new route point if moving direction changes previousDirectionX = directionX;
directionX = node.getLoc().getNodeX() - node.getParent().getLoc().getNodeX(); previousDirectionY = directionY;
directionY = node.getLoc().getNodeY() - node.getParent().getLoc().getNodeY(); path.addFirst(node.getLoc());
}
if ((directionX != previousDirectionX) || (directionY != previousDirectionY)) node = node.getParent();
{ }
previousDirectionX = directionX; return path;
previousDirectionY = directionY; }
path.addFirst(node.getLoc());
} public GeoNode[] readNeighbors(GeoNode n, int idx)
node = node.getParent(); {
} final int node_x = n.getLoc().getNodeX();
return path; final int node_y = n.getLoc().getNodeY();
} // short node_z = n.getLoc().getZ();
public GeoNode[] readNeighbors(GeoNode n, int idx) final short regoffset = getRegionOffset(getRegionX(node_x), getRegionY(node_y));
{ final ByteBuffer pn = _pathNodes.get(regoffset);
final int node_x = n.getLoc().getNodeX();
final int node_y = n.getLoc().getNodeY(); final List<AbstractNode<GeoNodeLoc>> Neighbors = new ArrayList<>(8);
GeoNode newNode;
final short regoffset = getRegionOffset(getRegionX(node_x), getRegionY(node_y)); short new_node_x, new_node_y;
final ByteBuffer pn = pathNodes.get(regoffset);
// Region for sure will change, we must read from correct file
final List<AbstractNode> Neighbors = new FastList<>(8); byte neighbor = pn.get(idx++); // N
if (neighbor > 0)
GeoNode newNode; {
short new_node_x, new_node_y; neighbor--;
new_node_x = (short) node_x;
// Region for sure will change, we must read from correct file new_node_y = (short) (node_y - 1);
byte neighbor = pn.get(idx); // N newNode = readNode(new_node_x, new_node_y, neighbor);
idx++; if (newNode != null)
if (neighbor > 0) {
{ Neighbors.add(newNode);
neighbor--; }
new_node_x = (short) node_x; }
new_node_y = (short) (node_y - 1); neighbor = pn.get(idx++); // NE
newNode = readNode(new_node_x, new_node_y, neighbor); if (neighbor > 0)
if (newNode != null) {
{ neighbor--;
Neighbors.add(newNode); new_node_x = (short) (node_x + 1);
} new_node_y = (short) (node_y - 1);
} newNode = readNode(new_node_x, new_node_y, neighbor);
neighbor = pn.get(idx); // NE if (newNode != null)
idx++; {
if (neighbor > 0) Neighbors.add(newNode);
{ }
neighbor--; }
new_node_x = (short) (node_x + 1); neighbor = pn.get(idx++); // E
new_node_y = (short) (node_y - 1); if (neighbor > 0)
newNode = readNode(new_node_x, new_node_y, neighbor); {
if (newNode != null) neighbor--;
{ new_node_x = (short) (node_x + 1);
Neighbors.add(newNode); new_node_y = (short) node_y;
} newNode = readNode(new_node_x, new_node_y, neighbor);
} if (newNode != null)
neighbor = pn.get(idx); // E {
idx++; Neighbors.add(newNode);
if (neighbor > 0) }
{ }
neighbor--; neighbor = pn.get(idx++); // SE
new_node_x = (short) (node_x + 1); if (neighbor > 0)
new_node_y = (short) node_y; {
newNode = readNode(new_node_x, new_node_y, neighbor); neighbor--;
if (newNode != null) new_node_x = (short) (node_x + 1);
{ new_node_y = (short) (node_y + 1);
Neighbors.add(newNode); newNode = readNode(new_node_x, new_node_y, neighbor);
} if (newNode != null)
} {
neighbor = pn.get(idx); // SE Neighbors.add(newNode);
idx++; }
if (neighbor > 0) }
{ neighbor = pn.get(idx++); // S
neighbor--; if (neighbor > 0)
new_node_x = (short) (node_x + 1); {
new_node_y = (short) (node_y + 1); neighbor--;
newNode = readNode(new_node_x, new_node_y, neighbor); new_node_x = (short) node_x;
if (newNode != null) new_node_y = (short) (node_y + 1);
{ newNode = readNode(new_node_x, new_node_y, neighbor);
Neighbors.add(newNode); if (newNode != null)
} {
} Neighbors.add(newNode);
neighbor = pn.get(idx); // S }
idx++; }
if (neighbor > 0) neighbor = pn.get(idx++); // SW
{ if (neighbor > 0)
neighbor--; {
new_node_x = (short) node_x; neighbor--;
new_node_y = (short) (node_y + 1); new_node_x = (short) (node_x - 1);
newNode = readNode(new_node_x, new_node_y, neighbor); new_node_y = (short) (node_y + 1);
if (newNode != null) newNode = readNode(new_node_x, new_node_y, neighbor);
{ if (newNode != null)
Neighbors.add(newNode); {
} Neighbors.add(newNode);
} }
neighbor = pn.get(idx); // SW }
idx++; neighbor = pn.get(idx++); // W
if (neighbor > 0) if (neighbor > 0)
{ {
neighbor--; neighbor--;
new_node_x = (short) (node_x - 1); new_node_x = (short) (node_x - 1);
new_node_y = (short) (node_y + 1); new_node_y = (short) node_y;
newNode = readNode(new_node_x, new_node_y, neighbor); newNode = readNode(new_node_x, new_node_y, neighbor);
if (newNode != null) if (newNode != null)
{ {
Neighbors.add(newNode); Neighbors.add(newNode);
} }
} }
neighbor = pn.get(idx); // W neighbor = pn.get(idx++); // NW
idx++; if (neighbor > 0)
if (neighbor > 0) {
{ neighbor--;
neighbor--; new_node_x = (short) (node_x - 1);
new_node_x = (short) (node_x - 1); new_node_y = (short) (node_y - 1);
new_node_y = (short) node_y; newNode = readNode(new_node_x, new_node_y, neighbor);
newNode = readNode(new_node_x, new_node_y, neighbor); if (newNode != null)
if (newNode != null) {
{ Neighbors.add(newNode);
Neighbors.add(newNode); }
} }
} final GeoNode[] result = new GeoNode[Neighbors.size()];
neighbor = pn.get(idx); // NW return Neighbors.toArray(result);
idx++; }
if (neighbor > 0)
{ // Private
neighbor--;
new_node_x = (short) (node_x - 1); private GeoNode readNode(short node_x, short node_y, byte layer)
new_node_y = (short) (node_y - 1); {
newNode = readNode(new_node_x, new_node_y, neighbor); final short regoffset = getRegionOffset(getRegionX(node_x), getRegionY(node_y));
if (newNode != null) if (!pathNodesExist(regoffset))
{ {
Neighbors.add(newNode); return null;
} }
} final short nbx = getNodeBlock(node_x);
final GeoNode[] result = new GeoNode[Neighbors.size()]; final short nby = getNodeBlock(node_y);
return Neighbors.toArray(result); int idx = _pathNodesIndex.get(regoffset).get((nby << 8) + nbx);
} final ByteBuffer pn = _pathNodes.get(regoffset);
// reading
private GeoNode readNode(short node_x, short node_y, byte layer) final byte nodes = pn.get(idx);
{ idx += (layer * 10) + 1; // byte + layer*10byte
final short regoffset = getRegionOffset(getRegionX(node_x), getRegionY(node_y)); if (nodes < layer)
if (!pathNodesExist(regoffset)) {
{ _log.warning("SmthWrong!");
return null; }
} final short node_z = pn.getShort(idx);
final short nbx = getNodeBlock(node_x); idx += 2;
final short nby = getNodeBlock(node_y); return new GeoNode(new GeoNodeLoc(node_x, node_y, node_z), idx);
int idx = pathNodes_index.get(regoffset).get((nby << 8) + nbx); }
final ByteBuffer pn = pathNodes.get(regoffset);
// reading private GeoNode readNode(int gx, int gy, short z)
final byte nodes = pn.get(idx); {
idx += (layer * 10) + 1;// byte + layer*10byte final short node_x = getNodePos(gx);
if (nodes < layer) final short node_y = getNodePos(gy);
{ final short regoffset = getRegionOffset(getRegionX(node_x), getRegionY(node_y));
_log.warning("SmthWrong!"); if (!pathNodesExist(regoffset))
} {
final short node_z = pn.getShort(idx); return null;
idx += 2; }
return new GeoNode(new GeoNodeLoc(node_x, node_y, node_z), idx); final short nbx = getNodeBlock(node_x);
} final short nby = getNodeBlock(node_y);
int idx = _pathNodesIndex.get(regoffset).get((nby << 8) + nbx);
private GeoNode readNode(int gx, int gy, short z) final ByteBuffer pn = _pathNodes.get(regoffset);
{ // reading
final short node_x = getNodePos(gx); byte nodes = pn.get(idx++);
final short node_y = getNodePos(gy); int idx2 = 0; // create index to nearlest node by z
final short regoffset = getRegionOffset(getRegionX(node_x), getRegionY(node_y)); short last_z = Short.MIN_VALUE;
if (!pathNodesExist(regoffset)) while (nodes > 0)
{ {
return null; final short node_z = pn.getShort(idx);
} if (Math.abs(last_z - z) > Math.abs(node_z - z))
final short nbx = getNodeBlock(node_x); {
final short nby = getNodeBlock(node_y); last_z = node_z;
int idx = pathNodes_index.get(regoffset).get((nby << 8) + nbx); idx2 = idx + 2;
final ByteBuffer pn = pathNodes.get(regoffset); }
// reading idx += 10; // short + 8 byte
byte nodes = pn.get(idx); nodes--;
idx++;// byte }
int idx2 = 0; // create index to nearlest node by z return new GeoNode(new GeoNodeLoc(node_x, node_y, last_z), idx2);
short last_z = Short.MIN_VALUE; }
while (nodes > 0)
{ protected GeoPathFinding()
final short node_z = pn.getShort(idx); {
if (Math.abs(last_z - z) > Math.abs(node_z - z)) try
{ {
last_z = node_z; _log.info("Path Engine: - Loading Path Nodes...");
idx2 = idx + 2; //@formatter:off
} Files.lines(Paths.get(Config.PATHNODE_DIR.getPath(), "pn_index.txt"), StandardCharsets.UTF_8)
idx += 10; // short + 8 byte .map(String::trim)
nodes--; .filter(l -> !l.isEmpty())
} .forEach(line -> {
return new GeoNode(new GeoNodeLoc(node_x, node_y, last_z), idx2); final String[] parts = line.split("_");
}
if ((parts.length < 2)
private GeoPathFinding() || !Util.isDigit(parts[0])
{ || !Util.isDigit(parts[1]))
final File Data = new File(Config.PATHNODE_DIR, "pn_index.txt"); {
try (FileReader fr = new FileReader(Data); _log.warning("Invalid pathnode entry: '" + line + "', must be in format 'XX_YY', where X and Y - integers");
BufferedReader br = new BufferedReader(fr); return;
LineNumberReader lnr = new LineNumberReader(br)) }
{
_log.info("PathFinding Engine: - Loading Path Nodes..."); final byte rx = Byte.parseByte(parts[0]);
String line; final byte ry = Byte.parseByte(parts[1]);
LoadPathNodeFile(rx, ry);
while ((line = lnr.readLine()) != null) });
{ //@formatter:on
if (line.trim().length() == 0) }
{ catch (IOException e)
continue; {
} _log.log(Level.WARNING, "", e);
final StringTokenizer st = new StringTokenizer(line, "_"); throw new Error("Failed to read pn_index file.");
final byte rx = Byte.parseByte(st.nextToken()); }
final byte ry = Byte.parseByte(st.nextToken()); }
LoadPathNodeFile(rx, ry);
} private void LoadPathNodeFile(byte rx, byte ry)
} {
catch (final Exception e) if ((rx < L2World.TILE_X_MIN) || (rx > L2World.TILE_X_MAX) || (ry < L2World.TILE_Y_MIN) || (ry > L2World.TILE_Y_MAX))
{ {
e.printStackTrace(); _log.warning("Failed to Load PathNode File: invalid region " + rx + "," + ry + Config.EOL);
throw new Error("Failed to Read pn_index File."); return;
} }
} final short regionoffset = getRegionOffset(rx, ry);
final File file = new File(Config.PATHNODE_DIR, rx + "_" + ry + ".pn");
private void LoadPathNodeFile(byte rx, byte ry) _log.info("Path Engine: - Loading: " + file.getName() + " -> region offset: " + regionoffset + " X: " + rx + " Y: " + ry);
{ int node = 0, size, index = 0;
final short regionoffset = getRegionOffset(rx, ry);
final File pn = new File(Config.PATHNODE_DIR, rx + "_" + ry + ".pn"); // Create a read-only memory-mapped file
_log.info("PathFinding Engine: - Loading: " + pn.getName() + " -> region offset: " + regionoffset + "X: " + rx + " Y: " + ry); try (RandomAccessFile raf = new RandomAccessFile(file, "r");
int node = 0, size, index = 0; FileChannel roChannel = raf.getChannel())
{
// Create a read-only memory-mapped file size = (int) roChannel.size();
try (RandomAccessFile raf = new RandomAccessFile(pn, "r"); MappedByteBuffer nodes;
FileChannel roChannel = raf.getChannel()) if (Config.FORCE_GEODATA)
{ {
size = (int) roChannel.size(); // it is not guarantee, because the underlying operating system may have paged out some of the buffer's data
MappedByteBuffer nodes; nodes = roChannel.map(FileChannel.MapMode.READ_ONLY, 0, size).load();
if (Config.FORCE_GEODATA) // Force O/S to Loads this buffer's content into physical memory. }
{ else
// 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(); nodes = roChannel.map(FileChannel.MapMode.READ_ONLY, 0, size);
} }
else
{ // Indexing pathnode files, so we will know where each block starts
nodes = roChannel.map(FileChannel.MapMode.READ_ONLY, 0, size); final IntBuffer indexs = IntBuffer.allocate(65536);
}
while (node < 65536)
// Indexing pathnode files, so we will know where each block starts {
final IntBuffer indexs = IntBuffer.allocate(65536); final byte layer = nodes.get(index);
indexs.put(node++, index);
while (node < 65536) index += (layer * 10) + 1;
{ }
final byte layer = nodes.get(index); _pathNodesIndex.put(regionoffset, indexs);
indexs.put(node, index); _pathNodes.put(regionoffset, nodes);
node++; }
index += (layer * 10) + 1; catch (Exception e)
} {
pathNodes_index.put(regionoffset, indexs); _log.log(Level.WARNING, "Failed to Load PathNode File: " + file.getAbsolutePath() + " : " + e.getMessage(), e);
pathNodes.put(regionoffset, nodes); }
} }
catch (final Exception e)
{ private static class SingletonHolder
e.printStackTrace(); {
_log.warning("Failed to Load PathNode File: " + pn.getAbsolutePath() + "\n"); protected static final GeoPathFinding _instance = new GeoPathFinding();
} }
} }
}

View File

@@ -1,124 +1,124 @@
/* /*
* This file is part of the L2J Mobius project. * This file is part of the L2J Mobius project.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * 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- * @author -Nemesiss-
*/ */
public class BinaryNodeHeap public class BinaryNodeHeap
{ {
private final GeoNode[] _list; private final GeoNode[] _list;
private int _size; private int _size;
public BinaryNodeHeap(int size) public BinaryNodeHeap(int size)
{ {
_list = new GeoNode[size + 1]; _list = new GeoNode[size + 1];
_size = 0; _size = 0;
} }
public void add(GeoNode n) public void add(GeoNode n)
{ {
_size++; _size++;
int pos = _size; int pos = _size;
_list[pos] = n; _list[pos] = n;
while (pos != 1) while (pos != 1)
{ {
final int p2 = pos / 2; final int p2 = pos / 2;
if (_list[pos].getCost() <= _list[p2].getCost()) if (_list[pos].getCost() <= _list[p2].getCost())
{ {
final GeoNode temp = _list[p2]; final GeoNode temp = _list[p2];
_list[p2] = _list[pos]; _list[p2] = _list[pos];
_list[pos] = temp; _list[pos] = temp;
pos = p2; pos = p2;
} }
else else
{ {
break; break;
} }
} }
} }
public GeoNode removeFirst() public GeoNode removeFirst()
{ {
final GeoNode first = _list[1]; final GeoNode first = _list[1];
_list[1] = _list[_size]; _list[1] = _list[_size];
_list[_size] = null; _list[_size] = null;
_size--; _size--;
int pos = 1; int pos = 1;
int cpos; int cpos;
int dblcpos; int dblcpos;
GeoNode temp; GeoNode temp;
while (true) while (true)
{ {
cpos = pos; cpos = pos;
dblcpos = cpos * 2; dblcpos = cpos * 2;
if ((dblcpos + 1) <= _size) if ((dblcpos + 1) <= _size)
{ {
if (_list[cpos].getCost() >= _list[dblcpos].getCost()) if (_list[cpos].getCost() >= _list[dblcpos].getCost())
{ {
pos = dblcpos; pos = dblcpos;
} }
if (_list[pos].getCost() >= _list[dblcpos + 1].getCost()) if (_list[pos].getCost() >= _list[dblcpos + 1].getCost())
{ {
pos = dblcpos + 1; pos = dblcpos + 1;
} }
} }
else if (dblcpos <= _size) else if (dblcpos <= _size)
{ {
if (_list[cpos].getCost() >= _list[dblcpos].getCost()) if (_list[cpos].getCost() >= _list[dblcpos].getCost())
{ {
pos = dblcpos; pos = dblcpos;
} }
} }
if (cpos != pos) if (cpos != pos)
{ {
temp = _list[cpos]; temp = _list[cpos];
_list[cpos] = _list[pos]; _list[cpos] = _list[pos];
_list[pos] = temp; _list[pos] = temp;
} }
else else
{ {
break; break;
} }
} }
return first; return first;
} }
public boolean contains(GeoNode n) public boolean contains(GeoNode n)
{ {
if (_size == 0) if (_size == 0)
{ {
return false; return false;
} }
for (int i = 1; i <= _size; i++) for (int i = 1; i <= _size; i++)
{ {
if (_list[i].equals(n)) if (_list[i].equals(n))
{ {
return true; return true;
} }
} }
return false; return false;
} }
public boolean isEmpty() public boolean isEmpty()
{ {
return _size == 0; return _size == 0;
} }
} }

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; package com.l2jmobius.gameserver.handler.admincommandhandlers;
import com.l2jmobius.Config; 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.handler.IAdminCommandHandler;
import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.util.GeoUtils;
/** /**
* @author -Nemesiss- * @author -Nemesiss-
@@ -32,7 +34,9 @@ public class AdminGeodata implements IAdminCommandHandler
"admin_geo_pos", "admin_geo_pos",
"admin_geo_spawn_pos", "admin_geo_spawn_pos",
"admin_geo_can_move", "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; private static final int REQUIRED_LEVEL = Config.GM_MIN;
@@ -75,7 +79,7 @@ public class AdminGeodata implements IAdminCommandHandler
if (GeoData.getInstance().hasGeoPos(geoX, geoY)) 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 else
{ {
@@ -120,6 +124,16 @@ public class AdminGeodata implements IAdminCommandHandler
activeChar.sendMessage("Incorrect Target."); 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 else
{ {
return false; return false;

View File

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

View File

@@ -17,8 +17,8 @@
package com.l2jmobius.gameserver.handler.skillhandlers; package com.l2jmobius.gameserver.handler.skillhandlers;
import com.l2jmobius.Config; import com.l2jmobius.Config;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.datatables.ZoneTable; import com.l2jmobius.gameserver.datatables.ZoneTable;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.handler.ISkillHandler; import com.l2jmobius.gameserver.handler.ISkillHandler;
import com.l2jmobius.gameserver.model.Inventory; import com.l2jmobius.gameserver.model.Inventory;
import com.l2jmobius.gameserver.model.L2Character; import com.l2jmobius.gameserver.model.L2Character;
@@ -169,7 +169,7 @@ public class Fishing implements ISkillHandler
if (aimingTo != null) if (aimingTo != null)
{ {
// fishing zone found, we can fish here // 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 // geodata enabled, checking if we can see end of the pole
if (GeoData.getInstance().canSeeTarget(player.getX(), player.getY(), z, x, y, z)) 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 // Speed percentage mods
public static final double MAX_ARMOR_WEIGHT = 12000; public static final double MAX_ARMOR_WEIGHT = 12000;
public static final int ADENA_ID = 57;
private final L2ItemInstance[] _paperdoll; private final L2ItemInstance[] _paperdoll;
private final List<PaperdollListener> _paperdollListeners; private final List<PaperdollListener> _paperdollListeners;

View File

@@ -26,7 +26,6 @@ import java.util.logging.Logger;
import com.l2jmobius.Config; import com.l2jmobius.Config;
import com.l2jmobius.gameserver.GameTimeController; import com.l2jmobius.gameserver.GameTimeController;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.ai.CtrlEvent; import com.l2jmobius.gameserver.ai.CtrlEvent;
import com.l2jmobius.gameserver.ai.CtrlIntention; 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;
import com.l2jmobius.gameserver.datatables.MapRegionTable.TeleportWhereType; import com.l2jmobius.gameserver.datatables.MapRegionTable.TeleportWhereType;
import com.l2jmobius.gameserver.datatables.SkillTable; 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.ISkillHandler;
import com.l2jmobius.gameserver.handler.SkillHandler; import com.l2jmobius.gameserver.handler.SkillHandler;
import com.l2jmobius.gameserver.instancemanager.TownManager; 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.StopMove;
import com.l2jmobius.gameserver.network.serverpackets.SystemMessage; import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import com.l2jmobius.gameserver.network.serverpackets.TeleportToLocation; 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.Calculator;
import com.l2jmobius.gameserver.skills.Formulas; import com.l2jmobius.gameserver.skills.Formulas;
import com.l2jmobius.gameserver.skills.Stats; import com.l2jmobius.gameserver.skills.Stats;
@@ -4407,10 +4407,10 @@ public abstract class L2Character extends L2Object
final boolean isFloating = isFlying() || isInsideZone(L2Character.ZONE_WATER); final boolean isFloating = isFlying() || isInsideZone(L2Character.ZONE_WATER);
// Z coordinate will follow geodata or client values // 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)) ) && 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; dz = m._zDestination - geoHeight;
// quite a big difference, compare to validatePosition packet // 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)) 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 // make water move short and use no geodata checks for swimming chars
// distance in a click can easily be over 3000 // 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; final double divider = 700 / distance;
x = curX + (int) (divider * dx); x = curX + (int) (divider * dx);
@@ -4728,7 +4728,7 @@ public abstract class L2Character extends L2Object
m.onGeodataPathIndex = -1; // Initialize not on geodata path m.onGeodataPathIndex = -1; // Initialize not on geodata path
m.disregardingGeodata = false; 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 && !(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(); final boolean isInBoat = (this instanceof L2PcInstance) && ((L2PcInstance) this).isInBoat();
@@ -4747,12 +4747,7 @@ public abstract class L2Character extends L2Object
// Movement checks: // Movement checks:
// when geodata == 2, for all characters except mobs returning home (could be changed later to teleport if pathfinding fails) // 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 // 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 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
// intention_follow
// only
// when
// following
// owner
{ {
if (isOnGeodataPath()) 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 // 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 // than the original movement was and the LoS gives a shorter distance than 2000
// This way of detecting need for pathfinding could be changed. // 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 // Path calculation
// Overrides previous movement check // 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 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) if (this instanceof L2Summon)
{ {

View File

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

View File

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

View File

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

View File

@@ -47,6 +47,10 @@ public final class L2World
public static final int SHIFT_BY = 12; public static final int SHIFT_BY = 12;
/** Map dimensions */ /** 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_MIN_X = -131072;
public static final int MAP_MAX_X = 228608; public static final int MAP_MAX_X = 228608;
public static final int MAP_MIN_Y = -262144; 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 java.util.List;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.ai.CtrlIntention; import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.model.L2Character; import com.l2jmobius.gameserver.model.L2Character;
import com.l2jmobius.gameserver.model.L2Spawn; import com.l2jmobius.gameserver.model.L2Spawn;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed; 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.Config;
import com.l2jmobius.L2DatabaseFactory; import com.l2jmobius.L2DatabaseFactory;
import com.l2jmobius.gameserver.GameTimeController; import com.l2jmobius.gameserver.GameTimeController;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.ItemsAutoDestroy; import com.l2jmobius.gameserver.ItemsAutoDestroy;
import com.l2jmobius.gameserver.LoginServerThread; import com.l2jmobius.gameserver.LoginServerThread;
import com.l2jmobius.gameserver.Olympiad; 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.NpcTable;
import com.l2jmobius.gameserver.datatables.SkillTable; import com.l2jmobius.gameserver.datatables.SkillTable;
import com.l2jmobius.gameserver.datatables.SkillTreeTable; import com.l2jmobius.gameserver.datatables.SkillTreeTable;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.handler.IItemHandler; import com.l2jmobius.gameserver.handler.IItemHandler;
import com.l2jmobius.gameserver.handler.ItemHandler; import com.l2jmobius.gameserver.handler.ItemHandler;
import com.l2jmobius.gameserver.instancemanager.CastleManager; 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 // This Action Failed packet avoids player getting stuck when clicking three or more times
player.sendPacket(new ActionFailed()); 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.Config;
import com.l2jmobius.L2DatabaseFactory; import com.l2jmobius.L2DatabaseFactory;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.ai.CtrlIntention; import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.datatables.SkillTable; import com.l2jmobius.gameserver.datatables.SkillTable;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.handler.IItemHandler; import com.l2jmobius.gameserver.handler.IItemHandler;
import com.l2jmobius.gameserver.handler.ItemHandler; import com.l2jmobius.gameserver.handler.ItemHandler;
import com.l2jmobius.gameserver.idfactory.IdFactory; 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 // Check if the pet is attackable (without a forced attack) and isn't dead
if (isAutoAttackable(player) && !isOwner) if (isAutoAttackable(player) && !isOwner)
{ {
if (Config.GEODATA > 0) if (Config.PATHFINDING > 0)
{ {
if (GeoData.getInstance().canSeeTarget(player, this)) if (GeoData.getInstance().canSeeTarget(player, this))
{ {
@@ -333,7 +333,7 @@ public class L2PetInstance extends L2Summon
} }
else if (!isInsideRadius(player, 150, false, false)) else if (!isInsideRadius(player, 150, false, false))
{ {
if (Config.GEODATA > 0) if (Config.PATHFINDING > 0)
{ {
if (GeoData.getInstance().canSeeTarget(player, this)) 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. // 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()); activeChar.sendPacket(new ActionFailed());
} }

View File

@@ -19,7 +19,6 @@ package com.l2jmobius.gameserver.network.clientpackets;
import java.util.logging.Logger; import java.util.logging.Logger;
import com.l2jmobius.Config; import com.l2jmobius.Config;
import com.l2jmobius.gameserver.geoeditorcon.GeoEditorListener;
import com.l2jmobius.gameserver.model.L2Character; import com.l2jmobius.gameserver.model.L2Character;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.serverpackets.GetOnVehicle; import com.l2jmobius.gameserver.network.serverpackets.GetOnVehicle;
@@ -113,14 +112,6 @@ public class ValidatePosition extends L2GameClientPacket
activeChar.getParty().broadcastToPartyMembers(activeChar, new PartyMemberPosition(activeChar)); 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)) if (activeChar.isFlying() || activeChar.isInsideZone(L2Character.ZONE_WATER))
{ {
activeChar.setXYZ(realX, realY, _z); activeChar.setXYZ(realX, realY, _z);
@@ -165,7 +156,7 @@ public class ValidatePosition extends L2GameClientPacket
// intended for geodata. Sends a validation packet to client // intended for geodata. Sends a validation packet to client
// when too far from server calculated true coordinate. // when too far from server calculated true coordinate.
// Due to geodata "holes", some Z axis checks are made. // 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)) 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; package com.l2jmobius.gameserver.skills.effects;
import com.l2jmobius.Config; import com.l2jmobius.Config;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.ai.CtrlIntention; import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.model.L2CharPosition; import com.l2jmobius.gameserver.model.L2CharPosition;
import com.l2jmobius.gameserver.model.L2Effect; import com.l2jmobius.gameserver.model.L2Effect;
import com.l2jmobius.gameserver.model.Location; import com.l2jmobius.gameserver.model.Location;
@@ -110,7 +110,7 @@ final class EffectFear extends L2Effect
posX += _dX * FEAR_RANGE; posX += _dX * FEAR_RANGE;
posY += _dY * 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); final Location destiny = GeoData.getInstance().moveCheck(getEffected().getX(), getEffected().getY(), getEffected().getZ(), posX, posY, posZ);
posX = destiny.getX(); posX = destiny.getX();

View File

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

View File

@@ -16,25 +16,165 @@
*/ */
package com.l2jmobius.gameserver.util; 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 final class GeoUtils
{ {
public interface PointListener public static void debug2DLine(L2PcInstance player, int x, int y, int tx, int ty, int z)
{ {
/** final int gx = GeoData.getInstance().getGeoX(x);
* @param x final int gy = GeoData.getInstance().getGeoY(y);
* @param y
* @return true proceed, false abort final int tgx = GeoData.getInstance().getGeoX(tx);
*/ final int tgy = GeoData.getInstance().getGeoY(ty);
boolean onPoint(int x, int y);
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 * difference between y values: never above 1
* @param lastX * @param lastX
* @param lastY * @param lastY
@@ -42,36 +182,36 @@ public final class GeoUtils
* @param y * @param y
* @return * @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 (x > lastX) // east
{ {
if (y > lastY) if (y > lastY)
{ {
return Direction.SOUTH_EAST; return Cell.NSWE_SOUTH_EAST; // Direction.SOUTH_EAST;
} }
else if (y < lastY) else if (y < lastY)
{ {
return Direction.NORTH_EAST; return Cell.NSWE_NORTH_EAST; // Direction.NORTH_EAST;
} }
else else
{ {
return Direction.EAST; return Cell.NSWE_EAST; // Direction.EAST;
} }
} }
else if (x < lastX) // west else if (x < lastX) // west
{ {
if (y > lastY) if (y > lastY)
{ {
return Direction.SOUTH_WEST; return Cell.NSWE_SOUTH_WEST; // Direction.SOUTH_WEST;
} }
else if (y < lastY) else if (y < lastY)
{ {
return Direction.NORTH_WEST; return Cell.NSWE_NORTH_WEST; // Direction.NORTH_WEST;
} }
else else
{ {
return Direction.WEST; return Cell.NSWE_WEST; // Direction.WEST;
} }
} }
else else
@@ -79,15 +219,15 @@ public final class GeoUtils
{ {
if (y > lastY) if (y > lastY)
{ {
return Direction.SOUTH; return Cell.NSWE_SOUTH; // Direction.SOUTH;
} }
else if (y < lastY) else if (y < lastY)
{ {
return Direction.NORTH; return Cell.NSWE_NORTH; // Direction.NORTH;
} }
else else
{ {
return null;// error, should never happen, TODO: Logging throw new RuntimeException();
} }
} }
} }

View File

@@ -325,4 +325,24 @@ public final class Util
} }
return result; 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