Diagonal movement GeoEngine.

This commit is contained in:
MobiusDev
2017-08-26 20:50:32 +00:00
parent 1e943ff506
commit 05f0a141c3
549 changed files with 25017 additions and 20141 deletions

View File

@@ -74,6 +74,7 @@
<fileset dir="${build.bin}">
<exclude name="**/dbinstaller/**" />
<exclude name="**/gameserver/**" />
<exclude name="**/geodataconverter/**" />
<exclude name="**/commons/geodriver/**" />
<exclude name="**/commons/javaengine/**" />
</fileset>

View File

@@ -0,0 +1,6 @@
@echo off
title L2D geodata converter
java -Xmx512m -cp ./../libs/*;GameServer.jar com.l2jmobius.tools.geodataconverter.GeoDataConverter
pause

View File

@@ -0,0 +1,4 @@
#! /bin/sh
java -Xmx512m -cp ./../libs/*;GameServer.jar com.l2jmobius.tools.geodataconverter.GeoDataConverter > log/stdout.log 2>&1

View File

@@ -413,11 +413,7 @@
<admin command="admin_mons" accessLevel="100" />
<!-- ADMIN PATH NODE -->
<admin command="admin_pn_info" accessLevel="100" />
<admin command="admin_show_path" accessLevel="100" />
<admin command="admin_path_debug" accessLevel="100" />
<admin command="admin_show_pn" accessLevel="100" />
<admin command="admin_find_path" accessLevel="100" />
<admin command="admin_path_find" accessLevel="100" />
<!-- ADMIN PETITION -->
<admin command="admin_view_petitions" accessLevel="100" />

View File

@@ -1,75 +0,0 @@
# ---------------------------------------------------------------------------
# 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

@@ -0,0 +1,55 @@
# =================================================================
# Geodata
# =================================================================
# Because of real-time performance we are using geodata files only in
# diagonal L2D format now (using filename e.g. 22_16.l2d).
# L2D geodata can be obtained by conversion of existing L2J or L2OFF geodata.
# Launch "GeoDataConverter.bat/sh" and follow instructions to start the conversion.
# Specifies the path to geodata files. For example, when using geodata files located
# at different folder/harddrive ("C:/Program Files/Lineage II/system/geodata/"), default: ./data/geodata/
GeoDataPath = ./data/geodata/
# Player coordinates synchronization, default: 2
# 1 - partial synchronization Client --> Server ; don't use it with geodata
# 2 - partial synchronization Server --> Client ; use this setting with geodata
# -1 - Old system: will synchronize Z only
CoordSynchronize = 2
# =================================================================
# Path checking
# =================================================================
# Line of sight start at X percent of the character height, default: 75
PartOfCharacterHeight = 75
# Maximum height of an obstacle, which can exceed the line of sight, default: 32
MaxObstacleHeight = 32
# =================================================================
# Path finding
# =================================================================
# When line of movement check fails, the pathfinding algoritm is performed to look for
# an alternative path (e.g. walk around obstacle), default: true
PathFinding = true
# Pathfinding array buffers configuration, default: 100x6;128x6;192x6;256x4;320x4;384x4;500x2
PathFindBuffers = 100x6;128x6;192x6;256x4;320x4;384x4;500x2
# Base path weight, when moving from one node to another on axis direction, default: 10
BaseWeight = 10
# Path weight, when moving from one node to another on diagonal direction, default: BaseWeight * sqrt(2) = 14
DiagonalWeight = 14
# When movement flags of target node is blocked to any direction, multiply movement weight by this multiplier.
# This causes pathfinding algorithm to avoid path construction exactly near an obstacle, default: 10
ObstacleMultiplier = 10
# Weight of the heuristic algorithm, which is giving estimated cost from node to target, default: 20
# For proper function must be higher than BaseWeight and/or DiagonalWeight.
HeuristicWeight = 20
# Maximum number of generated nodes per one path-finding process, default 3500
MaxIterations = 3500

View File

@@ -1,11 +1,41 @@
#####################################################
# L2J GeoData #
#####################################################
# #
# GeoData files should be unpacked inside: #
# gameserver/data/geodata/ #
# #
# More Info at: #
# http://www.l2jserver.com/forum/viewforum.php?f=89 #
# #
#####################################################
##############################################
GEODATA COMPENDIUM
##############################################
Comprehensive guide for geodata, by Tryskell and Hasha.
I - How to configure it
a - Prerequisites
b - Make it work
c - L2D format
II - Addendum
##############################################
I - How to configure it
##############################################
----------------------------------------------
a - Prerequisites
----------------------------------------------
* A 64bits Windows/Java JDK is a must-have to run server with geodata. Linux servers don't have the issue.
* The server can start (hardly) with -Xmx3000m. -Xmx4g is recommended.
----------------------------------------------
b - Make it work
----------------------------------------------
To make geodata working:
* unpack your geodata files into "/data/geodata" folder
* open "/config/GeoEngine.ini" with your favorite text editor and then edit following config:
- CoordSynchronize = 2
* If you do not use any geodata files, the server will automatically change this setting to -1.
----------------------------------------------
c - L2D format
----------------------------------------------
* L2D is a new geodata file format. It holds diagonal movement informations, in addition to regular NSWE flags.
* Heavier file weight (+30%), but the pathfinding algorithms are processed way faster (-35% calculation times).
* L2D files can be converted from L2OFF/L2J formats without losing any information. Converter is part of the gameserver.
* Keep in mind to convert new geodata files, once you update your L2OFF/L2J ones.

View File

@@ -1,11 +0,0 @@
#####################################################
# L2J PathNode #
#####################################################
# #
# PathNode files should be unpacked inside: #
# gameserver/data/pathnode/ #
# #
# More Info at: #
# http://www.l2jserver.com/forum/viewforum.php?f=89 #
# #
#####################################################

View File

@@ -31,7 +31,7 @@ import com.l2jmobius.commons.util.IGameXmlReader;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
import com.l2jmobius.gameserver.instancemanager.ZoneManager;
import com.l2jmobius.gameserver.model.Location;
@@ -294,7 +294,7 @@ public final class FourSepulchers extends AbstractNpcAI implements IGameXmlReade
{
if ((npc != null) && !npc.isDead())
{
final Location destination = GeoData.getInstance().moveCheck(npc.getX(), npc.getY(), npc.getZ(), npc.getSpawn().getLocation().getX() + getRandom(-400, 400), npc.getSpawn().getLocation().getY() + getRandom(-400, 400), npc.getZ(), npc.getInstanceWorld());
final Location destination = GeoEngine.getInstance().canMoveToTargetLoc(npc.getX(), npc.getY(), npc.getZ(), npc.getSpawn().getLocation().getX() + getRandom(-400, 400), npc.getSpawn().getLocation().getY() + getRandom(-400, 400), npc.getZ(), npc.getInstanceWorld());
if (Util.calculateDistance(npc, npc.getSpawn().getLocation(), false, false) < 600)
{
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, destination);

View File

@@ -20,7 +20,7 @@ import java.util.List;
import com.l2jmobius.commons.util.CommonUtil;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.StatsSet;
@@ -92,7 +92,7 @@ public final class KartiaHelperAdolph extends AbstractNpcAI
{
final L2MonsterInstance monster = monsterList.get(getRandom(monsterList.size()));
if (monster.isTargetable() && GeoData.getInstance().canSeeTarget(npc, monster) && !CommonUtil.contains(MIRRORS, monster.getId()))
if (monster.isTargetable() && GeoEngine.getInstance().canSeeTarget(npc, monster) && !CommonUtil.contains(MIRRORS, monster.getId()))
{
actionFound = true;
addAttackDesire(npc, monster);
@@ -115,7 +115,7 @@ public final class KartiaHelperAdolph extends AbstractNpcAI
final double radian = Math.toRadians(Util.convertHeadingToDegree(instancePlayer.getHeading()));
final int X = (int) (instancePlayer.getX() + (Math.cos(radian) * 150));
final int Y = (int) (instancePlayer.getY() + (Math.sin(radian) * 150));
final Location loc = GeoData.getInstance().moveCheck(instancePlayer.getX(), instancePlayer.getY(), instancePlayer.getZ(), X, Y, instancePlayer.getZ(), instance);
final Location loc = GeoEngine.getInstance().canMoveToTargetLoc(instancePlayer.getX(), instancePlayer.getY(), instancePlayer.getZ(), X, Y, instancePlayer.getZ(), instance);
if (!npc.isInsideRadius(loc, 50, true, true))
{

View File

@@ -19,7 +19,7 @@ package ai.areas.KartiasLabyrinth;
import java.util.List;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Npc;
@@ -64,7 +64,7 @@ public final class KartiaSupportTroop extends AbstractNpcAI
{
final L2MonsterInstance monster = monsterList.get(getRandom(monsterList.size()));
if (monster.isTargetable() && GeoData.getInstance().canSeeTarget(npc, monster))
if (monster.isTargetable() && GeoEngine.getInstance().canSeeTarget(npc, monster))
{
addAttackDesire(npc, monster);
}

View File

@@ -18,7 +18,7 @@ package ai.areas.PlainsOfDion;
import com.l2jmobius.commons.util.CommonUtil;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2MonsterInstance;
@@ -78,7 +78,7 @@ public final class PlainsOfDion extends AbstractNpcAI
L2World.getInstance().forEachVisibleObjectInRange(npc, L2MonsterInstance.class, npc.getTemplate().getClanHelpRange(), obj ->
{
if (CommonUtil.contains(DELU_LIZARDMEN, obj.getId()) && !obj.isAttackingNow() && !obj.isDead() && GeoData.getInstance().canSeeTarget(npc, obj))
if (CommonUtil.contains(DELU_LIZARDMEN, obj.getId()) && !obj.isAttackingNow() && !obj.isDead() && GeoEngine.getInstance().canSeeTarget(npc, obj))
{
addAttackPlayerDesire(obj, player);
obj.broadcastSay(ChatType.NPC_GENERAL, MONSTERS_ASSIST_MSG[getRandom(3)]);

View File

@@ -19,7 +19,7 @@ package ai.areas.PrimevalIsle;
import com.l2jmobius.commons.util.CommonUtil;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.handler.IItemHandler;
import com.l2jmobius.gameserver.handler.ItemHandler;
import com.l2jmobius.gameserver.model.L2World;
@@ -270,7 +270,7 @@ public final class PrimevalIsle extends AbstractNpcAI
final double cos = Math.cos(radian);
final int newX = (int) (npc.getX() + (cos * distance));
final int newY = (int) (npc.getY() + (sin * distance));
final Location loc = GeoData.getInstance().moveCheck(npc.getX(), npc.getY(), npc.getZ(), newX, newY, npc.getZ(), npc.getInstanceWorld());
final Location loc = GeoEngine.getInstance().canMoveToTargetLoc(npc.getX(), npc.getY(), npc.getZ(), newX, newY, npc.getZ(), npc.getInstanceWorld());
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, loc, 0);
}
else if (ag_type == 1)

View File

@@ -17,7 +17,8 @@
package ai.areas.TalkingIsland;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
@@ -74,14 +75,16 @@ public final class BoyAndGirl extends AbstractNpcAI
getTimers().addTimer("NPC_CHANGEWEAP", 15000 + (getRandom(5) * 1000), npc, null);
getTimers().addTimer("NPC_SHOUT", 10000 + (getRandom(5) * 1000), npc, null);
npc.setIsRunning(true);
addMoveToDesire(npc, GeoData.getInstance().moveCheck(npc.getLocation(), Util.getRandomPosition(npc.getSpawn().getLocation(), 200, 600), npc.getInstanceWorld()), 23);
final Location randomLoc = Util.getRandomPosition(npc.getSpawn().getLocation(), 200, 600);
addMoveToDesire(npc, GeoEngine.getInstance().canMoveToTargetLoc(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
return super.onSpawn(npc);
}
@Override
public void onMoveFinished(L2Npc npc)
{
addMoveToDesire(npc, GeoData.getInstance().moveCheck(npc.getLocation(), Util.getRandomPosition(npc.getSpawn().getLocation(), 200, 600), npc.getInstanceWorld()), 23);
final Location randomLoc = Util.getRandomPosition(npc.getSpawn().getLocation(), 200, 600);
addMoveToDesire(npc, GeoEngine.getInstance().canMoveToTargetLoc(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
super.onMoveFinished(npc);
}

View File

@@ -17,7 +17,8 @@
package ai.areas.TalkingIsland;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
@@ -47,8 +48,8 @@ public final class Devno extends AbstractNpcAI
{
if (getRandomBoolean())
{
addMoveToDesire(npc, GeoData.getInstance().moveCheck(npc.getLocation(), Util.getRandomPosition(npc.getSpawn().getLocation(), 0, 500), npc.getInstanceWorld()), 23);
final Location randomLoc = Util.getRandomPosition(npc.getSpawn().getLocation(), 0, 500);
addMoveToDesire(npc, GeoEngine.getInstance().canMoveToTargetLoc(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
}
getTimers().addTimer("NPC_MOVE", (10 + getRandom(5)) * 1000, npc, null);
}

View File

@@ -17,7 +17,8 @@
package ai.areas.TalkingIsland;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
@@ -47,7 +48,8 @@ public final class Eleve extends AbstractNpcAI
{
if (getRandomBoolean())
{
addMoveToDesire(npc, GeoData.getInstance().moveCheck(npc.getLocation(), Util.getRandomPosition(npc.getSpawn().getLocation(), 0, 500), npc.getInstanceWorld()), 23);
final Location randomLoc = Util.getRandomPosition(npc.getSpawn().getLocation(), 0, 500);
addMoveToDesire(npc, GeoEngine.getInstance().canMoveToTargetLoc(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
}
getTimers().addTimer("NPC_MOVE", (10 + getRandom(5)) * 1000, npc, null);
}

View File

@@ -16,7 +16,7 @@
*/
package ai.areas.TalkingIsland;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
@@ -46,7 +46,7 @@ public final class Handermonkey extends AbstractNpcAI
{
final int x = npc.getSpawn().getX() + (getRandom(-100, 100));
final int y = npc.getSpawn().getY() + (getRandom(-100, 100));
final Location loc = GeoData.getInstance().moveCheck(npc.getX(), npc.getY(), npc.getZ(), x, y, npc.getZ(), npc.getInstanceWorld());
final Location loc = GeoEngine.getInstance().canMoveToTargetLoc(npc.getX(), npc.getY(), npc.getZ(), x, y, npc.getZ(), npc.getInstanceWorld());
addMoveToDesire(npc, loc, 0);
}
else

View File

@@ -17,7 +17,8 @@
package ai.areas.TalkingIsland;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
@@ -47,7 +48,8 @@ public final class Karonf extends AbstractNpcAI
{
if (getRandomBoolean())
{
addMoveToDesire(npc, GeoData.getInstance().moveCheck(npc.getLocation(), Util.getRandomPosition(npc.getSpawn().getLocation(), 0, 500), npc.getInstanceWorld()), 23);
final Location randomLoc = Util.getRandomPosition(npc.getSpawn().getLocation(), 0, 500);
addMoveToDesire(npc, GeoEngine.getInstance().canMoveToTargetLoc(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
}
getTimers().addTimer("NPC_MOVE", (10 + getRandom(5)) * 1000, npc, null);
}

View File

@@ -17,7 +17,8 @@
package ai.areas.TalkingIsland;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
@@ -47,7 +48,8 @@ public final class Marsha extends AbstractNpcAI
{
if (getRandomBoolean())
{
addMoveToDesire(npc, GeoData.getInstance().moveCheck(npc.getLocation(), Util.getRandomPosition(npc.getSpawn().getLocation(), 0, 500), npc.getInstanceWorld()), 23);
final Location randomLoc = Util.getRandomPosition(npc.getSpawn().getLocation(), 0, 500);
addMoveToDesire(npc, GeoEngine.getInstance().canMoveToTargetLoc(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
}
getTimers().addTimer("NPC_MOVE", (10 + getRandom(5)) * 1000, npc, null);
}

View File

@@ -17,7 +17,8 @@
package ai.areas.TalkingIsland;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
@@ -47,7 +48,8 @@ public final class Morgan extends AbstractNpcAI
{
if (getRandomBoolean())
{
addMoveToDesire(npc, GeoData.getInstance().moveCheck(npc.getLocation(), Util.getRandomPosition(npc.getSpawn().getLocation(), 0, 500), npc.getInstanceWorld()), 23);
final Location randomLoc = Util.getRandomPosition(npc.getSpawn().getLocation(), 0, 500);
addMoveToDesire(npc, GeoEngine.getInstance().canMoveToTargetLoc(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
}
getTimers().addTimer("NPC_MOVE", (10 + getRandom(5)) * 1000, npc, null);
}

View File

@@ -17,7 +17,8 @@
package ai.areas.TalkingIsland;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
@@ -47,7 +48,8 @@ public final class Rubentis extends AbstractNpcAI
{
if (getRandomBoolean())
{
addMoveToDesire(npc, GeoData.getInstance().moveCheck(npc.getLocation(), Util.getRandomPosition(npc.getSpawn().getLocation(), 0, 500), npc.getInstanceWorld()), 23);
final Location randomLoc = Util.getRandomPosition(npc.getSpawn().getLocation(), 0, 500);
addMoveToDesire(npc, GeoEngine.getInstance().canMoveToTargetLoc(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
}
getTimers().addTimer("NPC_MOVE", 10000 + (getRandom(5) * 1000), npc, null);
}

View File

@@ -23,7 +23,7 @@ import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
import java.util.ArrayList;
import com.l2jmobius.gameserver.data.xml.impl.SkillData;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Npc;
@@ -224,7 +224,7 @@ public final class ScarletVanHalisha extends AbstractNpcAI
continue;
}
if (((((L2Character) obj).getZ() < (npc.getZ() - 100)) && (((L2Character) obj).getZ() > (npc.getZ() + 100))) || !GeoData.getInstance().canSeeTarget(((L2Character) obj).getX(), ((L2Character) obj).getY(), ((L2Character) obj).getZ(), npc.getX(), npc.getY(), npc.getZ()))
if (((((L2Character) obj).getZ() < (npc.getZ() - 100)) && (((L2Character) obj).getZ() > (npc.getZ() + 100))) || !GeoEngine.getInstance().canSeeTarget(obj, npc))
{
continue;
}

View File

@@ -33,7 +33,7 @@ import com.l2jmobius.commons.util.IGameXmlReader;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.enums.Movie;
import com.l2jmobius.gameserver.enums.TrapAction;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.instancemanager.GraciaSeedsManager;
import com.l2jmobius.gameserver.model.L2Territory;
import com.l2jmobius.gameserver.model.L2World;
@@ -340,7 +340,7 @@ public final class Stage1 extends AbstractInstance implements IGameXmlReader
final Location location = terr.getRandomPoint();
if (location != null)
{
spawn(world, spw.npcId, location.getX(), location.getY(), GeoData.getInstance().getSpawnHeight(location), getRandom(65535), spw.isNeededNextFlag);
spawn(world, spw.npcId, location.getX(), location.getY(), GeoEngine.getInstance().getHeight(location.getX(), location.getY(), location.getZ()), getRandom(65535), spw.isNeededNextFlag);
}
}
}

View File

@@ -23,7 +23,7 @@ import com.l2jmobius.Config;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.data.xml.impl.SkillData;
import com.l2jmobius.gameserver.enums.MountType;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.instancemanager.GrandBossManager;
import com.l2jmobius.gameserver.instancemanager.ZoneManager;
import com.l2jmobius.gameserver.model.L2World;
@@ -475,7 +475,7 @@ public final class Valakas extends AbstractNpcAI
{
final int posX = npc.getX() + getRandom(-1400, 1400);
final int posY = npc.getY() + getRandom(-1400, 1400);
if (GeoData.getInstance().canMove(npc, posX, posY, npc.getZ()))
if (GeoEngine.getInstance().canMoveToTarget(npc.getX(), npc.getY(), npc.getZ(), posX, posY, npc.getZ(), npc.getInstanceWorld()))
{
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(posX, posY, npc.getZ(), 0));
}

View File

@@ -17,7 +17,7 @@
package ai.others;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.L2Summon;
@@ -69,7 +69,7 @@ public final class FleeMonsters extends AbstractNpcAI
final int posY = (int) (npc.getY() + (FLEE_DISTANCE * Math.sin(radians)));
final int posZ = npc.getZ();
final Location destination = GeoData.getInstance().moveCheck(npc.getX(), npc.getY(), npc.getZ(), posX, posY, posZ, attacker.getInstanceWorld());
final Location destination = GeoEngine.getInstance().canMoveToTargetLoc(npc.getX(), npc.getY(), npc.getZ(), posX, posY, posZ, attacker.getInstanceWorld());
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, destination);
return super.onAttack(npc, attacker, damage, isSummon);
}

View File

@@ -19,7 +19,7 @@ package handlers.actionhandlers;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.enums.InstanceType;
import com.l2jmobius.gameserver.enums.PrivateStoreType;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.handler.IActionHandler;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.L2Character;
@@ -93,7 +93,7 @@ public class L2PcInstanceAction implements IActionHandler
}
else
{
if (GeoData.getInstance().canSeeTarget(activeChar, target))
if (GeoEngine.getInstance().canSeeTarget(activeChar, target))
{
activeChar.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, target);
activeChar.onActionRequest();
@@ -104,7 +104,7 @@ public class L2PcInstanceAction implements IActionHandler
{
// This Action Failed packet avoids activeChar getting stuck when clicking three or more times
activeChar.sendPacket(ActionFailed.STATIC_PACKET);
if (GeoData.getInstance().canSeeTarget(activeChar, target))
if (GeoEngine.getInstance().canSeeTarget(activeChar, target))
{
activeChar.getAI().setIntention(CtrlIntention.AI_INTENTION_FOLLOW, target);
}

View File

@@ -18,7 +18,7 @@ package handlers.actionhandlers;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.enums.InstanceType;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.handler.IActionHandler;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.L2Character;
@@ -58,7 +58,7 @@ public class L2PetInstanceAction implements IActionHandler
// Check if the pet is attackable (without a forced attack) and isn't dead
if (target.isAutoAttackable(activeChar) && !isOwner)
{
if (GeoData.getInstance().canSeeTarget(activeChar, target))
if (GeoEngine.getInstance().canSeeTarget(activeChar, target))
{
// Set the L2PcInstance Intention to AI_INTENTION_ATTACK
activeChar.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, target);
@@ -67,7 +67,7 @@ public class L2PetInstanceAction implements IActionHandler
}
else if (!((L2Character) target).isInsideRadius(activeChar, 150, false, false))
{
if (GeoData.getInstance().canSeeTarget(activeChar, target))
if (GeoEngine.getInstance().canSeeTarget(activeChar, target))
{
activeChar.getAI().setIntention(CtrlIntention.AI_INTENTION_INTERACT, target);
activeChar.onActionRequest();

View File

@@ -18,7 +18,7 @@ package handlers.actionhandlers;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.enums.InstanceType;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.handler.IActionHandler;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.L2Summon;
@@ -58,7 +58,7 @@ public class L2SummonAction implements IActionHandler
{
if (target.isAutoAttackable(activeChar))
{
if (GeoData.getInstance().canSeeTarget(activeChar, target))
if (GeoEngine.getInstance().canSeeTarget(activeChar, target))
{
activeChar.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, target);
activeChar.onActionRequest();
@@ -72,7 +72,7 @@ public class L2SummonAction implements IActionHandler
{
activeChar.updateNotMoveUntil();
}
else if (GeoData.getInstance().canSeeTarget(activeChar, target))
else if (GeoEngine.getInstance().canSeeTarget(activeChar, target))
{
activeChar.getAI().setIntention(CtrlIntention.AI_INTENTION_FOLLOW, target);
}

View File

@@ -18,7 +18,7 @@ package handlers.admincommandhandlers;
import java.util.StringTokenizer;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
@@ -54,12 +54,12 @@ public class AdminGeodata implements IAdminCommandHandler
final int worldX = activeChar.getX();
final int worldY = activeChar.getY();
final int worldZ = activeChar.getZ();
final int geoX = GeoData.getInstance().getGeoX(worldX);
final int geoY = GeoData.getInstance().getGeoY(worldY);
final int geoX = GeoEngine.getInstance().getGeoX(worldX);
final int geoY = GeoEngine.getInstance().getGeoY(worldY);
if (GeoData.getInstance().hasGeoPos(geoX, geoY))
if (GeoEngine.getInstance().hasGeoPos(geoX, geoY))
{
activeChar.sendMessage("WorldX: " + worldX + ", WorldY: " + worldY + ", WorldZ: " + worldZ + ", GeoX: " + geoX + ", GeoY: " + geoY + ", GeoZ: " + GeoData.getInstance().getNearestZ(geoX, geoY, worldZ));
activeChar.sendMessage("WorldX: " + worldX + ", WorldY: " + worldY + ", WorldZ: " + worldZ + ", GeoX: " + geoX + ", GeoY: " + geoY + ", GeoZ: " + GeoEngine.getInstance().getHeight(worldX, worldY, worldZ));
}
else
{
@@ -72,12 +72,12 @@ public class AdminGeodata implements IAdminCommandHandler
final int worldX = activeChar.getX();
final int worldY = activeChar.getY();
final int worldZ = activeChar.getZ();
final int geoX = GeoData.getInstance().getGeoX(worldX);
final int geoY = GeoData.getInstance().getGeoY(worldY);
final int geoX = GeoEngine.getInstance().getGeoX(worldX);
final int geoY = GeoEngine.getInstance().getGeoY(worldY);
if (GeoData.getInstance().hasGeoPos(geoX, geoY))
if (GeoEngine.getInstance().hasGeoPos(geoX, geoY))
{
activeChar.sendMessage("WorldX: " + worldX + ", WorldY: " + worldY + ", WorldZ: " + worldZ + ", GeoX: " + geoX + ", GeoY: " + geoY + ", GeoZ: " + GeoData.getInstance().getSpawnHeight(worldX, worldY, worldZ));
activeChar.sendMessage("WorldX: " + worldX + ", WorldY: " + worldY + ", WorldZ: " + worldZ + ", GeoX: " + geoX + ", GeoY: " + geoY + ", GeoZ: " + GeoEngine.getInstance().getHeight(worldX, worldY, worldZ));
}
else
{
@@ -90,7 +90,7 @@ public class AdminGeodata implements IAdminCommandHandler
final L2Object target = activeChar.getTarget();
if (target != null)
{
if (GeoData.getInstance().canSeeTarget(activeChar, target))
if (GeoEngine.getInstance().canSeeTarget(activeChar, target))
{
activeChar.sendMessage("Can move beeline.");
}
@@ -110,7 +110,7 @@ public class AdminGeodata implements IAdminCommandHandler
final L2Object target = activeChar.getTarget();
if (target != null)
{
if (GeoData.getInstance().canSeeTarget(activeChar, target))
if (GeoEngine.getInstance().canSeeTarget(activeChar, target))
{
activeChar.sendMessage("Can see target.");
}

View File

@@ -18,78 +18,49 @@ package handlers.admincommandhandlers;
import java.util.List;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNodeLoc;
import com.l2jmobius.gameserver.geodata.pathfinding.PathFinding;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.SystemMessageId;
public class AdminPathNode implements IAdminCommandHandler
{
private static final String[] ADMIN_COMMANDS =
{
"admin_pn_info",
"admin_show_path",
"admin_path_debug",
"admin_show_pn",
"admin_find_path",
"admin_path_find",
};
@Override
public boolean useAdminCommand(String command, L2PcInstance activeChar)
{
if (command.equals("admin_pn_info"))
if (command.equals("admin_path_find"))
{
final String[] info = PathFinding.getInstance().getStat();
if (info == null)
{
activeChar.sendMessage("Not supported");
}
else
{
for (String msg : info)
{
activeChar.sendMessage(msg);
}
}
}
else if (command.equals("admin_show_path"))
{
}
else if (command.equals("admin_path_debug"))
{
}
else if (command.equals("admin_show_pn"))
{
}
else if (command.equals("admin_find_path"))
{
if (Config.PATHFINDING == 0)
{
activeChar.sendMessage("PathFinding is disabled.");
return true;
}
if (activeChar.getTarget() != null)
{
final List<AbstractNodeLoc> path = PathFinding.getInstance().findPath(activeChar.getX(), activeChar.getY(), (short) activeChar.getZ(), activeChar.getTarget().getX(), activeChar.getTarget().getY(), (short) activeChar.getTarget().getZ(), activeChar.getInstanceWorld(), true);
List<Location> path = GeoEngine.getInstance().findPath(activeChar.getX(), activeChar.getY(), (short) activeChar.getZ(), activeChar.getTarget().getX(), activeChar.getTarget().getY(), (short) activeChar.getTarget().getZ(), activeChar.getInstanceWorld(), true);
if (path == null)
{
activeChar.sendMessage("No Route!");
return true;
activeChar.sendMessage("No route found or pathfinding disabled.");
}
for (AbstractNodeLoc a : path)
else
{
activeChar.sendMessage("x:" + a.getX() + " y:" + a.getY() + " z:" + a.getZ());
for (Location point : path)
{
activeChar.sendMessage("x:" + point.getX() + " y:" + point.getY() + " z:" + point.getZ());
}
}
}
else
{
activeChar.sendMessage("No Target!");
activeChar.sendPacket(SystemMessageId.INVALID_TARGET);
}
}
else
{
return false;
}
return true;
}

View File

@@ -60,7 +60,7 @@ public class AdminServerInfo implements IAdminCommandHandler
html.replace("%slots%", getPlayersCount("ALL") + "/" + Config.MAXIMUM_ONLINE_USERS);
html.replace("%gameTime%", GameTimeController.getInstance().getGameHour() + ":" + GameTimeController.getInstance().getGameMinute());
html.replace("%dayNight%", GameTimeController.getInstance().isNight() ? "Night" : "Day");
html.replace("%geodata%", Config.PATHFINDING > 0 ? "Enabled" : "Disabled");
html.replace("%geodata%", Config.PATHFINDING ? "Enabled" : "Disabled");
html.replace("%serverTime%", fmt.format(new Date(System.currentTimeMillis())));
html.replace("%serverUpTime%", getServerUpTime());
html.replace("%onlineAll%", getPlayersCount("ALL"));

View File

@@ -29,7 +29,7 @@ import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.data.xml.impl.NpcData;
import com.l2jmobius.gameserver.datatables.SpawnTable;
import com.l2jmobius.gameserver.enums.AdminTeleportType;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
import com.l2jmobius.gameserver.instancemanager.DBSpawnManager;
import com.l2jmobius.gameserver.instancemanager.MapRegionManager;
@@ -194,7 +194,7 @@ public class AdminTeleport implements IAdminCommandHandler
st.nextToken();
final int x = (int) Float.parseFloat(st.nextToken());
final int y = (int) Float.parseFloat(st.nextToken());
final int z = st.hasMoreTokens() ? ((int) Float.parseFloat(st.nextToken())) : GeoData.getInstance().getHeight(x, y, L2World.MAP_MAX_Z);
final int z = st.hasMoreTokens() ? ((int) Float.parseFloat(st.nextToken())) : GeoEngine.getInstance().getHeight(x, y, L2World.MAP_MAX_Z);
activeChar.teleToLocation(x, y, z);
}

View File

@@ -34,7 +34,7 @@ import com.l2jmobius.Config;
import com.l2jmobius.commons.util.CommonUtil;
import com.l2jmobius.commons.util.Rnd;
import com.l2jmobius.gameserver.enums.PlayerAction;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
import com.l2jmobius.gameserver.instancemanager.ZoneManager;
import com.l2jmobius.gameserver.model.Location;
@@ -301,7 +301,7 @@ public class AdminZones extends AbstractNpcAI implements IAdminCommandHandler
{
final int x = zone.getX()[i];
final int y = zone.getY()[i];
holder.addNode(new Location(x, y, GeoData.getInstance().getSpawnHeight(x, y, Rnd.get(zone.getLowZ(), zone.getHighZ()))));
holder.addNode(new Location(x, y, GeoEngine.getInstance().getHeight(x, y, Rnd.get(zone.getLowZ(), zone.getHighZ()))));
}
showPoints(activeChar);
}

View File

@@ -17,7 +17,7 @@
package handlers.effecthandlers;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Character;
@@ -89,7 +89,7 @@ public final class Blink extends AbstractEffect
final int y = effected.getY() + y1;
final int z = effected.getZ();
final Location destination = GeoData.getInstance().moveCheck(effected.getX(), effected.getY(), effected.getZ(), x, y, z, effected.getInstanceWorld());
final Location destination = GeoEngine.getInstance().canMoveToTargetLoc(effected.getX(), effected.getY(), effected.getZ(), x, y, z, effected.getInstanceWorld());
effected.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
effected.broadcastPacket(new FlyToLocation(effected, destination, _flyType, _flySpeed, _flyDelay, _animationSpeed));

View File

@@ -19,7 +19,7 @@ package handlers.effecthandlers;
import com.l2jmobius.gameserver.ai.CtrlEvent;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.enums.Race;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Character;
@@ -90,7 +90,7 @@ public final class Fear extends AbstractEffect
final int posY = (int) (effected.getY() + (FEAR_RANGE * Math.sin(radians)));
final int posZ = effected.getZ();
final Location destination = GeoData.getInstance().moveCheck(effected.getX(), effected.getY(), effected.getZ(), posX, posY, posZ, effected.getInstanceWorld());
final Location destination = GeoEngine.getInstance().canMoveToTargetLoc(effected.getX(), effected.getY(), effected.getZ(), posX, posY, posZ, effected.getInstanceWorld());
effected.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, destination);
}
}

View File

@@ -16,7 +16,7 @@
*/
package handlers.effecthandlers;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Character;
@@ -57,7 +57,7 @@ public final class FlyAway extends AbstractEffect
final int y = (int) (effector.getY() - (nRadius * (dy / distance)));
final int z = effector.getZ();
final Location destination = GeoData.getInstance().moveCheck(effected.getX(), effected.getY(), effected.getZ(), x, y, z, effected.getInstanceWorld());
final Location destination = GeoEngine.getInstance().canMoveToTargetLoc(effected.getX(), effected.getY(), effected.getZ(), x, y, z, effected.getInstanceWorld());
effected.broadcastPacket(new FlyToLocation(effected, destination, FlyType.THROW_UP));
effected.setXYZ(destination);

View File

@@ -18,7 +18,7 @@ package handlers.effecthandlers;
import com.l2jmobius.gameserver.ai.CtrlEvent;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Character;
@@ -107,7 +107,7 @@ public final class KnockBack extends AbstractEffect
final int x = (int) (effected.getX() + (_distance * Math.cos(radians)));
final int y = (int) (effected.getY() + (_distance * Math.sin(radians)));
final int z = effected.getZ();
final Location loc = GeoData.getInstance().moveCheck(effected.getX(), effected.getY(), effected.getZ(), x, y, z, effected.getInstanceWorld());
final Location loc = GeoEngine.getInstance().canMoveToTargetLoc(effected.getX(), effected.getY(), effected.getZ(), x, y, z, effected.getInstanceWorld());
effected.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
effected.broadcastPacket(new FlyToLocation(effected, loc, _type, _speed, _delay, _animationSpeed));

View File

@@ -16,7 +16,7 @@
*/
package handlers.effecthandlers;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.effects.AbstractEffect;
@@ -62,7 +62,7 @@ public final class PullBack extends AbstractEffect
public void instant(L2Character effector, L2Character effected, Skill skill, L2ItemInstance item)
{
// In retail, you get debuff, but you are not even moved if there is obstacle. You are still disabled from using skills and moving though.
if (GeoData.getInstance().canMove(effected, effector))
if (GeoEngine.getInstance().canMoveToTarget(effected.getX(), effected.getY(), effected.getZ(), effector.getX(), effector.getY(), effector.getZ(), effector.getInstanceWorld()))
{
effected.broadcastPacket(new FlyToLocation(effected, effector, _type, _speed, _delay, _animationSpeed));
effected.setXYZ(effector);

View File

@@ -17,7 +17,7 @@
package handlers.effecthandlers;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Character;
@@ -88,7 +88,7 @@ public final class TeleportToSummon extends AbstractEffect
final int y = (int) (py + (25 * Math.sin(ph)));
final int z = summon.getZ();
final Location loc = GeoData.getInstance().moveCheck(effector.getX(), effector.getY(), effector.getZ(), x, y, z, effector.getInstanceWorld());
final Location loc = GeoEngine.getInstance().canMoveToTargetLoc(effector.getX(), effector.getY(), effector.getZ(), x, y, z, effector.getInstanceWorld());
effector.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
effector.broadcastPacket(new FlyToLocation(effector, loc.getX(), loc.getY(), loc.getZ(), FlyType.DUMMY));

View File

@@ -17,7 +17,7 @@
package handlers.effecthandlers;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Character;
@@ -70,7 +70,7 @@ public final class TeleportToTarget extends AbstractEffect
final int y = (int) (py + (25 * Math.sin(ph)));
final int z = effected.getZ();
final Location loc = GeoData.getInstance().moveCheck(effector.getX(), effector.getY(), effector.getZ(), x, y, z, effector.getInstanceWorld());
final Location loc = GeoEngine.getInstance().canMoveToTargetLoc(effector.getX(), effector.getY(), effector.getZ(), x, y, z, effector.getInstanceWorld());
effector.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
effector.broadcastPacket(new FlyToLocation(effector, loc.getX(), loc.getY(), loc.getZ(), FlyType.DUMMY));

View File

@@ -17,7 +17,7 @@
package handlers.skillconditionhandlers;
import com.l2jmobius.gameserver.enums.Position;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Character;
@@ -70,6 +70,6 @@ public class OpBlinkSkillCondition implements ISkillCondition
final int y = caster.getY() + y1;
final int z = caster.getZ();
return GeoData.getInstance().canMove(caster.getX(), caster.getY(), caster.getZ(), x, y, z, caster.getInstanceWorld());
return GeoEngine.getInstance().canMoveToTarget(caster.getX(), caster.getY(), caster.getZ(), x, y, z, caster.getInstanceWorld());
}
}

View File

@@ -16,7 +16,7 @@
*/
package handlers.targethandlers;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.handler.ITargetTypeHandler;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.L2Character;
@@ -103,7 +103,7 @@ public class Enemy implements ITargetTypeHandler
}
// Geodata check when character is within range.
if (!GeoData.getInstance().canSeeTarget(activeChar, target))
if (!GeoEngine.getInstance().canSeeTarget(activeChar, target))
{
if (sendMessage)
{

View File

@@ -16,7 +16,7 @@
*/
package handlers.targethandlers;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.handler.ITargetTypeHandler;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.L2Character;
@@ -73,7 +73,7 @@ public class EnemyNot implements ITargetTypeHandler
}
}
if ((skill.isFlyType()) && !GeoData.getInstance().canMove(activeChar, target))
if ((skill.isFlyType()) && !GeoEngine.getInstance().canMoveToTarget(activeChar.getX(), activeChar.getY(), activeChar.getZ(), target.getX(), target.getY(), target.getZ(), activeChar.getInstanceWorld()))
{
if (sendMessage)
{
@@ -83,7 +83,7 @@ public class EnemyNot implements ITargetTypeHandler
}
// Geodata check when character is within range.
if (!GeoData.getInstance().canSeeTarget(activeChar, target))
if (!GeoEngine.getInstance().canSeeTarget(activeChar, target))
{
if (sendMessage)
{

View File

@@ -16,7 +16,7 @@
*/
package handlers.targethandlers;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.handler.ITargetTypeHandler;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.L2Character;
@@ -103,7 +103,7 @@ public class EnemyOnly implements ITargetTypeHandler
}
// Geodata check when character is within range.
if (!GeoData.getInstance().canSeeTarget(activeChar, target))
if (!GeoEngine.getInstance().canSeeTarget(activeChar, target))
{
if (sendMessage)
{

View File

@@ -16,7 +16,7 @@
*/
package handlers.targethandlers;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.handler.ITargetTypeHandler;
import com.l2jmobius.gameserver.instancemanager.ZoneManager;
import com.l2jmobius.gameserver.model.L2Object;
@@ -52,7 +52,7 @@ public class Ground implements ITargetTypeHandler
return null;
}
if (!GeoData.getInstance().canSeeTarget(activeChar, worldPosition))
if (!GeoEngine.getInstance().canSeeTarget(activeChar, worldPosition))
{
if (sendMessage)
{

View File

@@ -16,7 +16,7 @@
*/
package handlers.targethandlers;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.handler.ITargetTypeHandler;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.L2Character;
@@ -80,7 +80,7 @@ public class NpcBody implements ITargetTypeHandler
}
// Geodata check when character is within range.
if (!GeoData.getInstance().canSeeTarget(activeChar, npc))
if (!GeoEngine.getInstance().canSeeTarget(activeChar, npc))
{
if (sendMessage)
{

View File

@@ -16,7 +16,7 @@
*/
package handlers.targethandlers;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.handler.ITargetTypeHandler;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.L2Character;
@@ -107,7 +107,7 @@ public class PcBody implements ITargetTypeHandler
}
// Geodata check when character is within range.
if (!GeoData.getInstance().canSeeTarget(activeChar, target))
if (!GeoEngine.getInstance().canSeeTarget(activeChar, target))
{
if (sendMessage)
{

View File

@@ -16,7 +16,7 @@
*/
package handlers.targethandlers;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.handler.ITargetTypeHandler;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.L2Character;
@@ -75,7 +75,7 @@ public class Target implements ITargetTypeHandler
}
}
if ((skill.isFlyType()) && !GeoData.getInstance().canMove(activeChar, target))
if (skill.isFlyType() && !GeoEngine.getInstance().canMoveToTarget(activeChar.getX(), activeChar.getY(), activeChar.getZ(), target.getX(), target.getY(), target.getZ(), activeChar.getInstanceWorld()))
{
if (sendMessage)
{
@@ -85,7 +85,7 @@ public class Target implements ITargetTypeHandler
}
// Geodata check when character is within range.
if (!GeoData.getInstance().canSeeTarget(activeChar, target))
if (!GeoEngine.getInstance().canSeeTarget(activeChar, target))
{
if (sendMessage)
{

View File

@@ -20,7 +20,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Predicate;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.handler.AffectObjectHandler;
import com.l2jmobius.gameserver.handler.IAffectObjectHandler;
import com.l2jmobius.gameserver.handler.IAffectScopeHandler;
@@ -67,7 +67,7 @@ public class Fan implements IAffectScopeHandler
{
return false;
}
if (!GeoData.getInstance().canSeeTarget(activeChar, c))
if (!GeoEngine.getInstance().canSeeTarget(activeChar, c))
{
return false;
}

View File

@@ -20,7 +20,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Predicate;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.handler.AffectObjectHandler;
import com.l2jmobius.gameserver.handler.IAffectObjectHandler;
import com.l2jmobius.gameserver.handler.IAffectScopeHandler;
@@ -68,7 +68,7 @@ public class FanPB implements IAffectScopeHandler
{
return false;
}
if (!GeoData.getInstance().canSeeTarget(activeChar, c))
if (!GeoEngine.getInstance().canSeeTarget(activeChar, c))
{
return false;
}

View File

@@ -20,7 +20,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Predicate;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.handler.AffectObjectHandler;
import com.l2jmobius.gameserver.handler.IAffectObjectHandler;
import com.l2jmobius.gameserver.handler.IAffectScopeHandler;
@@ -59,7 +59,7 @@ public class PointBlank implements IAffectScopeHandler
{
return false;
}
if (!GeoData.getInstance().canSeeTarget(target, c))
if (!GeoEngine.getInstance().canSeeTarget(target, c))
{
return false;
}

View File

@@ -20,7 +20,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Predicate;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.handler.AffectObjectHandler;
import com.l2jmobius.gameserver.handler.IAffectObjectHandler;
import com.l2jmobius.gameserver.handler.IAffectScopeHandler;
@@ -65,7 +65,7 @@ public class Range implements IAffectScopeHandler
{
return false;
}
if (!GeoData.getInstance().canSeeTarget(target, c))
if (!GeoEngine.getInstance().canSeeTarget(target, c))
{
return false;
}

View File

@@ -20,7 +20,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Predicate;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.handler.AffectObjectHandler;
import com.l2jmobius.gameserver.handler.IAffectObjectHandler;
import com.l2jmobius.gameserver.handler.IAffectScopeHandler;
@@ -69,7 +69,7 @@ public class RingRange implements IAffectScopeHandler
return false;
}
if (!GeoData.getInstance().canSeeTarget(target, c))
if (!GeoEngine.getInstance().canSeeTarget(target, c))
{
return false;
}

View File

@@ -20,7 +20,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Predicate;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.handler.AffectObjectHandler;
import com.l2jmobius.gameserver.handler.IAffectObjectHandler;
import com.l2jmobius.gameserver.handler.IAffectScopeHandler;
@@ -77,7 +77,7 @@ public class Square implements IAffectScopeHandler
{
return false;
}
if (!GeoData.getInstance().canSeeTarget(activeChar, c))
if (!GeoEngine.getInstance().canSeeTarget(activeChar, c))
{
return false;
}

View File

@@ -20,7 +20,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Predicate;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.handler.AffectObjectHandler;
import com.l2jmobius.gameserver.handler.IAffectObjectHandler;
import com.l2jmobius.gameserver.handler.IAffectScopeHandler;
@@ -77,7 +77,7 @@ public class SquarePB implements IAffectScopeHandler
{
return false;
}
if (!GeoData.getInstance().canSeeTarget(activeChar, c))
if (!GeoEngine.getInstance().canSeeTarget(activeChar, c))
{
return false;
}

View File

@@ -24,7 +24,7 @@ import com.l2jmobius.gameserver.enums.CategoryType;
import com.l2jmobius.gameserver.enums.HtmlActionScope;
import com.l2jmobius.gameserver.enums.QuestSound;
import com.l2jmobius.gameserver.enums.Race;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.instancemanager.CastleManager;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.Location;
@@ -561,7 +561,7 @@ public final class Q10753_WindsOfFateChoices extends Quest
player.sendPacket(new ExSendUIEvent(player, true, false, 1, 0, NpcStringId.REMAINING_TIME));
L2World.getInstance().forEachVisibleObjectInRange(npc, L2Npc.class, 1000, box ->
{
if ((box.getId() == ATHREAS_BOX) && GeoData.getInstance().canSeeTarget(npc, box))
if ((box.getId() == ATHREAS_BOX) && GeoEngine.getInstance().canSeeTarget(npc, box))
{
box.deleteMe();
}

View File

@@ -32,7 +32,6 @@ import java.net.URL;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.util.ArrayList;
@@ -60,7 +59,6 @@ import com.l2jmobius.commons.util.PropertiesParser;
import com.l2jmobius.commons.util.StringUtil;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.enums.IllegalActionPunishmentType;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.holders.ItemHolder;
import com.l2jmobius.gameserver.util.FloodProtectorConfig;
@@ -104,7 +102,7 @@ public final class Config
public static final String GRACIASEEDS_CONFIG_FILE = "./config/GraciaSeeds.ini";
public static final String CHAT_FILTER_FILE = "./config/chatfilter.txt";
public static final String CH_SIEGE_FILE = "./config/ConquerableHallSiege.ini";
public static final String GEODATA_FILE = "./config/GeoData.ini";
public static final String GEODATA_FILE = "./config/GeoEngine.ini";
// --------------------------------------------------
// Custom Config File Definitions
@@ -924,22 +922,26 @@ public final class Config
public static int CHS_FAME_AMOUNT;
public static int CHS_FAME_FREQUENCY;
// GeoData Settings
public static int PATHFINDING;
public static File PATHNODE_DIR;
public static String PATHFIND_BUFFERS;
public static float LOW_WEIGHT;
public static float MEDIUM_WEIGHT;
public static float HIGH_WEIGHT;
public static boolean ADVANCED_DIAGONAL_STRATEGY;
public static float DIAGONAL_WEIGHT;
public static int MAX_POSTFILTER_PASSES;
public static boolean DEBUG_PATH;
public static boolean FORCE_GEODATA;
// --------------------------------------------------
// GeoEngine
// --------------------------------------------------
/** Geodata */
public static String GEODATA_PATH;
public static int COORD_SYNCHRONIZE;
public static Path GEODATA_PATH;
public static boolean TRY_LOAD_UNSPECIFIED_REGIONS;
public static Map<String, Boolean> GEODATA_REGIONS;
/** Path checking */
public static int PART_OF_CHARACTER_HEIGHT;
public static int MAX_OBSTACLE_HEIGHT;
/** Path finding */
public static boolean PATHFINDING;
public static String PATHFIND_BUFFERS;
public static int BASE_WEIGHT;
public static int DIAGONAL_WEIGHT;
public static int HEURISTIC_WEIGHT;
public static int OBSTACLE_MULTIPLIER;
public static int MAX_ITERATIONS;
// --------------------------------------------------
// Custom Settings
@@ -2254,41 +2256,19 @@ public final class Config
final PropertiesParser geoData = new PropertiesParser(GEODATA_FILE);
try
{
PATHNODE_DIR = new File(geoData.getString("PathnodeDirectory", "data/pathnode").replaceAll("\\\\", "/")).getCanonicalFile();
}
catch (IOException e)
{
LOGGER.log(Level.WARNING, "Error setting pathnode directory!", e);
PATHNODE_DIR = new File("data/pathnode");
}
PATHFINDING = geoData.getInt("PathFinding", 0);
PATHFIND_BUFFERS = geoData.getString("PathFindBuffers", "100x6;128x6;192x6;256x4;320x4;384x4;500x2");
LOW_WEIGHT = geoData.getFloat("LowWeight", 0.5f);
MEDIUM_WEIGHT = geoData.getFloat("MediumWeight", 2);
HIGH_WEIGHT = geoData.getFloat("HighWeight", 3);
ADVANCED_DIAGONAL_STRATEGY = geoData.getBoolean("AdvancedDiagonalStrategy", true);
DIAGONAL_WEIGHT = geoData.getFloat("DiagonalWeight", 0.707f);
MAX_POSTFILTER_PASSES = geoData.getInt("MaxPostfilterPasses", 3);
DEBUG_PATH = geoData.getBoolean("DebugPath", false);
FORCE_GEODATA = geoData.getBoolean("ForceGeoData", true);
GEODATA_PATH = geoData.getString("GeoDataPath", "./data/geodata/");
COORD_SYNCHRONIZE = geoData.getInt("CoordSynchronize", -1);
GEODATA_PATH = Paths.get(geoData.getString("GeoDataPath", "./data/geodata"));
TRY_LOAD_UNSPECIFIED_REGIONS = geoData.getBoolean("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, geoData.getBoolean(key, false));
}
}
}
PART_OF_CHARACTER_HEIGHT = geoData.getInt("PartOfCharacterHeight", 75);
MAX_OBSTACLE_HEIGHT = geoData.getInt("MaxObstacleHeight", 32);
PATHFINDING = geoData.getBoolean("PathFinding", true);
PATHFIND_BUFFERS = geoData.getString("PathFindBuffers", "100x6;128x6;192x6;256x4;320x4;384x4;500x2");
BASE_WEIGHT = geoData.getInt("BaseWeight", 10);
DIAGONAL_WEIGHT = geoData.getInt("DiagonalWeight", 14);
OBSTACLE_MULTIPLIER = geoData.getInt("ObstacleMultiplier", 10);
HEURISTIC_WEIGHT = geoData.getInt("HeuristicWeight", 20);
MAX_ITERATIONS = geoData.getInt("MaxIterations", 3500);
// Load AllowedPlayerRaces config file (if exists)
final PropertiesParser AllowedPlayerRaces = new PropertiesParser(CUSTOM_ALLOWED_PLAYER_RACES_CONFIG_FILE);

View File

@@ -80,4 +80,15 @@ public class MathUtil
{
return oldValue / value;
}
/**
* @param numToTest : The number to test.
* @param min : The minimum limit.
* @param max : The maximum limit.
* @return the number or one of the limit (mininum / maximum).
*/
public static int limit(int numToTest, int min, int max)
{
return (numToTest > max) ? max : ((numToTest < min) ? min : numToTest);
}
}

View File

@@ -97,8 +97,7 @@ import com.l2jmobius.gameserver.datatables.AugmentationData;
import com.l2jmobius.gameserver.datatables.BotReportTable;
import com.l2jmobius.gameserver.datatables.EventDroplist;
import com.l2jmobius.gameserver.datatables.ItemTable;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geodata.pathfinding.PathFinding;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.handler.ConditionHandler;
import com.l2jmobius.gameserver.handler.DailyMissionHandler;
import com.l2jmobius.gameserver.handler.EffectHandler;
@@ -281,12 +280,8 @@ public class GameServer
printSection("Geodata");
long geodataMemory = getUsedMemoryMB();
GeoData.getInstance();
if (Config.PATHFINDING > 0)
{
PathFinding.getInstance();
}
geodataMemory -= getUsedMemoryMB();
GeoEngine.getInstance();
geodataMemory = getUsedMemoryMB() - geodataMemory;
if (geodataMemory < 0)
{
geodataMemory = 0;

View File

@@ -21,7 +21,7 @@ import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_REST;
import com.l2jmobius.commons.util.Rnd;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.Location;
@@ -150,7 +150,7 @@ public class FriendlyNpcAI extends L2AttackableAI
if (!npc.isInsideRadius(newX, newY, 0, collision, false, false))
{
final int newZ = npc.getZ() + 30;
if (GeoData.getInstance().canMove(npc.getX(), npc.getY(), npc.getZ(), newX, newY, newZ, npc.getInstanceWorld()))
if (GeoEngine.getInstance().canMoveToTarget(npc.getX(), npc.getY(), npc.getZ(), newX, newY, newZ, npc.getInstanceWorld()))
{
moveTo(newX, newY, newZ);
}
@@ -189,7 +189,7 @@ public class FriendlyNpcAI extends L2AttackableAI
posY = posY - 300;
}
if (GeoData.getInstance().canMove(npc.getX(), npc.getY(), npc.getZ(), posX, posY, posZ, npc.getInstanceWorld()))
if (GeoEngine.getInstance().canMoveToTarget(npc.getX(), npc.getY(), npc.getZ(), posX, posY, posZ, npc.getInstanceWorld()))
{
setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(posX, posY, posZ, 0));
}
@@ -210,7 +210,7 @@ public class FriendlyNpcAI extends L2AttackableAI
}
}
if ((dist2 > range) || !GeoData.getInstance().canSeeTarget(npc, originalAttackTarget))
if ((dist2 > range) || !GeoEngine.getInstance().canSeeTarget(npc, originalAttackTarget))
{
if (originalAttackTarget.isMoving())
{

View File

@@ -33,7 +33,7 @@ import com.l2jmobius.commons.util.Rnd;
import com.l2jmobius.gameserver.GameTimeController;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.enums.AISkillScope;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.model.AggroInfo;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
@@ -195,7 +195,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
}
}
return target.isAutoAttackable(me) && GeoData.getInstance().canSeeTarget(me, target);
return target.isAutoAttackable(me) && GeoEngine.getInstance().canSeeTarget(me, target);
}
public void startAITask()
@@ -555,7 +555,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
}
// Move the actor to Location (x,y,z) server side AND client side by sending Server->Client packet CharMoveToLocation (broadcast)
final Location moveLoc = GeoData.getInstance().moveCheck(npc.getX(), npc.getY(), npc.getZ(), x1, y1, z1, npc.getInstanceWorld());
final Location moveLoc = GeoEngine.getInstance().canMoveToTargetLoc(npc.getX(), npc.getY(), npc.getZ(), x1, y1, z1, npc.getInstanceWorld());
moveTo(moveLoc.getX(), moveLoc.getY(), moveLoc.getZ());
}
@@ -696,7 +696,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
if (!npc.isInsideRadius(newX, newY, 0, collision, false, false))
{
final int newZ = npc.getZ() + 30;
if (GeoData.getInstance().canMove(npc, newX, newY, newZ))
if (GeoEngine.getInstance().canMoveToTarget(npc.getX(), npc.getY(), npc.getZ(), newX, newY, newZ, npc.getInstanceWorld()))
{
moveTo(newX, newY, newZ);
}
@@ -736,7 +736,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
posY = posY - 300;
}
if (GeoData.getInstance().canMove(npc, posX, posY, posZ))
if (GeoEngine.getInstance().canMoveToTarget(npc.getX(), npc.getY(), npc.getZ(), posX, posY, posZ, npc.getInstanceWorld()))
{
setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(posX, posY, posZ, 0));
}
@@ -986,7 +986,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
return false;
}
if (!GeoData.getInstance().canSeeTarget(npc, target))
if (!GeoEngine.getInstance().canSeeTarget(npc, target))
{
return false;
}
@@ -998,7 +998,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
}
}
return GeoData.getInstance().canMove(npc, target);
return GeoEngine.getInstance().canMoveToTarget(npc.getX(), npc.getY(), npc.getZ(), target.getX(), target.getY(), target.getZ(), npc.getInstanceWorld());
}
private L2Character skillTargetReconsider(Skill skill, boolean insideCastRange)

View File

@@ -33,7 +33,7 @@ import java.util.logging.Logger;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.enums.ItemLocation;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.instancemanager.WalkingManager;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.Location;
@@ -1094,7 +1094,7 @@ public class L2CharacterAI extends AbstractAI
setIntention(AI_INTENTION_ACTIVE);
return true;
}
if ((_actor != null) && (_skill != null) && _skill.isBad() && (_skill.getAffectRange() > 0) && !GeoData.getInstance().canSeeTarget(_actor, target))
if ((_actor != null) && (_skill != null) && _skill.isBad() && (_skill.getAffectRange() > 0) && !GeoEngine.getInstance().canSeeTarget(_actor, target))
{
setIntention(AI_INTENTION_ACTIVE);
return true;

View File

@@ -26,7 +26,7 @@ import java.util.concurrent.Future;
import com.l2jmobius.commons.util.Rnd;
import com.l2jmobius.gameserver.GameTimeController;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
@@ -161,7 +161,7 @@ public class L2FortSiegeGuardAI extends L2CharacterAI implements Runnable
}
}
// Los Check Here
return (_actor.isAutoAttackable(target) && GeoData.getInstance().canSeeTarget(_actor, target));
return (_actor.isAutoAttackable(target) && GeoEngine.getInstance().canSeeTarget(_actor, target));
}
@@ -431,7 +431,7 @@ public class L2FortSiegeGuardAI extends L2CharacterAI implements Runnable
{
continue;
}
if (!GeoData.getInstance().canSeeTarget(_actor, cha))
if (!GeoEngine.getInstance().canSeeTarget(_actor, cha))
{
break;
}
@@ -460,7 +460,7 @@ public class L2FortSiegeGuardAI extends L2CharacterAI implements Runnable
// && _actor.getAttackByList().contains(getTarget())
&& ((npc.getAI()._intention == CtrlIntention.AI_INTENTION_IDLE) || (npc.getAI()._intention == CtrlIntention.AI_INTENTION_ACTIVE))
// limiting aggro for siege guards
&& npc.isInsideRadius(target, 1500, true, false) && GeoData.getInstance().canSeeTarget(npc, target))
&& npc.isInsideRadius(target, 1500, true, false) && GeoEngine.getInstance().canSeeTarget(npc, target))
{
// Notify the L2Object AI with EVT_AGGRESSION
npc.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, target, 1);
@@ -489,7 +489,7 @@ public class L2FortSiegeGuardAI extends L2CharacterAI implements Runnable
{
continue;
}
if (!GeoData.getInstance().canSeeTarget(_actor, npc))
if (!GeoEngine.getInstance().canSeeTarget(_actor, npc))
{
break;
}
@@ -558,7 +558,7 @@ public class L2FortSiegeGuardAI extends L2CharacterAI implements Runnable
return;
}
if (!GeoData.getInstance().canSeeTarget(_actor, attackTarget))
if (!GeoEngine.getInstance().canSeeTarget(_actor, attackTarget))
{
// Siege guards differ from normal mobs currently:
// If target cannot seen, don't attack any more

View File

@@ -26,7 +26,7 @@ import java.util.concurrent.Future;
import com.l2jmobius.commons.util.Rnd;
import com.l2jmobius.gameserver.GameTimeController;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
@@ -149,7 +149,7 @@ public class L2SiegeGuardAI extends L2CharacterAI implements Runnable
}
}
// Los Check Here
return (_actor.isAutoAttackable(target) && GeoData.getInstance().canSeeTarget(_actor, target));
return (_actor.isAutoAttackable(target) && GeoEngine.getInstance().canSeeTarget(_actor, target));
}
/**
@@ -403,7 +403,7 @@ public class L2SiegeGuardAI extends L2CharacterAI implements Runnable
{
continue;
}
if (!GeoData.getInstance().canSeeTarget(_actor, cha))
if (!GeoEngine.getInstance().canSeeTarget(_actor, cha))
{
break;
}
@@ -432,7 +432,7 @@ public class L2SiegeGuardAI extends L2CharacterAI implements Runnable
// && _actor.getAttackByList().contains(getTarget())
&& ((npc.getAI()._intention == CtrlIntention.AI_INTENTION_IDLE) || (npc.getAI()._intention == CtrlIntention.AI_INTENTION_ACTIVE))
// limiting aggro for siege guards
&& npc.isInsideRadius(target, 1500, true, false) && GeoData.getInstance().canSeeTarget(npc, target))
&& npc.isInsideRadius(target, 1500, true, false) && GeoEngine.getInstance().canSeeTarget(npc, target))
{
// Notify the L2Object AI with EVT_AGGRESSION
npc.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, target, 1);
@@ -461,7 +461,7 @@ public class L2SiegeGuardAI extends L2CharacterAI implements Runnable
{
continue;
}
if (!GeoData.getInstance().canSeeTarget(_actor, npc))
if (!GeoEngine.getInstance().canSeeTarget(_actor, npc))
{
break;
}
@@ -512,7 +512,7 @@ public class L2SiegeGuardAI extends L2CharacterAI implements Runnable
return;
}
if (!GeoData.getInstance().canSeeTarget(_actor, attackTarget))
if (!GeoEngine.getInstance().canSeeTarget(_actor, attackTarget))
{
// Siege guards differ from normal mobs currently:
// If target cannot seen, don't attack any more

View File

@@ -24,7 +24,7 @@ import java.util.concurrent.Future;
import com.l2jmobius.commons.util.Rnd;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Summon;
@@ -295,7 +295,7 @@ public class L2SummonAI extends L2PlayableAI implements Runnable
final int targetX = ownerX + (int) (AVOID_RADIUS * Math.cos(angle));
final int targetY = ownerY + (int) (AVOID_RADIUS * Math.sin(angle));
if (GeoData.getInstance().canMove(_actor, targetX, targetY, _actor.getZ()))
if (GeoEngine.getInstance().canMoveToTarget(_actor.getX(), _actor.getY(), _actor.getZ(), targetX, targetY, _actor.getZ(), _actor.getInstanceWorld()))
{
moveTo(targetX, targetY, _actor.getZ());
}

View File

@@ -34,8 +34,8 @@ import org.w3c.dom.Node;
import com.l2jmobius.commons.util.IGameXmlReader;
import com.l2jmobius.commons.util.IXmlReader;
import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNodeLoc;
import com.l2jmobius.gameserver.instancemanager.MapRegionManager;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.instance.L2DoorInstance;
import com.l2jmobius.gameserver.model.actor.templates.L2DoorTemplate;
@@ -205,7 +205,7 @@ public final class DoorData implements IGameXmlReader
return _doors.values();
}
public boolean checkIfDoorsBetween(AbstractNodeLoc start, AbstractNodeLoc end, Instance instance)
public boolean checkIfDoorsBetween(Location start, Location end, Instance instance)
{
return checkIfDoorsBetween(start.getX(), start.getY(), start.getZ(), end.getX(), end.getY(), end.getZ(), instance);
}

View File

@@ -1,626 +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.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.data.xml.impl.DoorData;
import com.l2jmobius.gameserver.geodata.geodriver.Cell;
import com.l2jmobius.gameserver.geodata.geodriver.GeoDriver;
import com.l2jmobius.gameserver.instancemanager.WarpedSpaceManager;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.instancezone.Instance;
import com.l2jmobius.gameserver.model.interfaces.ILocational;
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.isDoor())
{
// can always see doors :o
return true;
}
return canSeeTarget(cha.getX(), cha.getY(), cha.getZ(), cha.getInstanceWorld(), target.getX(), target.getY(), target.getZ(), target.getInstanceWorld());
}
/**
* Can see target. Checks doors between.
* @param cha the character
* @param worldPosition the world position
* @return {@code true} if the character can see the target at the given world position, {@code false} otherwise
*/
public boolean canSeeTarget(L2Object cha, ILocational worldPosition)
{
return canSeeTarget(cha.getX(), cha.getY(), cha.getZ(), cha.getInstanceWorld(), worldPosition.getX(), worldPosition.getY(), worldPosition.getZ());
}
/**
* Can see target. Checks doors between.
* @param x the x coordinate
* @param y the y coordinate
* @param z the z coordinate
* @param world
* @param tx the target's x coordinate
* @param ty the target's y coordinate
* @param tz the target's z coordinate
* @param tworld the target's instanceId
* @return
*/
public boolean canSeeTarget(int x, int y, int z, Instance world, int tx, int ty, int tz, Instance tworld)
{
return (world != tworld) ? false : canSeeTarget(x, y, z, world, tx, ty, tz);
}
/**
* Can see target. Checks doors between.
* @param x the x coordinate
* @param y the y coordinate
* @param z the z coordinate
* @param instance
* @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, Instance instance, int tx, int ty, int tz)
{
if (DoorData.getInstance().checkIfDoorsBetween(x, y, z, tx, ty, tz, instance, true))
{
return false;
}
return canSeeTarget(x, y, z, tx, ty, tz);
}
private int getLosGeoZ(int prevX, int prevY, int prevGeoZ, int curX, int curY, int nswe)
{
if ((((nswe & Cell.NSWE_NORTH) != 0) && ((nswe & Cell.NSWE_SOUTH) != 0)) || (((nswe & Cell.NSWE_WEST) != 0) && ((nswe & Cell.NSWE_EAST) != 0)))
{
throw new RuntimeException("Multiple directions!");
}
if (checkNearestNsweAntiCornerCut(prevX, prevY, prevGeoZ, nswe))
{
return getNearestZ(curX, curY, prevGeoZ);
}
return getNextHigherZ(curX, curY, prevGeoZ);
}
/**
* Can see target. Does not check doors between.
* @param x the x coordinate
* @param y the y coordinate
* @param z the z coordinate
* @param tx the target's x coordinate
* @param ty the target's y coordinate
* @param tz the target's z coordinate
* @return {@code true} if there is line of sight between the given coordinate sets, {@code false} otherwise
*/
public boolean canSeeTarget(int x, int y, int z, int tx, int ty, int tz)
{
int geoX = getGeoX(x);
int geoY = getGeoY(y);
int tGeoX = getGeoX(tx);
int tGeoY = getGeoY(ty);
z = getNearestZ(geoX, geoY, z);
tz = getNearestZ(tGeoX, tGeoY, tz);
// fastpath
if ((geoX == tGeoX) && (geoY == tGeoY))
{
if (hasGeoPos(tGeoX, tGeoY))
{
return z == tz;
}
return true;
}
if (tz > z)
{
int tmp = tx;
tx = x;
x = tmp;
tmp = ty;
ty = y;
y = tmp;
tmp = tz;
tz = z;
z = tmp;
tmp = tGeoX;
tGeoX = geoX;
geoX = tmp;
tmp = tGeoY;
tGeoY = geoY;
geoY = tmp;
}
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
* @param instance the instance
* @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, Instance instance)
{
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 (DoorData.getInstance().checkIfDoorsBetween(x, y, z, tx, ty, tz, instance, false))
{
return new Location(x, y, getHeight(x, y, z));
}
if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(x, y, z), new Location(tx, ty, tz), instance))
{
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);
}
public Location moveCheck(Location startLoc, Location endLoc, Instance instance)
{
return moveCheck(startLoc.getX(), startLoc.getY(), startLoc.getZ(), endLoc.getX(), endLoc.getY(), endLoc.getZ(), instance);
}
/**
* Checks if its possible to move from one location to another.
* @param fromX the X coordinate to start checking from
* @param fromY the Y coordinate to start checking from
* @param fromZ the Z coordinate to start checking from
* @param toX the X coordinate to end checking at
* @param toY the Y coordinate to end checking at
* @param toZ the Z coordinate to end checking at
* @param instance the instance
* @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, Instance instance)
{
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 (DoorData.getInstance().checkIfDoorsBetween(fromX, fromY, fromZ, toX, toY, toZ, instance, false))
{
return false;
}
if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(fromX, fromY, fromZ), new Location(toX, toY, toZ), instance))
{
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, from.getInstanceWorld());
}
/**
* 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

@@ -1,48 +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.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

@@ -1,189 +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.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

@@ -1,47 +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.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

@@ -1,79 +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.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

@@ -1,58 +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.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

@@ -1,186 +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.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

@@ -1,57 +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.geodata.geodriver.regions;
import com.l2jmobius.gameserver.geodata.geodriver.IRegion;
/**
* @author HorridoJoho
*/
public final class NullRegion implements IRegion
{
public static final NullRegion INSTANCE = new NullRegion();
@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 worldZ;
}
@Override
public int getNextLowerZ(int geoX, int geoY, int worldZ)
{
return worldZ;
}
@Override
public int getNextHigherZ(int geoX, int geoY, int worldZ)
{
return worldZ;
}
@Override
public boolean hasGeo()
{
return false;
}
}

View File

@@ -1,98 +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.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,87 +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.geodata.pathfinding;
public abstract class AbstractNode<T extends AbstractNodeLoc>
{
private T _loc;
private AbstractNode<T> _parent;
public AbstractNode(T loc)
{
_loc = loc;
}
public void setParent(AbstractNode<T> p)
{
_parent = p;
}
public AbstractNode<T> getParent()
{
return _parent;
}
public T getLoc()
{
return _loc;
}
public void setLoc(T l)
{
_loc = l;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = (prime * result) + ((_loc == null) ? 0 : _loc.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
if (obj == null)
{
return false;
}
if (!(obj instanceof AbstractNode))
{
return false;
}
final AbstractNode<?> other = (AbstractNode<?>) obj;
if (_loc == null)
{
if (other._loc != null)
{
return false;
}
}
else if (!_loc.equals(other._loc))
{
return false;
}
return true;
}
}

View File

@@ -1,211 +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.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;
import com.l2jmobius.gameserver.model.instancezone.Instance;
/**
* @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, Instance instance, 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,69 +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.geodata.pathfinding.cellnodes;
import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNode;
public class CellNode extends AbstractNode<NodeLoc>
{
private CellNode _next = null;
private boolean _isInUse = true;
private float _cost = -1000;
public CellNode(NodeLoc loc)
{
super(loc);
}
public boolean isInUse()
{
return _isInUse;
}
public void setInUse()
{
_isInUse = true;
}
public CellNode getNext()
{
return _next;
}
public void setNext(CellNode next)
{
_next = next;
}
public float getCost()
{
return _cost;
}
public void setCost(double cost)
{
_cost = (float) cost;
}
public void free()
{
setParent(null);
_cost = -1000;
_isInUse = false;
_next = null;
}
}

View File

@@ -1,361 +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.geodata.pathfinding.cellnodes;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import com.l2jmobius.Config;
/**
* @author DS Credits to Diamond
*/
public class CellNodeBuffer
{
private static final int MAX_ITERATIONS = 3500;
private final ReentrantLock _lock = new ReentrantLock();
private final int _mapSize;
private final CellNode[][] _buffer;
private int _baseX = 0;
private int _baseY = 0;
private int _targetX = 0;
private int _targetY = 0;
private int _targetZ = 0;
private long _timeStamp = 0;
private long _lastElapsedTime = 0;
private CellNode _current = null;
public CellNodeBuffer(int size)
{
_mapSize = size;
_buffer = new CellNode[_mapSize][_mapSize];
}
public final boolean lock()
{
return _lock.tryLock();
}
public final CellNode findPath(int x, int y, int z, int tx, int ty, int tz)
{
_timeStamp = System.currentTimeMillis();
_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
_targetX = tx;
_targetY = ty;
_targetZ = tz;
_current = getNode(x, y, z);
_current.setCost(getCost(x, y, z, Config.HIGH_WEIGHT));
for (int count = 0; count < MAX_ITERATIONS; count++)
{
if ((_current.getLoc().getNodeX() == _targetX) && (_current.getLoc().getNodeY() == _targetY) && (Math.abs(_current.getLoc().getZ() - _targetZ) < 64))
{
return _current; // found
}
getNeighbors();
if (_current.getNext() == null)
{
return null; // no more ways
}
_current = _current.getNext();
}
return null;
}
public final void free()
{
_current = null;
CellNode node;
for (int i = 0; i < _mapSize; i++)
{
for (int j = 0; j < _mapSize; j++)
{
node = _buffer[i][j];
if (node != null)
{
node.free();
}
}
}
_lock.unlock();
_lastElapsedTime = System.currentTimeMillis() - _timeStamp;
}
public final long getElapsedTime()
{
return _lastElapsedTime;
}
public final List<CellNode> debugPath()
{
final List<CellNode> result = new LinkedList<>();
for (CellNode n = _current; n.getParent() != null; n = (CellNode) n.getParent())
{
result.add(n);
n.setCost(-n.getCost());
}
for (int i = 0; i < _mapSize; i++)
{
for (int j = 0; j < _mapSize; j++)
{
final CellNode n = _buffer[i][j];
if ((n == null) || !n.isInUse() || (n.getCost() <= 0))
{
continue;
}
result.add(n);
}
}
return result;
}
private void getNeighbors()
{
if (!_current.getLoc().canGoAll())
{
return;
}
final int x = _current.getLoc().getNodeX();
final int y = _current.getLoc().getNodeY();
final int z = _current.getLoc().getZ();
CellNode nodeE = null;
CellNode nodeS = null;
CellNode nodeW = null;
CellNode nodeN = null;
// East
if (_current.getLoc().canGoEast())
{
nodeE = addNode(x + 1, y, z, false);
}
// South
if (_current.getLoc().canGoSouth())
{
nodeS = addNode(x, y + 1, z, false);
}
// West
if (_current.getLoc().canGoWest())
{
nodeW = addNode(x - 1, y, z, false);
}
// North
if (_current.getLoc().canGoNorth())
{
nodeN = addNode(x, y - 1, z, false);
}
if (Config.ADVANCED_DIAGONAL_STRATEGY)
{
// SouthEast
if ((nodeE != null) && (nodeS != null))
{
if (nodeE.getLoc().canGoSouth() && nodeS.getLoc().canGoEast())
{
addNode(x + 1, y + 1, z, true);
}
}
// SouthWest
if ((nodeS != null) && (nodeW != null))
{
if (nodeW.getLoc().canGoSouth() && nodeS.getLoc().canGoWest())
{
addNode(x - 1, y + 1, z, true);
}
}
// NorthEast
if ((nodeN != null) && (nodeE != null))
{
if (nodeE.getLoc().canGoNorth() && nodeN.getLoc().canGoEast())
{
addNode(x + 1, y - 1, z, true);
}
}
// NorthWest
if ((nodeN != null) && (nodeW != null))
{
if (nodeW.getLoc().canGoNorth() && nodeN.getLoc().canGoWest())
{
addNode(x - 1, y - 1, z, true);
}
}
}
}
private CellNode getNode(int x, int y, int z)
{
final int aX = x - _baseX;
if ((aX < 0) || (aX >= _mapSize))
{
return null;
}
final int aY = y - _baseY;
if ((aY < 0) || (aY >= _mapSize))
{
return null;
}
CellNode result = _buffer[aX][aY];
if (result == null)
{
result = new CellNode(new NodeLoc(x, y, z));
_buffer[aX][aY] = result;
}
else if (!result.isInUse())
{
result.setInUse();
// reinit node if needed
if (result.getLoc() != null)
{
result.getLoc().set(x, y, z);
}
else
{
result.setLoc(new NodeLoc(x, y, z));
}
}
return result;
}
private CellNode addNode(int x, int y, int z, boolean diagonal)
{
final CellNode newNode = getNode(x, y, z);
if (newNode == null)
{
return null;
}
if (newNode.getCost() >= 0)
{
return newNode;
}
final int geoZ = newNode.getLoc().getZ();
final int stepZ = Math.abs(geoZ - _current.getLoc().getZ());
float weight = diagonal ? Config.DIAGONAL_WEIGHT : Config.LOW_WEIGHT;
if (!newNode.getLoc().canGoAll() || (stepZ > 16))
{
weight = Config.HIGH_WEIGHT;
}
else if (isHighWeight(x + 1, y, geoZ))
{
weight = Config.MEDIUM_WEIGHT;
}
else if (isHighWeight(x - 1, y, geoZ))
{
weight = Config.MEDIUM_WEIGHT;
}
else if (isHighWeight(x, y + 1, geoZ))
{
weight = Config.MEDIUM_WEIGHT;
}
else if (isHighWeight(x, y - 1, geoZ))
{
weight = Config.MEDIUM_WEIGHT;
}
newNode.setParent(_current);
newNode.setCost(getCost(x, y, geoZ, weight));
CellNode node = _current;
int count = 0;
while ((node.getNext() != null) && (count < (MAX_ITERATIONS * 4)))
{
count++;
if (node.getNext().getCost() > newNode.getCost())
{
// insert node into a chain
newNode.setNext(node.getNext());
break;
}
node = node.getNext();
}
if (count == (MAX_ITERATIONS * 4))
{
System.err.println("Pathfinding: too long loop detected, cost:" + newNode.getCost());
}
node.setNext(newNode); // add last
return newNode;
}
private boolean isHighWeight(int x, int y, int z)
{
final CellNode result = getNode(x, y, z);
if (result == null)
{
return true;
}
if (!result.getLoc().canGoAll())
{
return true;
}
if (Math.abs(result.getLoc().getZ() - z) > 16)
{
return true;
}
return false;
}
private double getCost(int x, int y, int z, float weight)
{
final int dX = x - _targetX;
final int dY = y - _targetY;
final int dZ = z - _targetZ;
// Math.abs(dx) + Math.abs(dy) + Math.abs(dz) / 16
double result = Math.sqrt((dX * dX) + (dY * dY) + ((dZ * dZ) / 256.0));
if (result > weight)
{
result += weight;
}
if (result > Float.MAX_VALUE)
{
result = Float.MAX_VALUE;
}
return result;
}
}

View File

@@ -1,440 +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.geodata.pathfinding.cellnodes;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNode;
import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNodeLoc;
import com.l2jmobius.gameserver.geodata.pathfinding.PathFinding;
import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.model.instancezone.Instance;
import com.l2jmobius.gameserver.model.itemcontainer.Inventory;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
/**
* @author Sami, DS Credits to Diamond
*/
public class CellPathFinding extends PathFinding
{
private static final Logger _log = Logger.getLogger(CellPathFinding.class.getName());
private BufferInfo[] _allBuffers;
private int _findSuccess = 0;
private int _findFails = 0;
private int _postFilterUses = 0;
private int _postFilterPlayableUses = 0;
private int _postFilterPasses = 0;
private long _postFilterElapsed = 0;
private List<L2ItemInstance> _debugItems = null;
public static CellPathFinding getInstance()
{
return SingletonHolder._instance;
}
protected CellPathFinding()
{
try
{
final String[] array = Config.PATHFIND_BUFFERS.split(";");
_allBuffers = new BufferInfo[array.length];
String buf;
String[] args;
for (int i = 0; i < array.length; i++)
{
buf = array[i];
args = buf.split("x");
if (args.length != 2)
{
throw new Exception("Invalid buffer definition: " + buf);
}
_allBuffers[i] = new BufferInfo(Integer.parseInt(args[0]), Integer.parseInt(args[1]));
}
}
catch (Exception e)
{
_log.log(Level.WARNING, "CellPathFinding: Problem during buffer init: " + e.getMessage(), e);
throw new Error("CellPathFinding: load aborted");
}
}
@Override
public boolean pathNodesExist(short regionoffset)
{
return false;
}
@Override
public List<AbstractNodeLoc> findPath(int x, int y, int z, int tx, int ty, int tz, Instance instance, boolean playable)
{
final int gx = GeoData.getInstance().getGeoX(x);
final int gy = GeoData.getInstance().getGeoY(y);
if (!GeoData.getInstance().hasGeo(x, y))
{
return null;
}
final int gz = GeoData.getInstance().getHeight(x, y, z);
final int gtx = GeoData.getInstance().getGeoX(tx);
final int gty = GeoData.getInstance().getGeoY(ty);
if (!GeoData.getInstance().hasGeo(tx, ty))
{
return null;
}
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 (buffer == null)
{
return null;
}
final boolean debug = playable && Config.DEBUG_PATH;
if (debug)
{
if (_debugItems == null)
{
_debugItems = new CopyOnWriteArrayList<>();
}
else
{
for (L2ItemInstance item : _debugItems)
{
if (item == null)
{
continue;
}
item.decayMe();
}
_debugItems.clear();
}
}
List<AbstractNodeLoc> path = null;
try
{
final CellNode result = buffer.findPath(gx, gy, gz, gtx, gty, gtz);
if (debug)
{
for (CellNode n : buffer.debugPath())
{
if (n.getCost() < 0)
{
dropDebugItem(1831, (int) (-n.getCost() * 10), n.getLoc());
}
else
{
// known nodes
dropDebugItem(Inventory.ADENA_ID, (int) (n.getCost() * 10), n.getLoc());
}
}
}
if (result == null)
{
_findFails++;
return null;
}
path = constructPath(result);
}
catch (Exception e)
{
_log.log(Level.WARNING, "", e);
return null;
}
finally
{
buffer.free();
}
if ((path.size() < 3) || (Config.MAX_POSTFILTER_PASSES <= 0))
{
_findSuccess++;
return path;
}
final long timeStamp = System.currentTimeMillis();
_postFilterUses++;
if (playable)
{
_postFilterPlayableUses++;
}
int currentX, currentY, currentZ;
ListIterator<AbstractNodeLoc> middlePoint;
boolean remove;
int pass = 0;
do
{
pass++;
_postFilterPasses++;
remove = false;
middlePoint = path.listIterator();
currentX = x;
currentY = y;
currentZ = z;
while (middlePoint.hasNext())
{
final AbstractNodeLoc locMiddle = middlePoint.next();
if (!middlePoint.hasNext())
{
break;
}
final AbstractNodeLoc locEnd = path.get(middlePoint.nextIndex());
if (GeoData.getInstance().canMove(currentX, currentY, currentZ, locEnd.getX(), locEnd.getY(), locEnd.getZ(), instance))
{
middlePoint.remove();
remove = true;
if (debug)
{
dropDebugItem(735, 1, locMiddle);
}
}
else
{
currentX = locMiddle.getX();
currentY = locMiddle.getY();
currentZ = locMiddle.getZ();
}
}
}
// only one postfilter pass for AI
while (playable && remove && (path.size() > 2) && (pass < Config.MAX_POSTFILTER_PASSES));
if (debug)
{
path.forEach(n -> dropDebugItem(65, 1, n));
}
_findSuccess++;
_postFilterElapsed += System.currentTimeMillis() - timeStamp;
return path;
}
private List<AbstractNodeLoc> constructPath(AbstractNode<NodeLoc> node)
{
final LinkedList<AbstractNodeLoc> path = new LinkedList<>();
int previousDirectionX = Integer.MIN_VALUE;
int previousDirectionY = Integer.MIN_VALUE;
int directionX, directionY;
while (node.getParent() != null)
{
if (!Config.ADVANCED_DIAGONAL_STRATEGY && (node.getParent().getParent() != null))
{
final int tmpX = node.getLoc().getNodeX() - node.getParent().getParent().getLoc().getNodeX();
final int tmpY = node.getLoc().getNodeY() - node.getParent().getParent().getLoc().getNodeY();
if (Math.abs(tmpX) == Math.abs(tmpY))
{
directionX = tmpX;
directionY = tmpY;
}
else
{
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();
directionY = node.getLoc().getNodeY() - node.getParent().getLoc().getNodeY();
}
// only add a new route point if moving direction changes
if ((directionX != previousDirectionX) || (directionY != previousDirectionY))
{
previousDirectionX = directionX;
previousDirectionY = directionY;
path.addFirst(node.getLoc());
node.setLoc(null);
}
node = node.getParent();
}
return path;
}
private CellNodeBuffer alloc(int size, boolean playable)
{
CellNodeBuffer current = null;
for (BufferInfo i : _allBuffers)
{
if (i.mapSize >= size)
{
for (CellNodeBuffer buf : i.bufs)
{
if (buf.lock())
{
i.uses++;
if (playable)
{
i.playableUses++;
}
i.elapsed += buf.getElapsedTime();
current = buf;
break;
}
}
if (current != null)
{
break;
}
// not found, allocate temporary buffer
current = new CellNodeBuffer(i.mapSize);
current.lock();
if (i.bufs.size() < i.count)
{
i.bufs.add(current);
i.uses++;
if (playable)
{
i.playableUses++;
}
break;
}
i.overflows++;
if (playable)
{
i.playableOverflows++;
// System.err.println("Overflow, size requested: " + size + " playable:"+playable);
}
}
}
return current;
}
private void dropDebugItem(int itemId, int num, AbstractNodeLoc loc)
{
final L2ItemInstance item = new L2ItemInstance(IdFactory.getInstance().getNextId(), itemId);
item.setCount(num);
item.spawnMe(loc.getX(), loc.getY(), loc.getZ());
_debugItems.add(item);
}
private static final class BufferInfo
{
final int mapSize;
final int count;
ArrayList<CellNodeBuffer> bufs;
int uses = 0;
int playableUses = 0;
int overflows = 0;
int playableOverflows = 0;
long elapsed = 0;
public BufferInfo(int size, int cnt)
{
mapSize = size;
count = cnt;
bufs = new ArrayList<>(count);
}
@Override
public String toString()
{
final StringBuilder sb = new StringBuilder(100);
sb.append(mapSize);
sb.append("x");
sb.append(mapSize);
sb.append(" num:");
sb.append(bufs.size());
sb.append("/");
sb.append(count);
sb.append(" uses:");
sb.append(uses);
sb.append("/");
sb.append(playableUses);
if (uses > 0)
{
sb.append(" total/avg(ms):");
sb.append(elapsed);
sb.append("/");
sb.append(String.format("%1.2f", (double) elapsed / uses));
}
sb.append(" ovf:");
sb.append(overflows);
sb.append("/");
sb.append(playableOverflows);
return sb.toString();
}
}
@Override
public String[] getStat()
{
final String[] result = new String[_allBuffers.length + 1];
for (int i = 0; i < _allBuffers.length; i++)
{
result[i] = _allBuffers[i].toString();
}
final StringBuilder sb = new StringBuilder(128);
sb.append("LOS postfilter uses:");
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,184 +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.geodata.pathfinding.cellnodes;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geodata.geodriver.Cell;
import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNodeLoc;
/**
* @author -Nemesiss-, HorridoJoho
*/
public class NodeLoc extends AbstractNodeLoc
{
private int _x;
private int _y;
private boolean _goNorth;
private boolean _goEast;
private boolean _goSouth;
private boolean _goWest;
private int _geoHeight;
public NodeLoc(int x, int y, int z)
{
set(x, y, z);
}
public void set(int x, int y, int z)
{
_x = x;
_y = y;
_goNorth = GeoData.getInstance().checkNearestNswe(x, y, z, Cell.NSWE_NORTH);
_goEast = GeoData.getInstance().checkNearestNswe(x, y, z, Cell.NSWE_EAST);
_goSouth = GeoData.getInstance().checkNearestNswe(x, y, z, Cell.NSWE_SOUTH);
_goWest = GeoData.getInstance().checkNearestNswe(x, y, z, Cell.NSWE_WEST);
_geoHeight = GeoData.getInstance().getNearestZ(x, y, z);
}
public boolean canGoNorth()
{
return _goNorth;
}
public boolean canGoEast()
{
return _goEast;
}
public boolean canGoSouth()
{
return _goSouth;
}
public boolean canGoWest()
{
return _goWest;
}
public boolean canGoAll()
{
return canGoNorth() && canGoEast() && canGoSouth() && canGoWest();
}
@Override
public int getX()
{
return GeoData.getInstance().getWorldX(_x);
}
@Override
public int getY()
{
return GeoData.getInstance().getWorldY(_y);
}
@Override
public int getZ()
{
return _geoHeight;
}
@Override
public int getNodeX()
{
return _x;
}
@Override
public int getNodeY()
{
return _y;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = (prime * result) + _x;
result = (prime * result) + _y;
int nswe = 0;
if (canGoNorth())
{
nswe |= Cell.NSWE_NORTH;
}
if (canGoEast())
{
nswe |= Cell.NSWE_EAST;
}
if (canGoSouth())
{
nswe |= Cell.NSWE_SOUTH;
}
if (canGoWest())
{
nswe |= Cell.NSWE_WEST;
}
result = (prime * result) + (((_geoHeight & 0xFFFF) << 1) | nswe);
return result;
// return super.hashCode();
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
if (obj == null)
{
return false;
}
if (!(obj instanceof NodeLoc))
{
return false;
}
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,62 +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.geodata.pathfinding.geonodes;
import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNode;
/**
* @author -Nemesiss-
*/
public class GeoNode extends AbstractNode<GeoNodeLoc>
{
private final int _neighborsIdx;
private short _cost;
private GeoNode[] _neighbors;
public GeoNode(GeoNodeLoc Loc, int Neighbors_idx)
{
super(Loc);
_neighborsIdx = Neighbors_idx;
}
public short getCost()
{
return _cost;
}
public void setCost(int cost)
{
_cost = (short) cost;
}
public GeoNode[] getNeighbors()
{
return _neighbors;
}
public void attachNeighbors()
{
if (getLoc() == null)
{
_neighbors = null;
}
else
{
_neighbors = GeoPathFinding.getInstance().readNeighbors(this, _neighborsIdx);
}
}
}

View File

@@ -1,109 +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.geodata.pathfinding.geonodes;
import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNodeLoc;
import com.l2jmobius.gameserver.model.L2World;
/**
* @author -Nemesiss-
*/
public class GeoNodeLoc extends AbstractNodeLoc
{
private final short _x;
private final short _y;
private final short _z;
public GeoNodeLoc(short x, short y, short z)
{
_x = x;
_y = y;
_z = z;
}
@Override
public int getX()
{
return L2World.MAP_MIN_X + (_x * 128) + 48;
}
@Override
public int getY()
{
return L2World.MAP_MIN_Y + (_y * 128) + 48;
}
@Override
public int getZ()
{
return _z;
}
@Override
public int getNodeX()
{
return _x;
}
@Override
public int getNodeY()
{
return _y;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = (prime * result) + _x;
result = (prime * result) + _y;
result = (prime * result) + _z;
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
if (obj == null)
{
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 +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.geodata.pathfinding.geonodes;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNode;
import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNodeLoc;
import com.l2jmobius.gameserver.geodata.pathfinding.PathFinding;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.instancezone.Instance;
import com.l2jmobius.gameserver.util.Util;
/**
* @author -Nemesiss-
*/
public class GeoPathFinding extends PathFinding
{
private static Logger _log = Logger.getLogger(GeoPathFinding.class.getName());
private static Map<Short, ByteBuffer> _pathNodes = new ConcurrentHashMap<>();
private static Map<Short, IntBuffer> _pathNodesIndex = new ConcurrentHashMap<>();
public static GeoPathFinding getInstance()
{
return SingletonHolder._instance;
}
@Override
public boolean pathNodesExist(short regionoffset)
{
return _pathNodesIndex.containsKey(regionoffset);
}
@Override
public List<AbstractNodeLoc> findPath(int x, int y, int z, int tx, int ty, int tz, Instance instance, boolean playable)
{
final int gx = (x - L2World.MAP_MIN_X) >> 4;
final int gy = (y - L2World.MAP_MIN_Y) >> 4;
final short gz = (short) z;
final int gtx = (tx - L2World.MAP_MIN_X) >> 4;
final int gty = (ty - L2World.MAP_MIN_Y) >> 4;
final short gtz = (short) tz;
final GeoNode start = readNode(gx, gy, gz);
final GeoNode end = readNode(gtx, gty, gtz);
if ((start == null) || (end == null))
{
return null;
}
if (Math.abs(start.getLoc().getZ() - z) > 55)
{
return null; // not correct layer
}
if (Math.abs(end.getLoc().getZ() - tz) > 55)
{
return null; // not correct layer
}
if (start == end)
{
return null;
}
// TODO: Find closest path node we CAN access. Now only checks if we can not reach the closest
Location temp = GeoData.getInstance().moveCheck(x, y, z, start.getLoc().getX(), start.getLoc().getY(), start.getLoc().getZ(), instance);
if ((temp.getX() != start.getLoc().getX()) || (temp.getY() != start.getLoc().getY()))
{
return null; // cannot reach closest...
}
// TODO: Find closest path node around target, now only checks if final location can be reached
temp = GeoData.getInstance().moveCheck(tx, ty, tz, end.getLoc().getX(), end.getLoc().getY(), end.getLoc().getZ(), instance);
if ((temp.getX() != end.getLoc().getX()) || (temp.getY() != end.getLoc().getY()))
{
return null; // cannot reach closest...
}
// return searchAStar(start, end);
return searchByClosest2(start, end);
}
public List<AbstractNodeLoc> searchByClosest2(GeoNode start, GeoNode 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
// and accurate. And can reach insane distances (try it with 800 nodes..).
// Minimum required node count would be around 300-400.
// Generally returns a bit (only a bit) more intelligent looking routes than
// the basic version. Not a true distance image (which would increase CPU
// load) level of intelligence though.
// List of Visited Nodes
final List<GeoNode> visited = new ArrayList<>(550);
// List of Nodes to Visit
final LinkedList<GeoNode> to_visit = new LinkedList<>();
to_visit.add(start);
final int targetX = end.getLoc().getNodeX();
final int targetY = end.getLoc().getNodeY();
int dx, dy;
boolean added;
int i = 0;
while (i < 550)
{
GeoNode node;
try
{
node = to_visit.removeFirst();
}
catch (Exception e)
{
// No Path found
return null;
}
if (node.equals(end))
{
return constructPath2(node);
}
i++;
visited.add(node);
node.attachNeighbors();
final GeoNode[] neighbors = node.getNeighbors();
if (neighbors == null)
{
continue;
}
for (GeoNode n : neighbors)
{
if ((visited.lastIndexOf(n) == -1) && !to_visit.contains(n))
{
added = false;
n.setParent(node);
dx = targetX - n.getLoc().getNodeX();
dy = targetY - n.getLoc().getNodeY();
n.setCost((dx * dx) + (dy * dy));
for (int index = 0; index < to_visit.size(); index++)
{
// supposed to find it quite early..
if (to_visit.get(index).getCost() > n.getCost())
{
to_visit.add(index, n);
added = true;
break;
}
}
if (!added)
{
to_visit.addLast(n);
}
}
}
}
// No Path found
return null;
}
public List<AbstractNodeLoc> constructPath2(AbstractNode<GeoNodeLoc> node)
{
final LinkedList<AbstractNodeLoc> path = new LinkedList<>();
int previousDirectionX = -1000;
int previousDirectionY = -1000;
int directionX;
int directionY;
while (node.getParent() != null)
{
// only add a new route point if moving direction changes
directionX = node.getLoc().getNodeX() - node.getParent().getLoc().getNodeX();
directionY = node.getLoc().getNodeY() - node.getParent().getLoc().getNodeY();
if ((directionX != previousDirectionX) || (directionY != previousDirectionY))
{
previousDirectionX = directionX;
previousDirectionY = directionY;
path.addFirst(node.getLoc());
}
node = node.getParent();
}
return path;
}
public GeoNode[] readNeighbors(GeoNode n, int idx)
{
final int node_x = n.getLoc().getNodeX();
final int node_y = n.getLoc().getNodeY();
// short node_z = n.getLoc().getZ();
final short regoffset = getRegionOffset(getRegionX(node_x), getRegionY(node_y));
final ByteBuffer pn = _pathNodes.get(regoffset);
final List<AbstractNode<GeoNodeLoc>> Neighbors = new ArrayList<>(8);
GeoNode newNode;
short new_node_x, new_node_y;
// Region for sure will change, we must read from correct file
byte neighbor = pn.get(idx++); // N
if (neighbor > 0)
{
neighbor--;
new_node_x = (short) node_x;
new_node_y = (short) (node_y - 1);
newNode = readNode(new_node_x, new_node_y, neighbor);
if (newNode != null)
{
Neighbors.add(newNode);
}
}
neighbor = pn.get(idx++); // NE
if (neighbor > 0)
{
neighbor--;
new_node_x = (short) (node_x + 1);
new_node_y = (short) (node_y - 1);
newNode = readNode(new_node_x, new_node_y, neighbor);
if (newNode != null)
{
Neighbors.add(newNode);
}
}
neighbor = pn.get(idx++); // E
if (neighbor > 0)
{
neighbor--;
new_node_x = (short) (node_x + 1);
new_node_y = (short) node_y;
newNode = readNode(new_node_x, new_node_y, neighbor);
if (newNode != null)
{
Neighbors.add(newNode);
}
}
neighbor = pn.get(idx++); // SE
if (neighbor > 0)
{
neighbor--;
new_node_x = (short) (node_x + 1);
new_node_y = (short) (node_y + 1);
newNode = readNode(new_node_x, new_node_y, neighbor);
if (newNode != null)
{
Neighbors.add(newNode);
}
}
neighbor = pn.get(idx++); // S
if (neighbor > 0)
{
neighbor--;
new_node_x = (short) node_x;
new_node_y = (short) (node_y + 1);
newNode = readNode(new_node_x, new_node_y, neighbor);
if (newNode != null)
{
Neighbors.add(newNode);
}
}
neighbor = pn.get(idx++); // SW
if (neighbor > 0)
{
neighbor--;
new_node_x = (short) (node_x - 1);
new_node_y = (short) (node_y + 1);
newNode = readNode(new_node_x, new_node_y, neighbor);
if (newNode != null)
{
Neighbors.add(newNode);
}
}
neighbor = pn.get(idx++); // W
if (neighbor > 0)
{
neighbor--;
new_node_x = (short) (node_x - 1);
new_node_y = (short) node_y;
newNode = readNode(new_node_x, new_node_y, neighbor);
if (newNode != null)
{
Neighbors.add(newNode);
}
}
neighbor = pn.get(idx++); // NW
if (neighbor > 0)
{
neighbor--;
new_node_x = (short) (node_x - 1);
new_node_y = (short) (node_y - 1);
newNode = readNode(new_node_x, new_node_y, neighbor);
if (newNode != null)
{
Neighbors.add(newNode);
}
}
final GeoNode[] result = new GeoNode[Neighbors.size()];
return Neighbors.toArray(result);
}
// Private
private GeoNode readNode(short node_x, short node_y, byte layer)
{
final short regoffset = getRegionOffset(getRegionX(node_x), getRegionY(node_y));
if (!pathNodesExist(regoffset))
{
return null;
}
final short nbx = getNodeBlock(node_x);
final short nby = getNodeBlock(node_y);
int idx = _pathNodesIndex.get(regoffset).get((nby << 8) + nbx);
final ByteBuffer pn = _pathNodes.get(regoffset);
// reading
final byte nodes = pn.get(idx);
idx += (layer * 10) + 1; // byte + layer*10byte
if (nodes < layer)
{
_log.warning("SmthWrong!");
}
final short node_z = pn.getShort(idx);
idx += 2;
return new GeoNode(new GeoNodeLoc(node_x, node_y, node_z), idx);
}
private GeoNode readNode(int gx, int gy, short z)
{
final short node_x = getNodePos(gx);
final short node_y = getNodePos(gy);
final short regoffset = getRegionOffset(getRegionX(node_x), getRegionY(node_y));
if (!pathNodesExist(regoffset))
{
return null;
}
final short nbx = getNodeBlock(node_x);
final short nby = getNodeBlock(node_y);
int idx = _pathNodesIndex.get(regoffset).get((nby << 8) + nbx);
final ByteBuffer pn = _pathNodes.get(regoffset);
// reading
byte nodes = pn.get(idx++);
int idx2 = 0; // create index to nearlest node by z
short last_z = Short.MIN_VALUE;
while (nodes > 0)
{
final short node_z = pn.getShort(idx);
if (Math.abs(last_z - z) > Math.abs(node_z - z))
{
last_z = node_z;
idx2 = idx + 2;
}
idx += 10; // short + 8 byte
nodes--;
}
return new GeoNode(new GeoNodeLoc(node_x, node_y, last_z), idx2);
}
protected GeoPathFinding()
{
try
{
_log.info("Path Engine: - Loading Path Nodes...");
//@formatter:off
Files.lines(Paths.get(Config.PATHNODE_DIR.getPath(), "pn_index.txt"), StandardCharsets.UTF_8)
.map(String::trim)
.filter(l -> !l.isEmpty())
.forEach(line -> {
final String[] parts = line.split("_");
if ((parts.length < 2)
|| !Util.isDigit(parts[0])
|| !Util.isDigit(parts[1]))
{
_log.warning("Invalid pathnode entry: '" + line + "', must be in format 'XX_YY', where X and Y - integers");
return;
}
final byte rx = Byte.parseByte(parts[0]);
final byte ry = Byte.parseByte(parts[1]);
LoadPathNodeFile(rx, ry);
});
//@formatter:on
}
catch (IOException e)
{
_log.log(Level.WARNING, "", e);
throw new Error("Failed to read pn_index file.");
}
}
private void LoadPathNodeFile(byte rx, byte ry)
{
if ((rx < L2World.TILE_X_MIN) || (rx > L2World.TILE_X_MAX) || (ry < L2World.TILE_Y_MIN) || (ry > L2World.TILE_Y_MAX))
{
_log.warning("Failed to Load PathNode File: invalid region " + rx + "," + ry + Config.EOL);
return;
}
final short regionoffset = getRegionOffset(rx, ry);
final File file = new File(Config.PATHNODE_DIR, rx + "_" + ry + ".pn");
_log.info("Path Engine: - Loading: " + file.getName() + " -> region offset: " + regionoffset + " X: " + rx + " Y: " + ry);
int node = 0, size, index = 0;
// Create a read-only memory-mapped file
try (RandomAccessFile raf = new RandomAccessFile(file, "r");
FileChannel roChannel = raf.getChannel())
{
size = (int) roChannel.size();
MappedByteBuffer nodes;
if (Config.FORCE_GEODATA)
{
// it is not guarantee, because the underlying operating system may have paged out some of the buffer's data
nodes = roChannel.map(FileChannel.MapMode.READ_ONLY, 0, size).load();
}
else
{
nodes = roChannel.map(FileChannel.MapMode.READ_ONLY, 0, size);
}
// Indexing pathnode files, so we will know where each block starts
final IntBuffer indexs = IntBuffer.allocate(65536);
while (node < 65536)
{
final byte layer = nodes.get(index);
indexs.put(node++, index);
index += (layer * 10) + 1;
}
_pathNodesIndex.put(regionoffset, indexs);
_pathNodes.put(regionoffset, nodes);
}
catch (Exception e)
{
_log.log(Level.WARNING, "Failed to Load PathNode File: " + file.getAbsolutePath() + " : " + e.getMessage(), e);
}
}
private static class SingletonHolder
{
protected static final GeoPathFinding _instance = new GeoPathFinding();
}
}

View File

@@ -1,124 +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.geodata.pathfinding.utils;
import com.l2jmobius.gameserver.geodata.pathfinding.geonodes.GeoNode;
/**
* @author -Nemesiss-
*/
public class BinaryNodeHeap
{
private final GeoNode[] _list;
private int _size;
public BinaryNodeHeap(int size)
{
_list = new GeoNode[size + 1];
_size = 0;
}
public void add(GeoNode n)
{
_size++;
int pos = _size;
_list[pos] = n;
while (pos != 1)
{
final int p2 = pos / 2;
if (_list[pos].getCost() <= _list[p2].getCost())
{
final GeoNode temp = _list[p2];
_list[p2] = _list[pos];
_list[pos] = temp;
pos = p2;
}
else
{
break;
}
}
}
public GeoNode removeFirst()
{
final GeoNode first = _list[1];
_list[1] = _list[_size];
_list[_size] = null;
_size--;
int pos = 1;
int cpos;
int dblcpos;
GeoNode temp;
while (true)
{
cpos = pos;
dblcpos = cpos * 2;
if ((dblcpos + 1) <= _size)
{
if (_list[cpos].getCost() >= _list[dblcpos].getCost())
{
pos = dblcpos;
}
if (_list[pos].getCost() >= _list[dblcpos + 1].getCost())
{
pos = dblcpos + 1;
}
}
else if (dblcpos <= _size)
{
if (_list[cpos].getCost() >= _list[dblcpos].getCost())
{
pos = dblcpos;
}
}
if (cpos != pos)
{
temp = _list[cpos];
_list[cpos] = _list[pos];
_list[pos] = temp;
}
else
{
break;
}
}
return first;
}
public boolean contains(GeoNode n)
{
if (_size == 0)
{
return false;
}
for (int i = 1; i <= _size; i++)
{
if (_list[i].equals(n))
{
return true;
}
}
return false;
}
public boolean isEmpty()
{
return _size == 0;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,308 @@
/*
* 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.geoengine;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import com.l2jmobius.Config;
import com.l2jmobius.commons.util.StringUtil;
import com.l2jmobius.gameserver.geoengine.geodata.GeoLocation;
import com.l2jmobius.gameserver.geoengine.pathfinding.Node;
import com.l2jmobius.gameserver.geoengine.pathfinding.NodeBuffer;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.instancezone.Instance;
/**
* @author Hasha
*/
final class GeoEnginePathfinding extends GeoEngine
{
// pre-allocated buffers
private final BufferHolder[] _buffers;
protected GeoEnginePathfinding()
{
super();
String[] array = Config.PATHFIND_BUFFERS.split(";");
_buffers = new BufferHolder[array.length];
int count = 0;
for (int i = 0; i < array.length; i++)
{
String buf = array[i];
String[] args = buf.split("x");
try
{
int size = Integer.parseInt(args[1]);
count += size;
_buffers[i] = new BufferHolder(Integer.parseInt(args[0]), size);
}
catch (Exception e)
{
_log.warning("GeoEnginePathfinding: Can not load buffer setting: " + buf);
}
}
_log.info("GeoEnginePathfinding: Loaded " + count + " node buffers.");
}
@Override
public List<Location> findPath(int ox, int oy, int oz, int tx, int ty, int tz, Instance instance, boolean playable)
{
// get origin and check existing geo coords
int gox = getGeoX(ox);
int goy = getGeoY(oy);
if (!hasGeoPos(gox, goy))
{
return null;
}
short goz = getHeightNearest(gox, goy, oz);
// get target and check existing geo coords
int gtx = getGeoX(tx);
int gty = getGeoY(ty);
if (!hasGeoPos(gtx, gty))
{
return null;
}
short gtz = getHeightNearest(gtx, gty, tz);
// Prepare buffer for pathfinding calculations
NodeBuffer buffer = getBuffer(64 + (2 * Math.max(Math.abs(gox - gtx), Math.abs(goy - gty))), playable);
if (buffer == null)
{
return null;
}
// find path
List<Location> path = null;
try
{
Node result = buffer.findPath(gox, goy, goz, gtx, gty, gtz);
if (result == null)
{
return null;
}
path = constructPath(result);
}
catch (Exception e)
{
_log.warning(e.getMessage());
return null;
}
finally
{
buffer.free();
}
// check path
if (path.size() < 3)
{
return path;
}
// get path list iterator
ListIterator<Location> point = path.listIterator();
// get node A (origin)
int nodeAx = gox;
int nodeAy = goy;
short nodeAz = goz;
// get node B
GeoLocation nodeB = (GeoLocation) point.next();
// iterate thought the path to optimize it
while (point.hasNext())
{
// get node C
GeoLocation nodeC = (GeoLocation) path.get(point.nextIndex());
// check movement from node A to node C
GeoLocation loc = checkMove(nodeAx, nodeAy, nodeAz, nodeC.getGeoX(), nodeC.getGeoY(), nodeC.getZ(), instance);
if ((loc.getGeoX() == nodeC.getGeoX()) && (loc.getGeoY() == nodeC.getGeoY()))
{
// can move from node A to node C
// remove node B
point.remove();
}
else
{
// can not move from node A to node C
// set node A (node B is part of path, update A coordinates)
nodeAx = nodeB.getGeoX();
nodeAy = nodeB.getGeoY();
nodeAz = (short) nodeB.getZ();
}
// set node B
nodeB = (GeoLocation) point.next();
}
return path;
}
/**
* Create list of node locations as result of calculated buffer node tree.
* @param target : the entry point
* @return List<NodeLoc> : list of node location
*/
private static final List<Location> constructPath(Node target)
{
// create empty list
LinkedList<Location> list = new LinkedList<>();
// set direction X/Y
int dx = 0;
int dy = 0;
// get target parent
Node parent = target.getParent();
// while parent exists
while (parent != null)
{
// get parent <> target direction X/Y
final int nx = parent.getLoc().getGeoX() - target.getLoc().getGeoX();
final int ny = parent.getLoc().getGeoY() - target.getLoc().getGeoY();
// direction has changed?
if ((dx != nx) || (dy != ny))
{
// add node to the beginning of the list
list.addFirst(target.getLoc());
// update direction X/Y
dx = nx;
dy = ny;
}
// move to next node, set target and get its parent
target = parent;
parent = target.getParent();
}
// return list
return list;
}
/**
* Provides optimize selection of the buffer. When all pre-initialized buffer are locked, creates new buffer and log this situation.
* @param size : pre-calculated minimal required size
* @param playable : moving object is playable?
* @return NodeBuffer : buffer
*/
private final NodeBuffer getBuffer(int size, boolean playable)
{
NodeBuffer current = null;
for (BufferHolder holder : _buffers)
{
// Find proper size of buffer
if (holder._size < size)
{
continue;
}
// Find unlocked NodeBuffer
for (NodeBuffer buffer : holder._buffer)
{
if (!buffer.isLocked())
{
continue;
}
holder._uses++;
if (playable)
{
holder._playableUses++;
}
holder._elapsed += buffer.getElapsedTime();
return buffer;
}
// NodeBuffer not found, allocate temporary buffer
current = new NodeBuffer(holder._size);
current.isLocked();
holder._overflows++;
if (playable)
{
holder._playableOverflows++;
}
}
return current;
}
/**
* NodeBuffer container with specified size and count of separate buffers.
*/
private static final class BufferHolder
{
final int _size;
final int _count;
ArrayList<NodeBuffer> _buffer;
// statistics
int _playableUses = 0;
int _uses = 0;
int _playableOverflows = 0;
int _overflows = 0;
long _elapsed = 0;
public BufferHolder(int size, int count)
{
_size = size;
_count = count;
_buffer = new ArrayList<>(count);
for (int i = 0; i < count; i++)
{
_buffer.add(new NodeBuffer(size));
}
}
@Override
public String toString()
{
final StringBuilder sb = new StringBuilder(100);
StringUtil.append(sb, "Buffer ", String.valueOf(_size), "x", String.valueOf(_size), ": count=", String.valueOf(_count), " uses=", String.valueOf(_playableUses), "/", String.valueOf(_uses));
if (_uses > 0)
{
StringUtil.append(sb, " total/avg(ms)=", String.valueOf(_elapsed), "/", String.format("%1.2f", (double) _elapsed / _uses));
}
StringUtil.append(sb, " ovf=", String.valueOf(_playableOverflows), "/", String.valueOf(_overflows));
return sb.toString();
}
}
}

View File

@@ -0,0 +1,197 @@
/*
* 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.geoengine.geodata;
import java.io.BufferedOutputStream;
import java.io.IOException;
/**
* @author Hasha
*/
public abstract class ABlock
{
/**
* Checks the block for having geodata.
* @return boolean : True, when block has geodata (Flat, Complex, Multilayer).
*/
public abstract boolean hasGeoPos();
/**
* Returns the height of cell, which is closest to given coordinates.
* @param geoX : Cell geodata X coordinate.
* @param geoY : Cell geodata Y coordinate.
* @param worldZ : Cell world Z coordinate.
* @return short : Cell geodata Z coordinate, nearest to given coordinates.
*/
public abstract short getHeightNearest(int geoX, int geoY, int worldZ);
/**
* Returns the height of cell, which is closest to given coordinates.<br>
* Geodata without {@link IGeoObject} are taken in consideration.
* @param geoX : Cell geodata X coordinate.
* @param geoY : Cell geodata Y coordinate.
* @param worldZ : Cell world Z coordinate.
* @return short : Cell geodata Z coordinate, nearest to given coordinates.
*/
public abstract short getHeightNearestOriginal(int geoX, int geoY, int worldZ);
/**
* Returns the height of cell, which is first above given coordinates.
* @param geoX : Cell geodata X coordinate.
* @param geoY : Cell geodata Y coordinate.
* @param worldZ : Cell world Z coordinate.
* @return short : Cell geodata Z coordinate, above given coordinates.
*/
public abstract short getHeightAbove(int geoX, int geoY, int worldZ);
/**
* Returns the height of cell, which is first below given coordinates.
* @param geoX : Cell geodata X coordinate.
* @param geoY : Cell geodata Y coordinate.
* @param worldZ : Cell world Z coordinate.
* @return short : Cell geodata Z coordinate, below given coordinates.
*/
public abstract short getHeightBelow(int geoX, int geoY, int worldZ);
/**
* Returns the NSWE flag byte of cell, which is closest to given coordinates.
* @param geoX : Cell geodata X coordinate.
* @param geoY : Cell geodata Y coordinate.
* @param worldZ : Cell world Z coordinate.
* @return short : Cell NSWE flag byte, nearest to given coordinates.
*/
public abstract byte getNsweNearest(int geoX, int geoY, int worldZ);
/**
* Returns the NSWE flag byte of cell, which is closest to given coordinates.<br>
* Geodata without {@link IGeoObject} are taken in consideration.
* @param geoX : Cell geodata X coordinate.
* @param geoY : Cell geodata Y coordinate.
* @param worldZ : Cell world Z coordinate.
* @return short : Cell NSWE flag byte, nearest to given coordinates.
*/
public abstract byte getNsweNearestOriginal(int geoX, int geoY, int worldZ);
/**
* Returns the NSWE flag byte of cell, which is first above given coordinates.
* @param geoX : Cell geodata X coordinate.
* @param geoY : Cell geodata Y coordinate.
* @param worldZ : Cell world Z coordinate.
* @return short : Cell NSWE flag byte, nearest to given coordinates.
*/
public abstract byte getNsweAbove(int geoX, int geoY, int worldZ);
/**
* Returns the NSWE flag byte of cell, which is first below given coordinates.
* @param geoX : Cell geodata X coordinate.
* @param geoY : Cell geodata Y coordinate.
* @param worldZ : Cell world Z coordinate.
* @return short : Cell NSWE flag byte, nearest to given coordinates.
*/
public abstract byte getNsweBelow(int geoX, int geoY, int worldZ);
/**
* Returns index to data of the cell, which is closes layer to given coordinates.
* @param geoX : Cell geodata X coordinate.
* @param geoY : Cell geodata Y coordinate.
* @param worldZ : Cell world Z coordinate.
* @return {@code int} : Cell index.
*/
public abstract int getIndexNearest(int geoX, int geoY, int worldZ);
/**
* Returns index to data of the cell, which is first layer above given coordinates.
* @param geoX : Cell geodata X coordinate.
* @param geoY : Cell geodata Y coordinate.
* @param worldZ : Cell world Z coordinate.
* @return {@code int} : Cell index. -1..when no layer available below given Z coordinate.
*/
public abstract int getIndexAbove(int geoX, int geoY, int worldZ);
/**
* Returns index to data of the cell, which is first layer above given coordinates.<br>
* Geodata without {@link IGeoObject} are taken in consideration.
* @param geoX : Cell geodata X coordinate.
* @param geoY : Cell geodata Y coordinate.
* @param worldZ : Cell world Z coordinate.
* @return {@code int} : Cell index. -1..when no layer available below given Z coordinate.
*/
public abstract int getIndexAboveOriginal(int geoX, int geoY, int worldZ);
/**
* Returns index to data of the cell, which is first layer below given coordinates.
* @param geoX : Cell geodata X coordinate.
* @param geoY : Cell geodata Y coordinate.
* @param worldZ : Cell world Z coordinate.
* @return {@code int} : Cell index. -1..when no layer available below given Z coordinate.
*/
public abstract int getIndexBelow(int geoX, int geoY, int worldZ);
/**
* Returns index to data of the cell, which is first layer below given coordinates.<br>
* Geodata without {@link IGeoObject} are taken in consideration.
* @param geoX : Cell geodata X coordinate.
* @param geoY : Cell geodata Y coordinate.
* @param worldZ : Cell world Z coordinate.
* @return {@code int} : Cell index. -1..when no layer available below given Z coordinate.
*/
public abstract int getIndexBelowOriginal(int geoX, int geoY, int worldZ);
/**
* Returns the height of cell given by cell index.
* @param index : Index of the cell.
* @return short : Cell geodata Z coordinate, below given coordinates.
*/
public abstract short getHeight(int index);
/**
* Returns the height of cell given by cell index.<br>
* Geodata without {@link IGeoObject} are taken in consideration.
* @param index : Index of the cell.
* @return short : Cell geodata Z coordinate, below given coordinates.
*/
public abstract short getHeightOriginal(int index);
/**
* Returns the NSWE flag byte of cell given by cell index.
* @param index : Index of the cell.
* @return short : Cell geodata Z coordinate, below given coordinates.
*/
public abstract byte getNswe(int index);
/**
* Returns the NSWE flag byte of cell given by cell index.<br>
* Geodata without {@link IGeoObject} are taken in consideration.
* @param index : Index of the cell.
* @return short : Cell geodata Z coordinate, below given coordinates.
*/
public abstract byte getNsweOriginal(int index);
/**
* Sets the NSWE flag byte of cell given by cell index.
* @param index : Index of the cell.
* @param nswe : New NSWE flag byte.
*/
public abstract void setNswe(int index, byte nswe);
/**
* Saves the block in L2D format to {@link BufferedOutputStream}. Used only for L2D geodata conversion.
* @param stream : The stream.
* @throws IOException : Can't save the block to steam.
*/
public abstract void saveBlock(BufferedOutputStream stream) throws IOException;
}

View File

@@ -0,0 +1,252 @@
/*
* 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.geoengine.geodata;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
/**
* @author Hasha
*/
public class BlockComplex extends ABlock
{
protected byte[] _buffer;
/**
* Implicit constructor for children class.
*/
protected BlockComplex()
{
// buffer is initialized in children class
_buffer = null;
}
/**
* Creates ComplexBlock.
* @param bb : Input byte buffer.
* @param format : GeoFormat specifying format of loaded data.
*/
public BlockComplex(ByteBuffer bb, GeoFormat format)
{
// initialize buffer
_buffer = new byte[GeoStructure.BLOCK_CELLS * 3];
// load data
for (int i = 0; i < GeoStructure.BLOCK_CELLS; i++)
{
if (format != GeoFormat.L2D)
{
// get data
short data = bb.getShort();
// get nswe
_buffer[i * 3] = (byte) (data & 0x000F);
// get height
data = (short) ((short) (data & 0xFFF0) >> 1);
_buffer[(i * 3) + 1] = (byte) (data & 0x00FF);
_buffer[(i * 3) + 2] = (byte) (data >> 8);
}
else
{
// get nswe
final byte nswe = bb.get();
_buffer[i * 3] = nswe;
// get height
final short height = bb.getShort();
_buffer[(i * 3) + 1] = (byte) (height & 0x00FF);
_buffer[(i * 3) + 2] = (byte) (height >> 8);
}
}
}
@Override
public final boolean hasGeoPos()
{
return true;
}
@Override
public final short getHeightNearest(int geoX, int geoY, int worldZ)
{
// get cell index
final int index = (((geoX % GeoStructure.BLOCK_CELLS_X) * GeoStructure.BLOCK_CELLS_Y) + (geoY % GeoStructure.BLOCK_CELLS_Y)) * 3;
// get height
return (short) ((_buffer[index + 1] & 0x00FF) | (_buffer[index + 2] << 8));
}
@Override
public short getHeightNearestOriginal(int geoX, int geoY, int worldZ)
{
return getHeightNearest(geoX, geoY, worldZ);
}
@Override
public final short getHeightAbove(int geoX, int geoY, int worldZ)
{
// get cell index
final int index = (((geoX % GeoStructure.BLOCK_CELLS_X) * GeoStructure.BLOCK_CELLS_Y) + (geoY % GeoStructure.BLOCK_CELLS_Y)) * 3;
// get height
final short height = (short) ((_buffer[index + 1] & 0x00FF) | (_buffer[index + 2] << 8));
// check and return height
return height > worldZ ? height : Short.MIN_VALUE;
}
@Override
public final short getHeightBelow(int geoX, int geoY, int worldZ)
{
// get cell index
final int index = (((geoX % GeoStructure.BLOCK_CELLS_X) * GeoStructure.BLOCK_CELLS_Y) + (geoY % GeoStructure.BLOCK_CELLS_Y)) * 3;
// get height
final short height = (short) ((_buffer[index + 1] & 0x00FF) | (_buffer[index + 2] << 8));
// check and return height
return height < worldZ ? height : Short.MAX_VALUE;
}
@Override
public final byte getNsweNearest(int geoX, int geoY, int worldZ)
{
// get cell index
final int index = (((geoX % GeoStructure.BLOCK_CELLS_X) * GeoStructure.BLOCK_CELLS_Y) + (geoY % GeoStructure.BLOCK_CELLS_Y)) * 3;
// get nswe
return _buffer[index];
}
@Override
public byte getNsweNearestOriginal(int geoX, int geoY, int worldZ)
{
return getNsweNearest(geoX, geoY, worldZ);
}
@Override
public final byte getNsweAbove(int geoX, int geoY, int worldZ)
{
// get cell index
final int index = (((geoX % GeoStructure.BLOCK_CELLS_X) * GeoStructure.BLOCK_CELLS_Y) + (geoY % GeoStructure.BLOCK_CELLS_Y)) * 3;
// get height
final int height = (_buffer[index + 1] & 0x00FF) | (_buffer[index + 2] << 8);
// check height and return nswe
return height > worldZ ? _buffer[index] : 0;
}
@Override
public final byte getNsweBelow(int geoX, int geoY, int worldZ)
{
// get cell index
final int index = (((geoX % GeoStructure.BLOCK_CELLS_X) * GeoStructure.BLOCK_CELLS_Y) + (geoY % GeoStructure.BLOCK_CELLS_Y)) * 3;
// get height
final int height = (_buffer[index + 1] & 0x00FF) | (_buffer[index + 2] << 8);
// check height and return nswe
return height < worldZ ? _buffer[index] : 0;
}
@Override
public final int getIndexNearest(int geoX, int geoY, int worldZ)
{
return (((geoX % GeoStructure.BLOCK_CELLS_X) * GeoStructure.BLOCK_CELLS_Y) + (geoY % GeoStructure.BLOCK_CELLS_Y)) * 3;
}
@Override
public final int getIndexAbove(int geoX, int geoY, int worldZ)
{
// get cell index
final int index = (((geoX % GeoStructure.BLOCK_CELLS_X) * GeoStructure.BLOCK_CELLS_Y) + (geoY % GeoStructure.BLOCK_CELLS_Y)) * 3;
// get height
final int height = (_buffer[index + 1] & 0x00FF) | (_buffer[index + 2] << 8);
// check height and return nswe
return height > worldZ ? index : -1;
}
@Override
public int getIndexAboveOriginal(int geoX, int geoY, int worldZ)
{
return getIndexAbove(geoX, geoY, worldZ);
}
@Override
public final int getIndexBelow(int geoX, int geoY, int worldZ)
{
// get cell index
final int index = (((geoX % GeoStructure.BLOCK_CELLS_X) * GeoStructure.BLOCK_CELLS_Y) + (geoY % GeoStructure.BLOCK_CELLS_Y)) * 3;
// get height
final int height = (_buffer[index + 1] & 0x00FF) | (_buffer[index + 2] << 8);
// check height and return nswe
return height < worldZ ? index : -1;
}
@Override
public int getIndexBelowOriginal(int geoX, int geoY, int worldZ)
{
return getIndexBelow(geoX, geoY, worldZ);
}
@Override
public final short getHeight(int index)
{
return (short) ((_buffer[index + 1] & 0x00FF) | (_buffer[index + 2] << 8));
}
@Override
public short getHeightOriginal(int index)
{
return (short) ((_buffer[index + 1] & 0x00FF) | (_buffer[index + 2] << 8));
}
@Override
public final byte getNswe(int index)
{
return _buffer[index];
}
@Override
public byte getNsweOriginal(int index)
{
return _buffer[index];
}
@Override
public final void setNswe(int index, byte nswe)
{
_buffer[index] = nswe;
}
@Override
public final void saveBlock(BufferedOutputStream stream) throws IOException
{
// write block type
stream.write(GeoStructure.TYPE_COMPLEX_L2D);
// write block data
stream.write(_buffer, 0, GeoStructure.BLOCK_CELLS * 3);
}
}

View File

@@ -0,0 +1,255 @@
/*
* 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.geoengine.geodata;
import java.util.LinkedList;
import java.util.List;
/**
* @author Hasha
*/
public final class BlockComplexDynamic extends BlockComplex implements IBlockDynamic
{
private final int _bx;
private final int _by;
private final byte[] _original;
private final List<IGeoObject> _objects;
/**
* Creates {@link BlockComplexDynamic}.
* @param bx : Block X coordinate.
* @param by : Block Y coordinate.
* @param block : The original FlatBlock to create a dynamic version from.
*/
public BlockComplexDynamic(int bx, int by, BlockFlat block)
{
// load data
final byte nswe = block._nswe;
final byte heightLow = (byte) (block._height & 0x00FF);
final byte heightHigh = (byte) (block._height >> 8);
// initialize buffer
_buffer = new byte[GeoStructure.BLOCK_CELLS * 3];
// save data
for (int i = 0; i < GeoStructure.BLOCK_CELLS; i++)
{
// set nswe
_buffer[i * 3] = nswe;
// set height
_buffer[(i * 3) + 1] = heightLow;
_buffer[(i * 3) + 2] = heightHigh;
}
// get block coordinates
_bx = bx;
_by = by;
// create copy for dynamic implementation
_original = new byte[GeoStructure.BLOCK_CELLS * 3];
System.arraycopy(_buffer, 0, _original, 0, GeoStructure.BLOCK_CELLS * 3);
// create list for geo objects
_objects = new LinkedList<>();
}
/**
* Creates {@link BlockComplexDynamic}.
* @param bx : Block X coordinate.
* @param by : Block Y coordinate.
* @param block : The original ComplexBlock to create a dynamic version from.
*/
public BlockComplexDynamic(int bx, int by, BlockComplex block)
{
// move buffer from BlockComplex object to this object
_buffer = block._buffer;
block._buffer = null;
// get block coordinates
_bx = bx;
_by = by;
// create copy for dynamic implementation
_original = new byte[GeoStructure.BLOCK_CELLS * 3];
System.arraycopy(_buffer, 0, _original, 0, GeoStructure.BLOCK_CELLS * 3);
// create list for geo objects
_objects = new LinkedList<>();
}
@Override
public final short getHeightNearestOriginal(int geoX, int geoY, int worldZ)
{
// get cell index
final int index = (((geoX % GeoStructure.BLOCK_CELLS_X) * GeoStructure.BLOCK_CELLS_Y) + (geoY % GeoStructure.BLOCK_CELLS_Y)) * 3;
// get height
return (short) ((_original[index + 1] & 0x00FF) | (_original[index + 2] << 8));
}
@Override
public final byte getNsweNearestOriginal(int geoX, int geoY, int worldZ)
{
// get cell index
final int index = (((geoX % GeoStructure.BLOCK_CELLS_X) * GeoStructure.BLOCK_CELLS_Y) + (geoY % GeoStructure.BLOCK_CELLS_Y)) * 3;
// get nswe
return _original[index];
}
@Override
public final int getIndexAboveOriginal(int geoX, int geoY, int worldZ)
{
// get cell index
final int index = (((geoX % GeoStructure.BLOCK_CELLS_X) * GeoStructure.BLOCK_CELLS_Y) + (geoY % GeoStructure.BLOCK_CELLS_Y)) * 3;
// get height
final int height = (_original[index + 1] & 0x00FF) | (_original[index + 2] << 8);
// check height and return nswe
return height > worldZ ? index : -1;
}
@Override
public final int getIndexBelowOriginal(int geoX, int geoY, int worldZ)
{
// get cell index
final int index = (((geoX % GeoStructure.BLOCK_CELLS_X) * GeoStructure.BLOCK_CELLS_Y) + (geoY % GeoStructure.BLOCK_CELLS_Y)) * 3;
// get height
final int height = (_original[index + 1] & 0x00FF) | (_original[index + 2] << 8);
// check height and return nswe
return height < worldZ ? index : -1;
}
@Override
public final short getHeightOriginal(int index)
{
return (short) ((_original[index + 1] & 0x00FF) | (_original[index + 2] << 8));
}
@Override
public final byte getNsweOriginal(int index)
{
return _original[index];
}
@Override
public synchronized final void addGeoObject(IGeoObject object)
{
// add geo object, update block geodata when added
if (_objects.add(object))
{
update();
}
}
@Override
public synchronized final void removeGeoObject(IGeoObject object)
{
// remove geo object, update block geodata when removed
if (_objects.remove(object))
{
update();
}
}
private final void update()
{
// copy original geodata, than apply changes
System.arraycopy(_original, 0, _buffer, 0, GeoStructure.BLOCK_CELLS * 3);
// get block geo coordinates
final int minBX = _bx * GeoStructure.BLOCK_CELLS_X;
final int minBY = _by * GeoStructure.BLOCK_CELLS_Y;
final int maxBX = minBX + GeoStructure.BLOCK_CELLS_X;
final int maxBY = minBY + GeoStructure.BLOCK_CELLS_Y;
// for all objects
for (IGeoObject object : _objects)
{
// get object geo coordinates and other object variables
final int minOX = object.getGeoX();
final int minOY = object.getGeoY();
final int minOZ = object.getGeoZ();
final int maxOZ = minOZ + object.getHeight();
final byte[][] geoData = object.getObjectGeoData();
// calculate min/max geo coordinates for iteration (intersection of block and object)
final int minGX = Math.max(minBX, minOX);
final int minGY = Math.max(minBY, minOY);
final int maxGX = Math.min(maxBX, minOX + geoData.length);
final int maxGY = Math.min(maxBY, minOY + geoData[0].length);
// iterate over intersection of block and object
for (int gx = minGX; gx < maxGX; gx++)
{
for (int gy = minGY; gy < maxGY; gy++)
{
// get object nswe
final byte objNswe = geoData[gx - minOX][gy - minOY];
// object contains no change of data in this cell, continue to next cell
if (objNswe == 0xFF)
{
continue;
}
// get block index of this cell
final int ib = (((gx - minBX) * GeoStructure.BLOCK_CELLS_Y) + (gy - minBY)) * 3;
// compare block data and original data, when height differs -> height was affected by other geo object
// -> cell is inside an object -> no need to check/change it anymore (Z is lifted, nswe is 0)
// compare is done in raw format (2 bytes) instead of conversion to short
if ((_buffer[ib + 1] != _original[ib + 1]) || (_buffer[ib + 2] != _original[ib + 2]))
{
continue;
}
// so far cell is not inside of any object
if (objNswe == 0)
{
// cell is inside of this object -> set nswe to 0 and lift Z up
// set block nswe
_buffer[ib] = 0;
// set block Z to object height
_buffer[ib + 1] = (byte) (maxOZ & 0x00FF);
_buffer[ib + 2] = (byte) (maxOZ >> 8);
}
else
{
// cell is outside of this object -> update nswe
// height different is too high (trying to update another layer), skip
short z = getHeight(ib);
if (Math.abs(z - minOZ) > GeoStructure.CELL_IGNORE_HEIGHT)
{
continue;
}
// adjust block nswe according to the object nswe
_buffer[ib] &= objNswe;
}
}
}
}
}
}

View File

@@ -0,0 +1,177 @@
/*
* 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.geoengine.geodata;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
/**
* @author Hasha
*/
public class BlockFlat extends ABlock
{
protected final short _height;
protected byte _nswe;
/**
* Creates FlatBlock.
* @param bb : Input byte buffer.
* @param format : GeoFormat specifying format of loaded data.
*/
public BlockFlat(ByteBuffer bb, GeoFormat format)
{
_height = bb.getShort();
_nswe = format != GeoFormat.L2D ? 0x0F : (byte) (0xFF);
if (format == GeoFormat.L2OFF)
{
bb.getShort();
}
}
@Override
public final boolean hasGeoPos()
{
return true;
}
@Override
public final short getHeightNearest(int geoX, int geoY, int worldZ)
{
return _height;
}
@Override
public final short getHeightNearestOriginal(int geoX, int geoY, int worldZ)
{
return _height;
}
@Override
public final short getHeightAbove(int geoX, int geoY, int worldZ)
{
// check and return height
return _height > worldZ ? _height : Short.MIN_VALUE;
}
@Override
public final short getHeightBelow(int geoX, int geoY, int worldZ)
{
// check and return height
return _height < worldZ ? _height : Short.MAX_VALUE;
}
@Override
public final byte getNsweNearest(int geoX, int geoY, int worldZ)
{
return _nswe;
}
@Override
public final byte getNsweNearestOriginal(int geoX, int geoY, int worldZ)
{
return _nswe;
}
@Override
public final byte getNsweAbove(int geoX, int geoY, int worldZ)
{
// check height and return nswe
return _height > worldZ ? _nswe : 0;
}
@Override
public final byte getNsweBelow(int geoX, int geoY, int worldZ)
{
// check height and return nswe
return _height < worldZ ? _nswe : 0;
}
@Override
public final int getIndexNearest(int geoX, int geoY, int worldZ)
{
return 0;
}
@Override
public final int getIndexAbove(int geoX, int geoY, int worldZ)
{
// check height and return index
return _height > worldZ ? 0 : -1;
}
@Override
public final int getIndexAboveOriginal(int geoX, int geoY, int worldZ)
{
return getIndexAbove(geoX, geoY, worldZ);
}
@Override
public final int getIndexBelow(int geoX, int geoY, int worldZ)
{
// check height and return index
return _height < worldZ ? 0 : -1;
}
@Override
public final int getIndexBelowOriginal(int geoX, int geoY, int worldZ)
{
return getIndexBelow(geoX, geoY, worldZ);
}
@Override
public final short getHeight(int index)
{
return _height;
}
@Override
public final short getHeightOriginal(int index)
{
return _height;
}
@Override
public final byte getNswe(int index)
{
return _nswe;
}
@Override
public final byte getNsweOriginal(int index)
{
return _nswe;
}
@Override
public final void setNswe(int index, byte nswe)
{
_nswe = nswe;
}
@Override
public final void saveBlock(BufferedOutputStream stream) throws IOException
{
// write block type
stream.write(GeoStructure.TYPE_FLAT_L2D);
// write height
stream.write((byte) (_height & 0x00FF));
stream.write((byte) (_height >> 8));
}
}

View File

@@ -0,0 +1,466 @@
/*
* 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.geoengine.geodata;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
/**
* @author Hasha
*/
public class BlockMultilayer extends ABlock
{
private static final int MAX_LAYERS = Byte.MAX_VALUE;
private static ByteBuffer _temp;
/**
* Initializes the temporarily buffer.
*/
public static final void initialize()
{
// initialize temporarily buffer and sorting mechanism
_temp = ByteBuffer.allocate(GeoStructure.BLOCK_CELLS * MAX_LAYERS * 3);
_temp.order(ByteOrder.LITTLE_ENDIAN);
}
/**
* Releases temporarily buffer.
*/
public static final void release()
{
_temp = null;
}
protected byte[] _buffer;
/**
* Implicit constructor for children class.
*/
protected BlockMultilayer()
{
_buffer = null;
}
/**
* Creates MultilayerBlock.
* @param bb : Input byte buffer.
* @param format : GeoFormat specifying format of loaded data.
*/
public BlockMultilayer(ByteBuffer bb, GeoFormat format)
{
// move buffer pointer to end of MultilayerBlock
for (int cell = 0; cell < GeoStructure.BLOCK_CELLS; cell++)
{
// get layer count for this cell
final byte layers = format != GeoFormat.L2OFF ? bb.get() : (byte) bb.getShort();
if ((layers <= 0) || (layers > MAX_LAYERS))
{
throw new RuntimeException("Invalid layer count for MultilayerBlock");
}
// add layers count
_temp.put(layers);
// loop over layers
for (byte layer = 0; layer < layers; layer++)
{
if (format != GeoFormat.L2D)
{
// get data
short data = bb.getShort();
// add nswe and height
_temp.put((byte) (data & 0x000F));
_temp.putShort((short) ((short) (data & 0xFFF0) >> 1));
}
else
{
// add nswe
_temp.put(bb.get());
// add height
_temp.putShort(bb.getShort());
}
}
}
// initialize buffer
_buffer = Arrays.copyOf(_temp.array(), _temp.position());
// clear temp buffer
_temp.clear();
}
@Override
public final boolean hasGeoPos()
{
return true;
}
@Override
public final short getHeightNearest(int geoX, int geoY, int worldZ)
{
// get cell index
final int index = getIndexNearest(geoX, geoY, worldZ);
// get height
return (short) ((_buffer[index + 1] & 0x00FF) | (_buffer[index + 2] << 8));
}
@Override
public short getHeightNearestOriginal(int geoX, int geoY, int worldZ)
{
return getHeightNearest(geoX, geoY, worldZ);
}
@Override
public final short getHeightAbove(int geoX, int geoY, int worldZ)
{
// move index to the cell given by coordinates
int index = 0;
for (int i = 0; i < (((geoX % GeoStructure.BLOCK_CELLS_X) * GeoStructure.BLOCK_CELLS_Y) + (geoY % GeoStructure.BLOCK_CELLS_Y)); i++)
{
// move index by amount of layers for this cell
index += (_buffer[index] * 3) + 1;
}
// get layers count and shift to last layer data (first from bottom)
byte layers = _buffer[index++];
index += (layers - 1) * 3;
// loop though all layers, find first layer above worldZ
while (layers-- > 0)
{
// get layer height
final int height = (_buffer[index + 1] & 0x00FF) | (_buffer[index + 2] << 8);
// layer height is higher than worldZ, return layer height
if (height > worldZ)
{
return (short) height;
}
// move index to next layer
index -= 3;
}
// none layer found, return minimum value
return Short.MIN_VALUE;
}
@Override
public final short getHeightBelow(int geoX, int geoY, int worldZ)
{
// move index to the cell given by coordinates
int index = 0;
for (int i = 0; i < (((geoX % GeoStructure.BLOCK_CELLS_X) * GeoStructure.BLOCK_CELLS_Y) + (geoY % GeoStructure.BLOCK_CELLS_Y)); i++)
{
// move index by amount of layers for this cell
index += (_buffer[index] * 3) + 1;
}
// get layers count and shift to first layer data (first from top)
byte layers = _buffer[index++];
// loop though all layers, find first layer below worldZ
while (layers-- > 0)
{
// get layer height
final int height = (_buffer[index + 1] & 0x00FF) | (_buffer[index + 2] << 8);
// layer height is lower than worldZ, return layer height
if (height < worldZ)
{
return (short) height;
}
// move index to next layer
index += 3;
}
// none layer found, return maximum value
return Short.MAX_VALUE;
}
@Override
public final byte getNsweNearest(int geoX, int geoY, int worldZ)
{
// get cell index
final int index = getIndexNearest(geoX, geoY, worldZ);
// get nswe
return _buffer[index];
}
@Override
public byte getNsweNearestOriginal(int geoX, int geoY, int worldZ)
{
return getNsweNearest(geoX, geoY, worldZ);
}
@Override
public final byte getNsweAbove(int geoX, int geoY, int worldZ)
{
// move index to the cell given by coordinates
int index = 0;
for (int i = 0; i < (((geoX % GeoStructure.BLOCK_CELLS_X) * GeoStructure.BLOCK_CELLS_Y) + (geoY % GeoStructure.BLOCK_CELLS_Y)); i++)
{
// move index by amount of layers for this cell
index += (_buffer[index] * 3) + 1;
}
// get layers count and shift to last layer data (first from bottom)
byte layers = _buffer[index++];
index += (layers - 1) * 3;
// loop though all layers, find first layer above worldZ
while (layers-- > 0)
{
// get layer height
final int height = (_buffer[index + 1] & 0x00FF) | (_buffer[index + 2] << 8);
// layer height is higher than worldZ, return layer nswe
if (height > worldZ)
{
return _buffer[index];
}
// move index to next layer
index -= 3;
}
// none layer found, block movement
return 0;
}
@Override
public final byte getNsweBelow(int geoX, int geoY, int worldZ)
{
// move index to the cell given by coordinates
int index = 0;
for (int i = 0; i < (((geoX % GeoStructure.BLOCK_CELLS_X) * GeoStructure.BLOCK_CELLS_Y) + (geoY % GeoStructure.BLOCK_CELLS_Y)); i++)
{
// move index by amount of layers for this cell
index += (_buffer[index] * 3) + 1;
}
// get layers count and shift to first layer data (first from top)
byte layers = _buffer[index++];
// loop though all layers, find first layer below worldZ
while (layers-- > 0)
{
// get layer height
final int height = (_buffer[index + 1] & 0x00FF) | (_buffer[index + 2] << 8);
// layer height is lower than worldZ, return layer nswe
if (height < worldZ)
{
return _buffer[index];
}
// move index to next layer
index += 3;
}
// none layer found, block movement
return 0;
}
@Override
public final int getIndexNearest(int geoX, int geoY, int worldZ)
{
// move index to the cell given by coordinates
int index = 0;
for (int i = 0; i < (((geoX % GeoStructure.BLOCK_CELLS_X) * GeoStructure.BLOCK_CELLS_Y) + (geoY % GeoStructure.BLOCK_CELLS_Y)); i++)
{
// move index by amount of layers for this cell
index += (_buffer[index] * 3) + 1;
}
// get layers count and shift to first layer data (first from bottom)
byte layers = _buffer[index++];
// loop though all cell layers, find closest layer
int limit = Integer.MAX_VALUE;
while (layers-- > 0)
{
// get layer height
final int height = (_buffer[index + 1] & 0x00FF) | (_buffer[index + 2] << 8);
// get Z distance and compare with limit
// note: When 2 layers have same distance to worldZ (worldZ is in the middle of them):
// > returns bottom layer
// >= returns upper layer
final int distance = Math.abs(height - worldZ);
if (distance > limit)
{
break;
}
// update limit and move to next layer
limit = distance;
index += 3;
}
// return layer index
return index - 3;
}
@Override
public final int getIndexAbove(int geoX, int geoY, int worldZ)
{
// move index to the cell given by coordinates
int index = 0;
for (int i = 0; i < (((geoX % GeoStructure.BLOCK_CELLS_X) * GeoStructure.BLOCK_CELLS_Y) + (geoY % GeoStructure.BLOCK_CELLS_Y)); i++)
{
// move index by amount of layers for this cell
index += (_buffer[index] * 3) + 1;
}
// get layers count and shift to last layer data (first from bottom)
byte layers = _buffer[index++];
index += (layers - 1) * 3;
// loop though all layers, find first layer above worldZ
while (layers-- > 0)
{
// get layer height
final int height = (_buffer[index + 1] & 0x00FF) | (_buffer[index + 2] << 8);
// layer height is higher than worldZ, return layer index
if (height > worldZ)
{
return index;
}
// move index to next layer
index -= 3;
}
// none layer found
return -1;
}
@Override
public int getIndexAboveOriginal(int geoX, int geoY, int worldZ)
{
return getIndexAbove(geoX, geoY, worldZ);
}
@Override
public final int getIndexBelow(int geoX, int geoY, int worldZ)
{
// move index to the cell given by coordinates
int index = 0;
for (int i = 0; i < (((geoX % GeoStructure.BLOCK_CELLS_X) * GeoStructure.BLOCK_CELLS_Y) + (geoY % GeoStructure.BLOCK_CELLS_Y)); i++)
{
// move index by amount of layers for this cell
index += (_buffer[index] * 3) + 1;
}
// get layers count and shift to first layer data (first from top)
byte layers = _buffer[index++];
// loop though all layers, find first layer below worldZ
while (layers-- > 0)
{
// get layer height
final int height = (_buffer[index + 1] & 0x00FF) | (_buffer[index + 2] << 8);
// layer height is lower than worldZ, return layer index
if (height < worldZ)
{
return index;
}
// move index to next layer
index += 3;
}
// none layer found
return -1;
}
@Override
public int getIndexBelowOriginal(int geoX, int geoY, int worldZ)
{
return getIndexBelow(geoX, geoY, worldZ);
}
@Override
public final short getHeight(int index)
{
// get height
return (short) ((_buffer[index + 1] & 0x00FF) | (_buffer[index + 2] << 8));
}
@Override
public short getHeightOriginal(int index)
{
// get height
return (short) ((_buffer[index + 1] & 0x00FF) | (_buffer[index + 2] << 8));
}
@Override
public final byte getNswe(int index)
{
// get nswe
return _buffer[index];
}
@Override
public byte getNsweOriginal(int index)
{
// get nswe
return _buffer[index];
}
@Override
public final void setNswe(int index, byte nswe)
{
// set nswe
_buffer[index] = nswe;
}
@Override
public final void saveBlock(BufferedOutputStream stream) throws IOException
{
// write block type
stream.write(GeoStructure.TYPE_MULTILAYER_L2D);
// for each cell
int index = 0;
for (int i = 0; i < GeoStructure.BLOCK_CELLS; i++)
{
// write layers count
byte layers = _buffer[index++];
stream.write(layers);
// write cell data
stream.write(_buffer, index, layers * 3);
// move index to next cell
index += layers * 3;
}
}
}

View File

@@ -0,0 +1,312 @@
/*
* 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.geoengine.geodata;
import java.util.LinkedList;
import java.util.List;
/**
* @author Hasha
*/
public final class BlockMultilayerDynamic extends BlockMultilayer implements IBlockDynamic
{
private final int _bx;
private final int _by;
private final byte[] _original;
private final List<IGeoObject> _objects;
/**
* Creates {@link BlockMultilayerDynamic}.
* @param bx : Block X coordinate.
* @param by : Block Y coordinate.
* @param block : The original MultilayerBlock to create a dynamic version from.
*/
public BlockMultilayerDynamic(int bx, int by, BlockMultilayer block)
{
// move buffer from ComplexBlock object to this object
_buffer = block._buffer;
block._buffer = null;
// get block coordinates
_bx = bx;
_by = by;
// create copy for dynamic implementation
_original = new byte[_buffer.length];
System.arraycopy(_buffer, 0, _original, 0, _buffer.length);
// create list for geo objects
_objects = new LinkedList<>();
}
@Override
public short getHeightNearestOriginal(int geoX, int geoY, int worldZ)
{
// get cell index
final int index = getIndexNearestOriginal(geoX, geoY, worldZ);
// get height
return (short) ((_original[index + 1] & 0x00FF) | (_original[index + 2] << 8));
}
@Override
public byte getNsweNearestOriginal(int geoX, int geoY, int worldZ)
{
// get cell index
final int index = getIndexNearestOriginal(geoX, geoY, worldZ);
// get nswe
return _original[index];
}
private final int getIndexNearestOriginal(int geoX, int geoY, int worldZ)
{
// move index to the cell given by coordinates
int index = 0;
for (int i = 0; i < (((geoX % GeoStructure.BLOCK_CELLS_X) * GeoStructure.BLOCK_CELLS_Y) + (geoY % GeoStructure.BLOCK_CELLS_Y)); i++)
{
// move index by amount of layers for this cell
index += (_original[index] * 3) + 1;
}
// get layers count and shift to first layer data (first from bottom)
byte layers = _original[index++];
// loop though all cell layers, find closest layer
int limit = Integer.MAX_VALUE;
while (layers-- > 0)
{
// get layer height
final int height = (_original[index + 1] & 0x00FF) | (_original[index + 2] << 8);
// get Z distance and compare with limit
// note: When 2 layers have same distance to worldZ (worldZ is in the middle of them):
// > returns bottom layer
// >= returns upper layer
final int distance = Math.abs(height - worldZ);
if (distance > limit)
{
break;
}
// update limit and move to next layer
limit = distance;
index += 3;
}
// return layer index
return index - 3;
}
@Override
public final int getIndexAboveOriginal(int geoX, int geoY, int worldZ)
{
// move index to the cell given by coordinates
int index = 0;
for (int i = 0; i < (((geoX % GeoStructure.BLOCK_CELLS_X) * GeoStructure.BLOCK_CELLS_Y) + (geoY % GeoStructure.BLOCK_CELLS_Y)); i++)
{
// move index by amount of layers for this cell
index += (_original[index] * 3) + 1;
}
// get layers count and shift to last layer data (first from bottom)
byte layers = _original[index++];
index += (layers - 1) * 3;
// loop though all layers, find first layer above worldZ
while (layers-- > 0)
{
// get layer height
final int height = (_original[index + 1] & 0x00FF) | (_original[index + 2] << 8);
// layer height is higher than worldZ, return layer index
if (height > worldZ)
{
return index;
}
// move index to next layer
index -= 3;
}
// none layer found
return -1;
}
@Override
public final int getIndexBelowOriginal(int geoX, int geoY, int worldZ)
{
// move index to the cell given by coordinates
int index = 0;
for (int i = 0; i < (((geoX % GeoStructure.BLOCK_CELLS_X) * GeoStructure.BLOCK_CELLS_Y) + (geoY % GeoStructure.BLOCK_CELLS_Y)); i++)
{
// move index by amount of layers for this cell
index += (_original[index] * 3) + 1;
}
// get layers count and shift to first layer data (first from top)
byte layers = _original[index++];
// loop though all layers, find first layer below worldZ
while (layers-- > 0)
{
// get layer height
final int height = (_original[index + 1] & 0x00FF) | (_original[index + 2] << 8);
// layer height is lower than worldZ, return layer index
if (height < worldZ)
{
return index;
}
// move index to next layer
index += 3;
}
// none layer found
return -1;
}
@Override
public short getHeightOriginal(int index)
{
// get height
return (short) ((_original[index + 1] & 0x00FF) | (_original[index + 2] << 8));
}
@Override
public byte getNsweOriginal(int index)
{
// get nswe
return _original[index];
}
@Override
public synchronized final void addGeoObject(IGeoObject object)
{
// add geo object, update block geodata when added
if (_objects.add(object))
{
update();
}
}
@Override
public synchronized final void removeGeoObject(IGeoObject object)
{
// remove geo object, update block geodata when removed
if (_objects.remove(object))
{
update();
}
}
private final void update()
{
// copy original geodata, than apply changes
System.arraycopy(_original, 0, _buffer, 0, _original.length);
// get block geo coordinates
final int minBX = _bx * GeoStructure.BLOCK_CELLS_X;
final int minBY = _by * GeoStructure.BLOCK_CELLS_Y;
final int maxBX = minBX + GeoStructure.BLOCK_CELLS_X;
final int maxBY = minBY + GeoStructure.BLOCK_CELLS_Y;
// for all objects
for (IGeoObject object : _objects)
{
// get object geo coordinates and other object variables
final int minOX = object.getGeoX();
final int minOY = object.getGeoY();
final int minOZ = object.getGeoZ();
final int maxOZ = minOZ + object.getHeight();
final byte[][] geoData = object.getObjectGeoData();
// calculate min/max geo coordinates for iteration (intersection of block and object)
final int minGX = Math.max(minBX, minOX);
final int minGY = Math.max(minBY, minOY);
final int maxGX = Math.min(maxBX, minOX + geoData.length);
final int maxGY = Math.min(maxBY, minOY + geoData[0].length);
// iterate over intersection of block and object
for (int gx = minGX; gx < maxGX; gx++)
{
for (int gy = minGY; gy < maxGY; gy++)
{
// get object nswe
final byte objNswe = geoData[gx - minOX][gy - minOY];
// object contains no change of data in this cell, continue to next cell
if (objNswe == 0xFF)
{
continue;
}
// get block index of this cell
int ib = getIndexNearest(gx, gy, minOZ);
// compare block data and original data, when height differs -> height was affected by other geo object
// -> cell is inside an object -> no need to check/change it anymore (Z is lifted, nswe is 0)
// compare is done in raw format (2 bytes) instead of conversion to short
if ((_buffer[ib + 1] != _original[ib + 1]) || (_buffer[ib + 2] != _original[ib + 2]))
{
continue;
}
// so far cell is not inside of any object
if (objNswe == 0)
{
// cell is inside of this object -> set nswe to 0 and lift Z up
// set block nswe
_buffer[ib] = 0;
// calculate object height, limit to next layer
int z = maxOZ;
int i = getIndexAbove(gx, gy, minOZ);
if (i != -1)
{
int az = getHeight(i);
if (az <= maxOZ)
{
z = az - GeoStructure.CELL_IGNORE_HEIGHT;
}
}
// set block Z to object height
_buffer[ib + 1] = (byte) (z & 0x00FF);
_buffer[ib + 2] = (byte) (z >> 8);
}
else
{
// cell is outside of this object -> update nswe
// height different is too high (trying to update another layer), skip
short z = getHeight(ib);
if (Math.abs(z - minOZ) > GeoStructure.CELL_IGNORE_HEIGHT)
{
continue;
}
// adjust block nswe according to the object nswe
_buffer[ib] &= objNswe;
}
}
}
}
}
}

View File

@@ -0,0 +1,150 @@
/*
* 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.geoengine.geodata;
import java.io.BufferedOutputStream;
/**
* @author Hasha
*/
public class BlockNull extends ABlock
{
private final byte _nswe;
public BlockNull()
{
_nswe = (byte) 0xFF;
}
@Override
public final boolean hasGeoPos()
{
return false;
}
@Override
public final short getHeightNearest(int geoX, int geoY, int worldZ)
{
return (short) worldZ;
}
@Override
public final short getHeightNearestOriginal(int geoX, int geoY, int worldZ)
{
return (short) worldZ;
}
@Override
public final short getHeightAbove(int geoX, int geoY, int worldZ)
{
return (short) worldZ;
}
@Override
public final short getHeightBelow(int geoX, int geoY, int worldZ)
{
return (short) worldZ;
}
@Override
public final byte getNsweNearest(int geoX, int geoY, int worldZ)
{
return _nswe;
}
@Override
public final byte getNsweNearestOriginal(int geoX, int geoY, int worldZ)
{
return _nswe;
}
@Override
public final byte getNsweAbove(int geoX, int geoY, int worldZ)
{
return _nswe;
}
@Override
public final byte getNsweBelow(int geoX, int geoY, int worldZ)
{
return _nswe;
}
@Override
public final int getIndexNearest(int geoX, int geoY, int worldZ)
{
return 0;
}
@Override
public final int getIndexAbove(int geoX, int geoY, int worldZ)
{
return 0;
}
@Override
public final int getIndexAboveOriginal(int geoX, int geoY, int worldZ)
{
return 0;
}
@Override
public final int getIndexBelow(int geoX, int geoY, int worldZ)
{
return 0;
}
@Override
public final int getIndexBelowOriginal(int geoX, int geoY, int worldZ)
{
return 0;
}
@Override
public final short getHeight(int index)
{
return 0;
}
@Override
public final short getHeightOriginal(int index)
{
return 0;
}
@Override
public final byte getNswe(int index)
{
return _nswe;
}
@Override
public final byte getNsweOriginal(int index)
{
return _nswe;
}
@Override
public final void setNswe(int index, byte nswe)
{
}
@Override
public final void saveBlock(BufferedOutputStream stream)
{
}
}

View File

@@ -14,20 +14,26 @@
* 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;
package com.l2jmobius.gameserver.geoengine.geodata;
/**
* @author -Nemesiss-
* @author Hasha
*/
public abstract class AbstractNodeLoc
public enum GeoFormat
{
public abstract int getX();
L2J("%d_%d.l2j"),
L2OFF("%d_%d_conv.dat"),
L2D("%d_%d.l2d");
public abstract int getY();
private final String _filename;
public abstract int getZ();
private GeoFormat(String filename)
{
_filename = filename;
}
public abstract int getNodeX();
public abstract int getNodeY();
}
public String getFilename()
{
return _filename;
}
}

View File

@@ -0,0 +1,67 @@
/*
* 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.geoengine.geodata;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.model.Location;
/**
* @author Hasha
*/
public class GeoLocation extends Location
{
private byte _nswe;
public GeoLocation(int x, int y, int z)
{
super(x, y, GeoEngine.getInstance().getHeightNearest(x, y, z));
_nswe = GeoEngine.getInstance().getNsweNearest(x, y, z);
}
public void set(int x, int y, short z)
{
super.setXYZ(x, y, GeoEngine.getInstance().getHeightNearest(x, y, z));
_nswe = GeoEngine.getInstance().getNsweNearest(x, y, z);
}
public int getGeoX()
{
return _x;
}
public int getGeoY()
{
return _y;
}
@Override
public int getX()
{
return GeoEngine.getInstance().getWorldX(_x);
}
@Override
public int getY()
{
return GeoEngine.getInstance().getWorldY(_y);
}
public byte getNSWE()
{
return _nswe;
}
}

View File

@@ -0,0 +1,75 @@
/*
* 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.geoengine.geodata;
import com.l2jmobius.gameserver.model.L2World;
/**
* @author Hasha
*/
public final class GeoStructure
{
// cells
public static final byte CELL_FLAG_E = 1 << 0;
public static final byte CELL_FLAG_W = 1 << 1;
public static final byte CELL_FLAG_S = 1 << 2;
public static final byte CELL_FLAG_N = 1 << 3;
public static final byte CELL_FLAG_SE = 1 << 4;
public static final byte CELL_FLAG_SW = 1 << 5;
public static final byte CELL_FLAG_NE = 1 << 6;
public static final byte CELL_FLAG_NW = (byte) (1 << 7);
public static final byte CELL_FLAG_S_AND_E = CELL_FLAG_S | CELL_FLAG_E;
public static final byte CELL_FLAG_S_AND_W = CELL_FLAG_S | CELL_FLAG_W;
public static final byte CELL_FLAG_N_AND_E = CELL_FLAG_N | CELL_FLAG_E;
public static final byte CELL_FLAG_N_AND_W = CELL_FLAG_N | CELL_FLAG_W;
public static final int CELL_SIZE = 16;
public static final int CELL_HEIGHT = 8;
public static final int CELL_IGNORE_HEIGHT = CELL_HEIGHT * 6;
// blocks
public static final byte TYPE_FLAT_L2J_L2OFF = 0;
public static final byte TYPE_FLAT_L2D = (byte) 0xD0;
public static final byte TYPE_COMPLEX_L2J = 1;
public static final byte TYPE_COMPLEX_L2OFF = 0x40;
public static final byte TYPE_COMPLEX_L2D = (byte) 0xD1;
public static final byte TYPE_MULTILAYER_L2J = 2;
// public static final byte TYPE_MULTILAYER_L2OFF = 0x41; // officially not does exist, is anything above complex block (0x41 - 0xFFFF)
public static final byte TYPE_MULTILAYER_L2D = (byte) 0xD2;
public static final int BLOCK_CELLS_X = 8;
public static final int BLOCK_CELLS_Y = 8;
public static final int BLOCK_CELLS = BLOCK_CELLS_X * BLOCK_CELLS_Y;
// regions
public static final int REGION_BLOCKS_X = 256;
public static final int REGION_BLOCKS_Y = 256;
public static final int REGION_BLOCKS = REGION_BLOCKS_X * REGION_BLOCKS_Y;
public static final int REGION_CELLS_X = REGION_BLOCKS_X * BLOCK_CELLS_X;
public static final int REGION_CELLS_Y = REGION_BLOCKS_Y * BLOCK_CELLS_Y;
// global geodata
public static final int GEO_REGIONS_X = ((L2World.TILE_X_MAX - L2World.TILE_X_MIN) + 1);
public static final int GEO_REGIONS_Y = ((L2World.TILE_Y_MAX - L2World.TILE_Y_MIN) + 1);
public static final int GEO_BLOCKS_X = GEO_REGIONS_X * REGION_BLOCKS_X;
public static final int GEO_BLOCKS_Y = GEO_REGIONS_Y * REGION_BLOCKS_Y;
public static final int GEO_CELLS_X = GEO_BLOCKS_X * BLOCK_CELLS_X;
public static final int GEO_CELLS_Y = GEO_BLOCKS_Y * BLOCK_CELLS_Y;
}

View File

@@ -14,29 +14,22 @@
* 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;
package com.l2jmobius.gameserver.geoengine.geodata;
/**
* @author HorridoJoho
* @author Hasha
*/
public interface IBlock
public interface IBlockDynamic
{
int TYPE_FLAT = 0;
int TYPE_COMPLEX = 1;
int TYPE_MULTILAYER = 2;
/**
* Adds {@link IGeoObject} to the {@link ABlock}. The block will update geodata according the object.
* @param object : {@link IGeoObject} to be added.
*/
public void addGeoObject(IGeoObject object);
/** 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);
}
/**
* Removes {@link IGeoObject} from the {@link ABlock}. The block will update geodata according the object.
* @param object : {@link IGeoObject} to be removed.
*/
public void removeGeoObject(IGeoObject object);
}

View File

@@ -0,0 +1,53 @@
/*
* 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.geoengine.geodata;
/**
* @author Hasha
*/
public interface IGeoObject
{
/**
* Returns geodata X coordinate of the {@link IGeoObject}.
* @return int : Geodata X coordinate.
*/
public int getGeoX();
/**
* Returns geodata Y coordinate of the {@link IGeoObject}.
* @return int : Geodata Y coordinate.
*/
public int getGeoY();
/**
* Returns geodata Z coordinate of the {@link IGeoObject}.
* @return int : Geodata Z coordinate.
*/
public int getGeoZ();
/**
* Returns height of the {@link IGeoObject}.
* @return int : Height.
*/
public int getHeight();
/**
* Returns {@link IGeoObject} data.
* @return byte[][] : {@link IGeoObject} data.
*/
public byte[][] getObjectGeoData();
}

View File

@@ -0,0 +1,87 @@
/*
* 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.geoengine.pathfinding;
import com.l2jmobius.gameserver.geoengine.geodata.GeoLocation;
/**
* @author Hasha
*/
public class Node
{
// node coords and nswe flag
private GeoLocation _loc;
// node parent (for reverse path construction)
private Node _parent;
// node child (for moving over nodes during iteration)
private Node _child;
// node G cost (movement cost = parent movement cost + current movement cost)
private double _cost = -1000;
public void setLoc(int x, int y, int z)
{
_loc = new GeoLocation(x, y, z);
}
public GeoLocation getLoc()
{
return _loc;
}
public void setParent(Node parent)
{
_parent = parent;
}
public Node getParent()
{
return _parent;
}
public void setChild(Node child)
{
_child = child;
}
public Node getChild()
{
return _child;
}
public void setCost(double cost)
{
_cost = cost;
}
public double getCost()
{
return _cost;
}
public void free()
{
// reset node location
_loc = null;
// reset node parent, child and cost
_parent = null;
_child = null;
_cost = -1000;
}
}

Some files were not shown because too many files have changed in this diff Show More