From 05f0a141c37fdc5961868b46c79a1eb6f038b5ed Mon Sep 17 00:00:00 2001 From: MobiusDev <8391001+MobiusDevelopment@users.noreply.github.com> Date: Sat, 26 Aug 2017 20:50:32 +0000 Subject: [PATCH] Diagonal movement GeoEngine. --- L2J_Mobius_Classic/build.xml | 1 + .../dist/game/GeoDataConverter.bat | 6 + .../dist/game/GeoDataConverter.sh | 4 + .../dist/game/config/AdminCommands.xml | 6 +- .../dist/game/config/GeoData.ini | 75 - .../dist/game/config/GeoEngine.ini | 55 + .../dist/game/data/geodata/Readme.txt | 52 +- .../dist/game/data/pathnode/Readme.txt | 11 - .../data/scripts/ai/others/FleeMonsters.java | 4 +- .../ai/others/RandomWalkingGuards.java | 6 +- .../actionhandlers/L2PcInstanceAction.java | 6 +- .../actionhandlers/L2PetInstanceAction.java | 6 +- .../actionhandlers/L2SummonAction.java | 6 +- .../admincommandhandlers/AdminGeodata.java | 22 +- .../admincommandhandlers/AdminPathNode.java | 65 +- .../admincommandhandlers/AdminServerInfo.java | 2 +- .../admincommandhandlers/AdminTeleport.java | 4 +- .../admincommandhandlers/AdminZones.java | 4 +- .../handlers/effecthandlers/Blink.java | 4 +- .../scripts/handlers/effecthandlers/Fear.java | 4 +- .../handlers/effecthandlers/FlyAway.java | 4 +- .../handlers/effecthandlers/KnockBack.java | 4 +- .../handlers/effecthandlers/PullBack.java | 4 +- .../effecthandlers/TeleportToSummon.java | 4 +- .../effecthandlers/TeleportToTarget.java | 4 +- .../OpBlinkSkillCondition.java | 4 +- .../handlers/targethandlers/Enemy.java | 4 +- .../handlers/targethandlers/EnemyNot.java | 6 +- .../handlers/targethandlers/EnemyOnly.java | 4 +- .../handlers/targethandlers/Ground.java | 4 +- .../handlers/targethandlers/NpcBody.java | 4 +- .../handlers/targethandlers/PcBody.java | 4 +- .../handlers/targethandlers/Target.java | 6 +- .../targethandlers/affectscope/Fan.java | 4 +- .../targethandlers/affectscope/FanPB.java | 4 +- .../affectscope/PointBlank.java | 4 +- .../targethandlers/affectscope/Range.java | 4 +- .../targethandlers/affectscope/RingRange.java | 4 +- .../targethandlers/affectscope/Square.java | 4 +- .../targethandlers/affectscope/SquarePB.java | 4 +- .../java/com/l2jmobius/Config.java | 84 +- .../com/l2jmobius/commons/util/MathUtil.java | 11 + .../com/l2jmobius/gameserver/GameServer.java | 11 +- .../gameserver/ai/FriendlyNpcAI.java | 8 +- .../gameserver/ai/L2AttackableAI.java | 14 +- .../gameserver/ai/L2CharacterAI.java | 4 +- .../gameserver/ai/L2FortSiegeGuardAI.java | 12 +- .../gameserver/ai/L2SiegeGuardAI.java | 12 +- .../l2jmobius/gameserver/ai/L2SummonAI.java | 4 +- .../gameserver/data/xml/impl/DoorData.java | 4 +- .../l2jmobius/gameserver/geodata/GeoData.java | 626 -------- .../gameserver/geodata/geodriver/Cell.java | 48 - .../geodata/geodriver/GeoDriver.java | 189 --- .../gameserver/geodata/geodriver/IBlock.java | 42 - .../gameserver/geodata/geodriver/IRegion.java | 47 - .../geodriver/blocks/ComplexBlock.java | 79 - .../geodata/geodriver/blocks/FlatBlock.java | 58 - .../geodriver/blocks/MultilayerBlock.java | 186 --- .../geodata/geodriver/regions/NullRegion.java | 57 - .../geodata/geodriver/regions/Region.java | 98 -- .../geodata/pathfinding/AbstractNode.java | 87 -- .../geodata/pathfinding/PathFinding.java | 211 --- .../pathfinding/cellnodes/CellNode.java | 69 - .../pathfinding/cellnodes/CellNodeBuffer.java | 361 ----- .../cellnodes/CellPathFinding.java | 440 ------ .../pathfinding/cellnodes/NodeLoc.java | 184 --- .../geodata/pathfinding/geonodes/GeoNode.java | 62 - .../pathfinding/geonodes/GeoNodeLoc.java | 109 -- .../pathfinding/geonodes/GeoPathFinding.java | 470 ------ .../pathfinding/utils/BinaryNodeHeap.java | 124 -- .../gameserver/geoengine/GeoEngine.java | 1311 +++++++++++++++++ .../geoengine/GeoEnginePathfinding.java | 308 ++++ .../gameserver/geoengine/geodata/ABlock.java | 197 +++ .../geoengine/geodata/BlockComplex.java | 252 ++++ .../geodata/BlockComplexDynamic.java | 255 ++++ .../geoengine/geodata/BlockFlat.java | 177 +++ .../geoengine/geodata/BlockMultilayer.java | 466 ++++++ .../geodata/BlockMultilayerDynamic.java | 312 ++++ .../geoengine/geodata/BlockNull.java | 150 ++ .../geoengine/geodata/GeoFormat.java | 26 +- .../geoengine/geodata/GeoLocation.java | 67 + .../geoengine/geodata/GeoStructure.java | 75 + .../geoengine/geodata/IBlockDynamic.java | 35 + .../geoengine/geodata/IGeoObject.java | 53 + .../geoengine/pathfinding/Node.java | 87 ++ .../geoengine/pathfinding/NodeBuffer.java | 351 +++++ .../instancemanager/WarpedSpaceManager.java | 6 - .../l2jmobius/gameserver/model/Fishing.java | 10 +- .../l2jmobius/gameserver/model/L2Spawn.java | 4 +- .../l2jmobius/gameserver/model/Location.java | 6 +- .../gameserver/model/actor/L2Character.java | 155 +- .../gameserver/model/actor/L2Tower.java | 4 +- .../model/actor/instance/L2PcInstance.java | 4 +- .../model/items/instance/L2ItemInstance.java | 4 +- .../gameserver/model/skills/SkillCaster.java | 4 +- .../model/skills/SkillChannelizer.java | 4 +- .../model/zone/form/ZoneCuboid.java | 4 +- .../model/zone/form/ZoneCylinder.java | 4 +- .../gameserver/model/zone/form/ZoneNPoly.java | 4 +- .../l2jmobius/gameserver/util/GeoUtils.java | 66 +- .../geodataconverter/GeoDataConverter.java | 375 +++++ L2J_Mobius_Ertheia/build.xml | 1 + .../dist/game/GeoDataConverter.bat | 6 + .../dist/game/GeoDataConverter.sh | 4 + .../dist/game/config/AdminCommands.xml | 6 +- .../dist/game/config/GeoData.ini | 75 - .../dist/game/config/GeoEngine.ini | 55 + .../dist/game/data/geodata/Readme.txt | 52 +- .../dist/game/data/pathnode/Readme.txt | 11 - .../FourSepulchers/FourSepulchers.java | 4 +- .../KartiasLabyrinth/KartiaHelperAdolph.java | 6 +- .../KartiasLabyrinth/KartiaSupportTroop.java | 4 +- .../ai/areas/PlainsOfDion/PlainsOfDion.java | 4 +- .../ai/areas/PrimevalIsle/PrimevalIsle.java | 4 +- .../ai/areas/TalkingIsland/BoyAndGirl.java | 9 +- .../scripts/ai/areas/TalkingIsland/Devno.java | 7 +- .../scripts/ai/areas/TalkingIsland/Eleve.java | 6 +- .../ai/areas/TalkingIsland/Handermonkey.java | 4 +- .../ai/areas/TalkingIsland/Karonf.java | 6 +- .../ai/areas/TalkingIsland/Marsha.java | 6 +- .../ai/areas/TalkingIsland/Morgan.java | 6 +- .../ai/areas/TalkingIsland/Rubentis.java | 6 +- .../bosses/Frintezza/ScarletVanHalisha.java | 4 +- .../data/scripts/ai/bosses/Tiat/Stage1.java | 4 +- .../scripts/ai/bosses/Valakas/Valakas.java | 4 +- .../data/scripts/ai/others/FleeMonsters.java | 4 +- .../actionhandlers/L2PcInstanceAction.java | 6 +- .../actionhandlers/L2PetInstanceAction.java | 6 +- .../actionhandlers/L2SummonAction.java | 6 +- .../admincommandhandlers/AdminGeodata.java | 22 +- .../admincommandhandlers/AdminPathNode.java | 65 +- .../admincommandhandlers/AdminServerInfo.java | 2 +- .../admincommandhandlers/AdminTeleport.java | 4 +- .../admincommandhandlers/AdminZones.java | 4 +- .../handlers/effecthandlers/Blink.java | 4 +- .../scripts/handlers/effecthandlers/Fear.java | 4 +- .../handlers/effecthandlers/FlyAway.java | 4 +- .../handlers/effecthandlers/KnockBack.java | 4 +- .../handlers/effecthandlers/PullBack.java | 4 +- .../effecthandlers/TeleportToSummon.java | 4 +- .../effecthandlers/TeleportToTarget.java | 4 +- .../OpBlinkSkillCondition.java | 4 +- .../handlers/targethandlers/Enemy.java | 4 +- .../handlers/targethandlers/EnemyNot.java | 6 +- .../handlers/targethandlers/EnemyOnly.java | 4 +- .../handlers/targethandlers/Ground.java | 4 +- .../handlers/targethandlers/NpcBody.java | 4 +- .../handlers/targethandlers/PcBody.java | 4 +- .../handlers/targethandlers/Target.java | 6 +- .../targethandlers/affectscope/Fan.java | 4 +- .../targethandlers/affectscope/FanPB.java | 4 +- .../affectscope/PointBlank.java | 4 +- .../targethandlers/affectscope/Range.java | 4 +- .../targethandlers/affectscope/RingRange.java | 4 +- .../targethandlers/affectscope/Square.java | 4 +- .../targethandlers/affectscope/SquarePB.java | 4 +- .../Q10753_WindsOfFateChoices.java | 4 +- .../java/com/l2jmobius/Config.java | 84 +- .../com/l2jmobius/commons/util/MathUtil.java | 11 + .../com/l2jmobius/gameserver/GameServer.java | 11 +- .../gameserver/ai/FriendlyNpcAI.java | 8 +- .../gameserver/ai/L2AttackableAI.java | 14 +- .../gameserver/ai/L2CharacterAI.java | 4 +- .../gameserver/ai/L2FortSiegeGuardAI.java | 12 +- .../gameserver/ai/L2SiegeGuardAI.java | 12 +- .../l2jmobius/gameserver/ai/L2SummonAI.java | 4 +- .../gameserver/data/xml/impl/DoorData.java | 4 +- .../l2jmobius/gameserver/geodata/GeoData.java | 626 -------- .../gameserver/geodata/geodriver/Cell.java | 48 - .../geodata/geodriver/GeoDriver.java | 189 --- .../gameserver/geodata/geodriver/IBlock.java | 42 - .../gameserver/geodata/geodriver/IRegion.java | 47 - .../geodriver/blocks/ComplexBlock.java | 79 - .../geodata/geodriver/blocks/FlatBlock.java | 58 - .../geodriver/blocks/MultilayerBlock.java | 186 --- .../geodata/geodriver/regions/NullRegion.java | 57 - .../geodata/geodriver/regions/Region.java | 98 -- .../geodata/pathfinding/AbstractNode.java | 87 -- .../geodata/pathfinding/PathFinding.java | 211 --- .../pathfinding/cellnodes/CellNode.java | 69 - .../pathfinding/cellnodes/CellNodeBuffer.java | 361 ----- .../cellnodes/CellPathFinding.java | 440 ------ .../pathfinding/cellnodes/NodeLoc.java | 184 --- .../geodata/pathfinding/geonodes/GeoNode.java | 62 - .../pathfinding/geonodes/GeoNodeLoc.java | 109 -- .../pathfinding/geonodes/GeoPathFinding.java | 470 ------ .../pathfinding/utils/BinaryNodeHeap.java | 124 -- .../gameserver/geoengine/GeoEngine.java | 1311 +++++++++++++++++ .../geoengine/GeoEnginePathfinding.java | 308 ++++ .../gameserver/geoengine/geodata/ABlock.java | 197 +++ .../geoengine/geodata/BlockComplex.java | 252 ++++ .../geodata/BlockComplexDynamic.java | 255 ++++ .../geoengine/geodata/BlockFlat.java | 177 +++ .../geoengine/geodata/BlockMultilayer.java | 466 ++++++ .../geodata/BlockMultilayerDynamic.java | 312 ++++ .../geoengine/geodata/BlockNull.java | 150 ++ .../geoengine/geodata/GeoFormat.java | 26 +- .../geoengine/geodata/GeoLocation.java | 67 + .../geoengine/geodata/GeoStructure.java | 75 + .../geoengine/geodata/IBlockDynamic.java | 35 + .../geoengine/geodata/IGeoObject.java | 53 + .../geoengine/pathfinding/Node.java | 87 ++ .../geoengine/pathfinding/NodeBuffer.java | 351 +++++ .../instancemanager/WarpedSpaceManager.java | 6 - .../l2jmobius/gameserver/model/Fishing.java | 10 +- .../l2jmobius/gameserver/model/L2Spawn.java | 4 +- .../l2jmobius/gameserver/model/Location.java | 6 +- .../gameserver/model/actor/L2Character.java | 155 +- .../gameserver/model/actor/L2Tower.java | 4 +- .../model/actor/instance/L2PcInstance.java | 4 +- .../model/items/instance/L2ItemInstance.java | 4 +- .../gameserver/model/skills/SkillCaster.java | 4 +- .../model/skills/SkillChannelizer.java | 4 +- .../model/zone/form/ZoneCuboid.java | 4 +- .../model/zone/form/ZoneCylinder.java | 4 +- .../gameserver/model/zone/form/ZoneNPoly.java | 4 +- .../l2jmobius/gameserver/util/GeoUtils.java | 66 +- .../geodataconverter/GeoDataConverter.java | 375 +++++ L2J_Mobius_Ertheia/readme.txt | 2 +- L2J_Mobius_Helios/build.xml | 1 + .../dist/game/GeoDataConverter.bat | 6 + .../dist/game/GeoDataConverter.sh | 4 + .../dist/game/config/AdminCommands.xml | 6 +- .../dist/game/config/GeoData.ini | 75 - .../dist/game/config/GeoEngine.ini | 55 + .../dist/game/data/geodata/Readme.txt | 52 +- .../dist/game/data/pathnode/Readme.txt | 11 - .../FourSepulchers/FourSepulchers.java | 4 +- .../KartiasLabyrinth/KartiaHelperAdolph.java | 6 +- .../KartiasLabyrinth/KartiaSupportTroop.java | 4 +- .../ai/areas/PlainsOfDion/PlainsOfDion.java | 4 +- .../ai/areas/PrimevalIsle/PrimevalIsle.java | 4 +- .../ai/areas/TalkingIsland/BoyAndGirl.java | 9 +- .../scripts/ai/areas/TalkingIsland/Devno.java | 7 +- .../scripts/ai/areas/TalkingIsland/Eleve.java | 6 +- .../ai/areas/TalkingIsland/Handermonkey.java | 4 +- .../ai/areas/TalkingIsland/Karonf.java | 6 +- .../ai/areas/TalkingIsland/Marsha.java | 6 +- .../ai/areas/TalkingIsland/Morgan.java | 6 +- .../ai/areas/TalkingIsland/Rubentis.java | 6 +- .../bosses/Frintezza/ScarletVanHalisha.java | 4 +- .../data/scripts/ai/bosses/Tiat/Stage1.java | 4 +- .../scripts/ai/bosses/Valakas/Valakas.java | 4 +- .../data/scripts/ai/others/FleeMonsters.java | 4 +- .../actionhandlers/L2PcInstanceAction.java | 6 +- .../actionhandlers/L2PetInstanceAction.java | 6 +- .../actionhandlers/L2SummonAction.java | 6 +- .../admincommandhandlers/AdminGeodata.java | 22 +- .../admincommandhandlers/AdminPathNode.java | 65 +- .../admincommandhandlers/AdminServerInfo.java | 2 +- .../admincommandhandlers/AdminTeleport.java | 4 +- .../admincommandhandlers/AdminZones.java | 4 +- .../handlers/effecthandlers/Blink.java | 4 +- .../scripts/handlers/effecthandlers/Fear.java | 4 +- .../handlers/effecthandlers/FlyAway.java | 4 +- .../handlers/effecthandlers/KnockBack.java | 4 +- .../handlers/effecthandlers/PullBack.java | 4 +- .../effecthandlers/TeleportToSummon.java | 4 +- .../effecthandlers/TeleportToTarget.java | 4 +- .../OpBlinkSkillCondition.java | 4 +- .../handlers/targethandlers/Enemy.java | 4 +- .../handlers/targethandlers/EnemyNot.java | 6 +- .../handlers/targethandlers/EnemyOnly.java | 4 +- .../handlers/targethandlers/Ground.java | 4 +- .../handlers/targethandlers/NpcBody.java | 4 +- .../handlers/targethandlers/PcBody.java | 4 +- .../handlers/targethandlers/Target.java | 6 +- .../targethandlers/affectscope/Fan.java | 4 +- .../targethandlers/affectscope/FanPB.java | 4 +- .../affectscope/PointBlank.java | 4 +- .../targethandlers/affectscope/Range.java | 4 +- .../targethandlers/affectscope/RingRange.java | 4 +- .../targethandlers/affectscope/Square.java | 4 +- .../targethandlers/affectscope/SquarePB.java | 4 +- .../Q10753_WindsOfFateChoices.java | 4 +- .../java/com/l2jmobius/Config.java | 84 +- .../com/l2jmobius/commons/util/MathUtil.java | 11 + .../com/l2jmobius/gameserver/GameServer.java | 11 +- .../gameserver/ai/FriendlyNpcAI.java | 8 +- .../gameserver/ai/L2AttackableAI.java | 14 +- .../gameserver/ai/L2CharacterAI.java | 4 +- .../gameserver/ai/L2FortSiegeGuardAI.java | 12 +- .../gameserver/ai/L2SiegeGuardAI.java | 12 +- .../l2jmobius/gameserver/ai/L2SummonAI.java | 4 +- .../gameserver/data/xml/impl/DoorData.java | 4 +- .../l2jmobius/gameserver/geodata/GeoData.java | 626 -------- .../gameserver/geodata/geodriver/Cell.java | 48 - .../geodata/geodriver/GeoDriver.java | 189 --- .../gameserver/geodata/geodriver/IBlock.java | 42 - .../gameserver/geodata/geodriver/IRegion.java | 47 - .../geodriver/blocks/ComplexBlock.java | 79 - .../geodata/geodriver/blocks/FlatBlock.java | 58 - .../geodriver/blocks/MultilayerBlock.java | 186 --- .../geodata/geodriver/regions/NullRegion.java | 57 - .../geodata/geodriver/regions/Region.java | 98 -- .../geodata/pathfinding/AbstractNode.java | 87 -- .../geodata/pathfinding/PathFinding.java | 211 --- .../pathfinding/cellnodes/CellNode.java | 69 - .../pathfinding/cellnodes/CellNodeBuffer.java | 361 ----- .../cellnodes/CellPathFinding.java | 440 ------ .../pathfinding/cellnodes/NodeLoc.java | 184 --- .../geodata/pathfinding/geonodes/GeoNode.java | 62 - .../pathfinding/geonodes/GeoNodeLoc.java | 109 -- .../pathfinding/geonodes/GeoPathFinding.java | 470 ------ .../pathfinding/utils/BinaryNodeHeap.java | 124 -- .../gameserver/geoengine/GeoEngine.java | 1311 +++++++++++++++++ .../geoengine/GeoEnginePathfinding.java | 308 ++++ .../gameserver/geoengine/geodata/ABlock.java | 197 +++ .../geoengine/geodata/BlockComplex.java | 252 ++++ .../geodata/BlockComplexDynamic.java | 255 ++++ .../geoengine/geodata/BlockFlat.java | 177 +++ .../geoengine/geodata/BlockMultilayer.java | 466 ++++++ .../geodata/BlockMultilayerDynamic.java | 312 ++++ .../geoengine/geodata/BlockNull.java | 150 ++ .../geoengine/geodata/GeoFormat.java | 28 +- .../geoengine/geodata/GeoLocation.java | 67 + .../geoengine/geodata/GeoStructure.java | 75 + .../geoengine/geodata/IBlockDynamic.java | 35 + .../geoengine/geodata/IGeoObject.java | 53 + .../geoengine/pathfinding/Node.java | 87 ++ .../geoengine/pathfinding/NodeBuffer.java | 351 +++++ .../instancemanager/WarpedSpaceManager.java | 6 - .../l2jmobius/gameserver/model/Fishing.java | 10 +- .../l2jmobius/gameserver/model/L2Spawn.java | 4 +- .../l2jmobius/gameserver/model/Location.java | 6 +- .../gameserver/model/actor/L2Character.java | 155 +- .../gameserver/model/actor/L2Tower.java | 4 +- .../model/actor/instance/L2PcInstance.java | 4 +- .../model/items/instance/L2ItemInstance.java | 4 +- .../gameserver/model/skills/SkillCaster.java | 4 +- .../model/skills/SkillChannelizer.java | 4 +- .../model/zone/form/ZoneCuboid.java | 4 +- .../model/zone/form/ZoneCylinder.java | 4 +- .../gameserver/model/zone/form/ZoneNPoly.java | 4 +- .../l2jmobius/gameserver/util/GeoUtils.java | 66 +- .../geodataconverter/GeoDataConverter.java | 375 +++++ L2J_Mobius_HighFive/build.xml | 1 + .../dist/game/GeoDataConverter.bat | 6 + .../dist/game/GeoDataConverter.sh | 4 + .../dist/game/config/AdminCommands.xml | 6 +- .../dist/game/config/GeoData.ini | 75 - .../dist/game/config/GeoEngine.ini | 55 + .../dist/game/data/geodata/Readme.txt | 52 +- .../dist/game/data/pathnode/Readme.txt | 11 - .../ai/group_template/AltarsOfSacrifice.java | 4 +- .../ai/group_template/FleeMonsters.java | 4 +- .../ai/group_template/PlainsOfDion.java | 4 +- .../ai/group_template/PrimevalIsle.java | 4 +- .../ai/individual/ScarletVanHalisha.java | 4 +- .../data/scripts/ai/individual/Valakas.java | 4 +- .../ai/npc/ForgeOfTheGods/TarBeetleSpawn.java | 4 +- .../handlers/actionhandlers/L2NpcAction.java | 6 +- .../actionhandlers/L2PcInstanceAction.java | 10 +- .../actionhandlers/L2PetInstanceAction.java | 6 +- .../actionhandlers/L2SummonAction.java | 6 +- .../admincommandhandlers/AdminGeodata.java | 22 +- .../admincommandhandlers/AdminPathNode.java | 65 +- .../admincommandhandlers/AdminServerInfo.java | 2 +- .../admincommandhandlers/AdminZones.java | 4 +- .../handlers/effecthandlers/Blink.java | 4 +- .../handlers/effecthandlers/EnemyCharge.java | 4 +- .../handlers/effecthandlers/Fishing.java | 11 +- .../effecthandlers/TeleportToTarget.java | 4 +- .../handlers/effecthandlers/ThrowUp.java | 4 +- .../handlers/targethandlers/AreaFriendly.java | 4 +- .../CrystalCaverns/CrystalCaverns.java | 4 +- .../FinalEmperialTomb/FinalEmperialTomb.java | 4 +- .../java/com/l2jmobius/Config.java | 75 +- .../com/l2jmobius/gameserver/GameServer.java | 11 +- .../gameserver/ai/L2AttackableAI.java | 94 +- .../gameserver/ai/L2CharacterAI.java | 16 +- .../gameserver/ai/L2FortSiegeGuardAI.java | 10 +- .../gameserver/ai/L2SiegeGuardAI.java | 12 +- .../l2jmobius/gameserver/ai/L2SummonAI.java | 7 +- .../gameserver/data/xml/impl/DoorData.java | 4 +- .../l2jmobius/gameserver/geodata/GeoData.java | 578 -------- .../gameserver/geodata/geodriver/Cell.java | 48 - .../geodata/geodriver/GeoDriver.java | 162 -- .../gameserver/geodata/geodriver/IBlock.java | 42 - .../gameserver/geodata/geodriver/IRegion.java | 47 - .../geodriver/blocks/ComplexBlock.java | 79 - .../geodata/geodriver/blocks/FlatBlock.java | 58 - .../geodriver/blocks/MultilayerBlock.java | 186 --- .../geodata/geodriver/regions/NullRegion.java | 57 - .../geodata/geodriver/regions/Region.java | 98 -- .../geodata/pathfinding/AbstractNode.java | 84 -- .../geodata/pathfinding/PathFinding.java | 204 --- .../pathfinding/cellnodes/CellNode.java | 69 - .../pathfinding/cellnodes/CellNodeBuffer.java | 335 ----- .../cellnodes/CellPathFinding.java | 429 ------ .../pathfinding/cellnodes/NodeLoc.java | 167 --- .../geodata/pathfinding/geonodes/GeoNode.java | 60 - .../pathfinding/geonodes/GeoNodeLoc.java | 103 -- .../pathfinding/geonodes/GeoPathFinding.java | 473 ------ .../pathfinding/utils/BinaryNodeHeap.java | 124 -- .../pathfinding/utils/FastNodeList.java | 49 - .../gameserver/geoengine/GeoEngine.java | 1294 ++++++++++++++++ .../geoengine/GeoEnginePathfinding.java | 307 ++++ .../gameserver/geoengine/geodata/ABlock.java | 197 +++ .../geoengine/geodata/BlockComplex.java | 252 ++++ .../geodata/BlockComplexDynamic.java | 255 ++++ .../geoengine/geodata/BlockFlat.java | 177 +++ .../geoengine/geodata/BlockMultilayer.java | 466 ++++++ .../geodata/BlockMultilayerDynamic.java | 312 ++++ .../geoengine/geodata/BlockNull.java | 150 ++ .../geoengine/geodata/GeoFormat.java | 72 +- .../geoengine/geodata/GeoLocation.java | 67 + .../geoengine/geodata/GeoStructure.java | 75 + .../geoengine/geodata/IBlockDynamic.java | 35 + .../geoengine/geodata/IGeoObject.java | 53 + .../geoengine/pathfinding/Node.java | 87 ++ .../geoengine/pathfinding/NodeBuffer.java | 351 +++++ .../l2jmobius/gameserver/model/L2Spawn.java | 6 +- .../l2jmobius/gameserver/model/Location.java | 6 +- .../gameserver/model/actor/L2Character.java | 28 +- .../gameserver/model/actor/L2Summon.java | 4 +- .../gameserver/model/actor/L2Tower.java | 4 +- .../model/actor/instance/L2PcInstance.java | 57 +- .../model/items/instance/L2ItemInstance.java | 4 +- .../gameserver/model/skills/Skill.java | 4 +- .../model/skills/SkillChannelizer.java | 4 +- .../model/zone/form/ZoneCuboid.java | 4 +- .../model/zone/form/ZoneCylinder.java | 4 +- .../gameserver/model/zone/form/ZoneNPoly.java | 4 +- .../l2jmobius/gameserver/util/GeoUtils.java | 94 +- .../l2jmobius/gameserver/util/MathUtil.java | 94 ++ .../l2jmobius/gameserver/util/StringUtil.java | 276 ++++ .../com/l2jmobius/gameserver/util/Util.java | 4 +- .../geodataconverter/GeoDataConverter.java | 375 +++++ L2J_Mobius_HighFive/readme.txt | 3 + L2J_Mobius_Underground/build.xml | 1 + .../dist/game/GeoDataConverter.bat | 6 + .../dist/game/GeoDataConverter.sh | 4 + .../dist/game/config/AdminCommands.xml | 6 +- .../dist/game/config/GeoData.ini | 75 - .../dist/game/config/GeoEngine.ini | 55 + .../dist/game/data/geodata/Readme.txt | 52 +- .../dist/game/data/pathnode/Readme.txt | 11 - .../FourSepulchers/FourSepulchers.java | 4 +- .../KartiasLabyrinth/KartiaHelperAdolph.java | 6 +- .../KartiasLabyrinth/KartiaSupportTroop.java | 4 +- .../ai/areas/PlainsOfDion/PlainsOfDion.java | 4 +- .../ai/areas/PrimevalIsle/PrimevalIsle.java | 4 +- .../ai/areas/TalkingIsland/BoyAndGirl.java | 9 +- .../scripts/ai/areas/TalkingIsland/Devno.java | 7 +- .../scripts/ai/areas/TalkingIsland/Eleve.java | 6 +- .../ai/areas/TalkingIsland/Handermonkey.java | 4 +- .../ai/areas/TalkingIsland/Karonf.java | 6 +- .../ai/areas/TalkingIsland/Marsha.java | 6 +- .../ai/areas/TalkingIsland/Morgan.java | 6 +- .../ai/areas/TalkingIsland/Rubentis.java | 6 +- .../bosses/Frintezza/ScarletVanHalisha.java | 4 +- .../data/scripts/ai/bosses/Tiat/Stage1.java | 4 +- .../scripts/ai/bosses/Valakas/Valakas.java | 4 +- .../data/scripts/ai/others/FleeMonsters.java | 4 +- .../actionhandlers/L2PcInstanceAction.java | 6 +- .../actionhandlers/L2PetInstanceAction.java | 6 +- .../actionhandlers/L2SummonAction.java | 6 +- .../admincommandhandlers/AdminGeodata.java | 22 +- .../admincommandhandlers/AdminPathNode.java | 65 +- .../admincommandhandlers/AdminServerInfo.java | 2 +- .../admincommandhandlers/AdminTeleport.java | 4 +- .../admincommandhandlers/AdminZones.java | 4 +- .../handlers/effecthandlers/Blink.java | 4 +- .../scripts/handlers/effecthandlers/Fear.java | 4 +- .../handlers/effecthandlers/FlyAway.java | 4 +- .../handlers/effecthandlers/KnockBack.java | 4 +- .../handlers/effecthandlers/PullBack.java | 4 +- .../effecthandlers/TeleportToSummon.java | 4 +- .../effecthandlers/TeleportToTarget.java | 4 +- .../OpBlinkSkillCondition.java | 4 +- .../handlers/targethandlers/Enemy.java | 4 +- .../handlers/targethandlers/EnemyNot.java | 6 +- .../handlers/targethandlers/EnemyOnly.java | 4 +- .../handlers/targethandlers/Ground.java | 4 +- .../handlers/targethandlers/NpcBody.java | 4 +- .../handlers/targethandlers/PcBody.java | 4 +- .../handlers/targethandlers/Target.java | 6 +- .../targethandlers/affectscope/Fan.java | 4 +- .../targethandlers/affectscope/FanPB.java | 4 +- .../affectscope/PointBlank.java | 4 +- .../targethandlers/affectscope/Range.java | 4 +- .../targethandlers/affectscope/RingRange.java | 4 +- .../targethandlers/affectscope/Square.java | 4 +- .../targethandlers/affectscope/SquarePB.java | 4 +- .../Q10753_WindsOfFateChoices.java | 4 +- .../java/com/l2jmobius/Config.java | 84 +- .../com/l2jmobius/commons/util/MathUtil.java | 11 + .../com/l2jmobius/gameserver/GameServer.java | 11 +- .../gameserver/ai/FriendlyNpcAI.java | 8 +- .../gameserver/ai/L2AttackableAI.java | 14 +- .../gameserver/ai/L2CharacterAI.java | 4 +- .../gameserver/ai/L2FortSiegeGuardAI.java | 12 +- .../gameserver/ai/L2SiegeGuardAI.java | 12 +- .../l2jmobius/gameserver/ai/L2SummonAI.java | 4 +- .../gameserver/data/xml/impl/DoorData.java | 4 +- .../l2jmobius/gameserver/geodata/GeoData.java | 626 -------- .../gameserver/geodata/geodriver/Cell.java | 48 - .../geodata/geodriver/GeoDriver.java | 189 --- .../gameserver/geodata/geodriver/IBlock.java | 42 - .../gameserver/geodata/geodriver/IRegion.java | 47 - .../geodriver/blocks/ComplexBlock.java | 79 - .../geodata/geodriver/blocks/FlatBlock.java | 58 - .../geodriver/blocks/MultilayerBlock.java | 186 --- .../geodata/geodriver/regions/NullRegion.java | 57 - .../geodata/geodriver/regions/Region.java | 98 -- .../geodata/pathfinding/AbstractNode.java | 87 -- .../geodata/pathfinding/AbstractNodeLoc.java | 33 - .../geodata/pathfinding/PathFinding.java | 211 --- .../pathfinding/cellnodes/CellNode.java | 69 - .../pathfinding/cellnodes/CellNodeBuffer.java | 361 ----- .../cellnodes/CellPathFinding.java | 440 ------ .../pathfinding/cellnodes/NodeLoc.java | 184 --- .../geodata/pathfinding/geonodes/GeoNode.java | 62 - .../pathfinding/geonodes/GeoNodeLoc.java | 109 -- .../pathfinding/geonodes/GeoPathFinding.java | 470 ------ .../pathfinding/utils/BinaryNodeHeap.java | 124 -- .../gameserver/geoengine/GeoEngine.java | 1311 +++++++++++++++++ .../geoengine/GeoEnginePathfinding.java | 308 ++++ .../gameserver/geoengine/geodata/ABlock.java | 197 +++ .../geoengine/geodata/BlockComplex.java | 252 ++++ .../geodata/BlockComplexDynamic.java | 255 ++++ .../geoengine/geodata/BlockFlat.java | 177 +++ .../geoengine/geodata/BlockMultilayer.java | 466 ++++++ .../geodata/BlockMultilayerDynamic.java | 312 ++++ .../geoengine/geodata/BlockNull.java | 150 ++ .../geoengine/geodata/GeoFormat.java | 39 + .../geoengine/geodata/GeoLocation.java | 67 + .../geoengine/geodata/GeoStructure.java | 75 + .../geoengine/geodata/IBlockDynamic.java | 35 + .../geoengine/geodata/IGeoObject.java | 53 + .../geoengine/pathfinding/Node.java | 87 ++ .../geoengine/pathfinding/NodeBuffer.java | 351 +++++ .../instancemanager/WarpedSpaceManager.java | 6 - .../l2jmobius/gameserver/model/Fishing.java | 10 +- .../l2jmobius/gameserver/model/L2Spawn.java | 4 +- .../l2jmobius/gameserver/model/Location.java | 6 +- .../gameserver/model/actor/L2Character.java | 155 +- .../gameserver/model/actor/L2Tower.java | 4 +- .../model/actor/instance/L2PcInstance.java | 4 +- .../model/items/instance/L2ItemInstance.java | 4 +- .../gameserver/model/skills/SkillCaster.java | 4 +- .../model/skills/SkillChannelizer.java | 4 +- .../model/zone/form/ZoneCuboid.java | 4 +- .../model/zone/form/ZoneCylinder.java | 4 +- .../gameserver/model/zone/form/ZoneNPoly.java | 4 +- .../l2jmobius/gameserver/util/GeoUtils.java | 66 +- .../geodataconverter/GeoDataConverter.java | 375 +++++ L2J_Mobius_Underground/readme.txt | 2 +- 549 files changed, 25017 insertions(+), 20141 deletions(-) create mode 100644 L2J_Mobius_Classic/dist/game/GeoDataConverter.bat create mode 100644 L2J_Mobius_Classic/dist/game/GeoDataConverter.sh delete mode 100644 L2J_Mobius_Classic/dist/game/config/GeoData.ini create mode 100644 L2J_Mobius_Classic/dist/game/config/GeoEngine.ini delete mode 100644 L2J_Mobius_Classic/dist/game/data/pathnode/Readme.txt delete mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/GeoData.java delete mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/Cell.java delete mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/GeoDriver.java delete mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/IBlock.java delete mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/IRegion.java delete mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/ComplexBlock.java delete mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/FlatBlock.java delete mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/MultilayerBlock.java delete mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/regions/NullRegion.java delete mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/regions/Region.java delete mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNode.java delete mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/PathFinding.java delete mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNode.java delete mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNodeBuffer.java delete mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellPathFinding.java delete mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/NodeLoc.java delete mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNode.java delete mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNodeLoc.java delete mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoPathFinding.java delete mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/utils/BinaryNodeHeap.java create mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java create mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/GeoEnginePathfinding.java create mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/ABlock.java create mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplex.java create mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplexDynamic.java create mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/BlockFlat.java create mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayer.java create mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayerDynamic.java create mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/BlockNull.java rename L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNodeLoc.java => L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/GeoFormat.java (67%) create mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/GeoLocation.java create mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/GeoStructure.java create mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/IBlockDynamic.java create mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/IGeoObject.java create mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/pathfinding/Node.java create mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/pathfinding/NodeBuffer.java create mode 100644 L2J_Mobius_Classic/java/com/l2jmobius/tools/geodataconverter/GeoDataConverter.java create mode 100644 L2J_Mobius_Ertheia/dist/game/GeoDataConverter.bat create mode 100644 L2J_Mobius_Ertheia/dist/game/GeoDataConverter.sh delete mode 100644 L2J_Mobius_Ertheia/dist/game/config/GeoData.ini create mode 100644 L2J_Mobius_Ertheia/dist/game/config/GeoEngine.ini delete mode 100644 L2J_Mobius_Ertheia/dist/game/data/pathnode/Readme.txt delete mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/GeoData.java delete mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/Cell.java delete mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/GeoDriver.java delete mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/IBlock.java delete mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/IRegion.java delete mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/ComplexBlock.java delete mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/FlatBlock.java delete mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/MultilayerBlock.java delete mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/regions/NullRegion.java delete mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/regions/Region.java delete mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNode.java delete mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/PathFinding.java delete mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNode.java delete mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNodeBuffer.java delete mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellPathFinding.java delete mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/NodeLoc.java delete mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNode.java delete mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNodeLoc.java delete mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoPathFinding.java delete mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/utils/BinaryNodeHeap.java create mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java create mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/GeoEnginePathfinding.java create mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/ABlock.java create mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplex.java create mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplexDynamic.java create mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/BlockFlat.java create mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayer.java create mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayerDynamic.java create mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/BlockNull.java rename L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNodeLoc.java => L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/GeoFormat.java (67%) create mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/GeoLocation.java create mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/GeoStructure.java create mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/IBlockDynamic.java create mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/IGeoObject.java create mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/pathfinding/Node.java create mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/pathfinding/NodeBuffer.java create mode 100644 L2J_Mobius_Ertheia/java/com/l2jmobius/tools/geodataconverter/GeoDataConverter.java create mode 100644 L2J_Mobius_Helios/dist/game/GeoDataConverter.bat create mode 100644 L2J_Mobius_Helios/dist/game/GeoDataConverter.sh delete mode 100644 L2J_Mobius_Helios/dist/game/config/GeoData.ini create mode 100644 L2J_Mobius_Helios/dist/game/config/GeoEngine.ini delete mode 100644 L2J_Mobius_Helios/dist/game/data/pathnode/Readme.txt delete mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/GeoData.java delete mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/Cell.java delete mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/GeoDriver.java delete mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/IBlock.java delete mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/IRegion.java delete mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/ComplexBlock.java delete mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/FlatBlock.java delete mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/MultilayerBlock.java delete mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/regions/NullRegion.java delete mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/regions/Region.java delete mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNode.java delete mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/PathFinding.java delete mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNode.java delete mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNodeBuffer.java delete mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellPathFinding.java delete mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/NodeLoc.java delete mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNode.java delete mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNodeLoc.java delete mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoPathFinding.java delete mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/utils/BinaryNodeHeap.java create mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java create mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/GeoEnginePathfinding.java create mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/ABlock.java create mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplex.java create mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplexDynamic.java create mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/BlockFlat.java create mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayer.java create mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayerDynamic.java create mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/BlockNull.java rename L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNodeLoc.java => L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/GeoFormat.java (67%) create mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/GeoLocation.java create mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/GeoStructure.java create mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/IBlockDynamic.java create mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/IGeoObject.java create mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/pathfinding/Node.java create mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/pathfinding/NodeBuffer.java create mode 100644 L2J_Mobius_Helios/java/com/l2jmobius/tools/geodataconverter/GeoDataConverter.java create mode 100644 L2J_Mobius_HighFive/dist/game/GeoDataConverter.bat create mode 100644 L2J_Mobius_HighFive/dist/game/GeoDataConverter.sh delete mode 100644 L2J_Mobius_HighFive/dist/game/config/GeoData.ini create mode 100644 L2J_Mobius_HighFive/dist/game/config/GeoEngine.ini delete mode 100644 L2J_Mobius_HighFive/dist/game/data/pathnode/Readme.txt delete mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/GeoData.java delete mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/Cell.java delete mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/GeoDriver.java delete mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/IBlock.java delete mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/IRegion.java delete mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/ComplexBlock.java delete mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/FlatBlock.java delete mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/MultilayerBlock.java delete mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/regions/NullRegion.java delete mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/regions/Region.java delete mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNode.java delete mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/PathFinding.java delete mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNode.java delete mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNodeBuffer.java delete mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellPathFinding.java delete mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/NodeLoc.java delete mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNode.java delete mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNodeLoc.java delete mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoPathFinding.java delete mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/utils/BinaryNodeHeap.java delete mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/utils/FastNodeList.java create mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java create mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/GeoEnginePathfinding.java create mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/ABlock.java create mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplex.java create mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplexDynamic.java create mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/BlockFlat.java create mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayer.java create mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayerDynamic.java create mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/BlockNull.java rename L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNodeLoc.java => L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/GeoFormat.java (67%) create mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/GeoLocation.java create mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/GeoStructure.java create mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/IBlockDynamic.java create mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/IGeoObject.java create mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/pathfinding/Node.java create mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/pathfinding/NodeBuffer.java create mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/util/MathUtil.java create mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/util/StringUtil.java create mode 100644 L2J_Mobius_HighFive/java/com/l2jmobius/tools/geodataconverter/GeoDataConverter.java create mode 100644 L2J_Mobius_Underground/dist/game/GeoDataConverter.bat create mode 100644 L2J_Mobius_Underground/dist/game/GeoDataConverter.sh delete mode 100644 L2J_Mobius_Underground/dist/game/config/GeoData.ini create mode 100644 L2J_Mobius_Underground/dist/game/config/GeoEngine.ini delete mode 100644 L2J_Mobius_Underground/dist/game/data/pathnode/Readme.txt delete mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/GeoData.java delete mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/Cell.java delete mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/GeoDriver.java delete mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/IBlock.java delete mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/IRegion.java delete mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/ComplexBlock.java delete mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/FlatBlock.java delete mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/MultilayerBlock.java delete mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/regions/NullRegion.java delete mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/regions/Region.java delete mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNode.java delete mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNodeLoc.java delete mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/PathFinding.java delete mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNode.java delete mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNodeBuffer.java delete mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellPathFinding.java delete mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/NodeLoc.java delete mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNode.java delete mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNodeLoc.java delete mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoPathFinding.java delete mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/utils/BinaryNodeHeap.java create mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java create mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/GeoEnginePathfinding.java create mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/ABlock.java create mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplex.java create mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplexDynamic.java create mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/BlockFlat.java create mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayer.java create mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayerDynamic.java create mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/BlockNull.java create mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/GeoFormat.java create mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/GeoLocation.java create mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/GeoStructure.java create mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/IBlockDynamic.java create mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/IGeoObject.java create mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/pathfinding/Node.java create mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/pathfinding/NodeBuffer.java create mode 100644 L2J_Mobius_Underground/java/com/l2jmobius/tools/geodataconverter/GeoDataConverter.java diff --git a/L2J_Mobius_Classic/build.xml b/L2J_Mobius_Classic/build.xml index 25920242f5..253d370018 100644 --- a/L2J_Mobius_Classic/build.xml +++ b/L2J_Mobius_Classic/build.xml @@ -74,6 +74,7 @@ + diff --git a/L2J_Mobius_Classic/dist/game/GeoDataConverter.bat b/L2J_Mobius_Classic/dist/game/GeoDataConverter.bat new file mode 100644 index 0000000000..1f199613e9 --- /dev/null +++ b/L2J_Mobius_Classic/dist/game/GeoDataConverter.bat @@ -0,0 +1,6 @@ +@echo off +title L2D geodata converter + +java -Xmx512m -cp ./../libs/*;GameServer.jar com.l2jmobius.tools.geodataconverter.GeoDataConverter + +pause diff --git a/L2J_Mobius_Classic/dist/game/GeoDataConverter.sh b/L2J_Mobius_Classic/dist/game/GeoDataConverter.sh new file mode 100644 index 0000000000..b039beec34 --- /dev/null +++ b/L2J_Mobius_Classic/dist/game/GeoDataConverter.sh @@ -0,0 +1,4 @@ +#! /bin/sh + +java -Xmx512m -cp ./../libs/*;GameServer.jar com.l2jmobius.tools.geodataconverter.GeoDataConverter > log/stdout.log 2>&1 + diff --git a/L2J_Mobius_Classic/dist/game/config/AdminCommands.xml b/L2J_Mobius_Classic/dist/game/config/AdminCommands.xml index 57c5dc031f..ca5e93c5c2 100644 --- a/L2J_Mobius_Classic/dist/game/config/AdminCommands.xml +++ b/L2J_Mobius_Classic/dist/game/config/AdminCommands.xml @@ -410,11 +410,7 @@ - - - - - + diff --git a/L2J_Mobius_Classic/dist/game/config/GeoData.ini b/L2J_Mobius_Classic/dist/game/config/GeoData.ini deleted file mode 100644 index 52ef701461..0000000000 --- a/L2J_Mobius_Classic/dist/game/config/GeoData.ini +++ /dev/null @@ -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 diff --git a/L2J_Mobius_Classic/dist/game/config/GeoEngine.ini b/L2J_Mobius_Classic/dist/game/config/GeoEngine.ini new file mode 100644 index 0000000000..94a0b1ac44 --- /dev/null +++ b/L2J_Mobius_Classic/dist/game/config/GeoEngine.ini @@ -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 diff --git a/L2J_Mobius_Classic/dist/game/data/geodata/Readme.txt b/L2J_Mobius_Classic/dist/game/data/geodata/Readme.txt index bf1f2071aa..8b18814e82 100644 --- a/L2J_Mobius_Classic/dist/game/data/geodata/Readme.txt +++ b/L2J_Mobius_Classic/dist/game/data/geodata/Readme.txt @@ -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 # -# # -##################################################### \ No newline at end of file +############################################## +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. diff --git a/L2J_Mobius_Classic/dist/game/data/pathnode/Readme.txt b/L2J_Mobius_Classic/dist/game/data/pathnode/Readme.txt deleted file mode 100644 index 2dfdaa8aab..0000000000 --- a/L2J_Mobius_Classic/dist/game/data/pathnode/Readme.txt +++ /dev/null @@ -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 # -# # -##################################################### \ No newline at end of file diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/ai/others/FleeMonsters.java b/L2J_Mobius_Classic/dist/game/data/scripts/ai/others/FleeMonsters.java index 7686510117..a57db7027f 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/ai/others/FleeMonsters.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/ai/others/FleeMonsters.java @@ -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; @@ -60,7 +60,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); } diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/ai/others/RandomWalkingGuards.java b/L2J_Mobius_Classic/dist/game/data/scripts/ai/others/RandomWalkingGuards.java index 509004b194..98386c33bf 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/ai/others/RandomWalkingGuards.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/ai/others/RandomWalkingGuards.java @@ -17,7 +17,8 @@ package ai.others; import com.l2jmobius.Config; -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; import com.l2jmobius.gameserver.util.Util; @@ -53,7 +54,8 @@ public class RandomWalkingGuards extends AbstractNpcAI { if (!npc.isInCombat()) { - addMoveToDesire(npc, GeoData.getInstance().moveCheck(npc.getLocation(), Util.getRandomPosition(npc.getSpawn().getLocation(), 0, Config.MAX_DRIFT_RANGE), npc.getInstanceWorld()), 23); + final Location randomLoc = Util.getRandomPosition(npc.getSpawn().getLocation(), 0, Config.MAX_DRIFT_RANGE); + addMoveToDesire(npc, GeoEngine.getInstance().canMoveToTargetLoc(npc.getX(), npc.getY(), npc.getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23); } startQuestTimer("RANDOM_WALK", getRandom(MIN_WALK_DELAY, MAX_WALK_DELAY), npc, null); } diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/actionhandlers/L2PcInstanceAction.java b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/actionhandlers/L2PcInstanceAction.java index eb06ec5594..13902652f4 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/actionhandlers/L2PcInstanceAction.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/actionhandlers/L2PcInstanceAction.java @@ -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); } diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/actionhandlers/L2PetInstanceAction.java b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/actionhandlers/L2PetInstanceAction.java index c21b0e6ca1..5c2fe5e762 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/actionhandlers/L2PetInstanceAction.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/actionhandlers/L2PetInstanceAction.java @@ -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(); diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/actionhandlers/L2SummonAction.java b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/actionhandlers/L2SummonAction.java index b6af1a7ca4..11b1192023 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/actionhandlers/L2SummonAction.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/actionhandlers/L2SummonAction.java @@ -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); } diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/admincommandhandlers/AdminGeodata.java b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/admincommandhandlers/AdminGeodata.java index bfa36a76d5..551e52bbb0 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/admincommandhandlers/AdminGeodata.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/admincommandhandlers/AdminGeodata.java @@ -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."); } diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/admincommandhandlers/AdminPathNode.java b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/admincommandhandlers/AdminPathNode.java index 03b3ca8902..9cb85c282f 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/admincommandhandlers/AdminPathNode.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/admincommandhandlers/AdminPathNode.java @@ -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 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 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; } diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/admincommandhandlers/AdminServerInfo.java b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/admincommandhandlers/AdminServerInfo.java index 6796381333..867836c680 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/admincommandhandlers/AdminServerInfo.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/admincommandhandlers/AdminServerInfo.java @@ -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")); diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/admincommandhandlers/AdminTeleport.java b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/admincommandhandlers/AdminTeleport.java index 1b738a0264..fbf049aae5 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/admincommandhandlers/AdminTeleport.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/admincommandhandlers/AdminTeleport.java @@ -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); } diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/admincommandhandlers/AdminZones.java b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/admincommandhandlers/AdminZones.java index d6949af214..d5baa52a73 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/admincommandhandlers/AdminZones.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/admincommandhandlers/AdminZones.java @@ -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); } diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/effecthandlers/Blink.java b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/effecthandlers/Blink.java index 0e1c1d1aca..db1463c04d 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/effecthandlers/Blink.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/effecthandlers/Blink.java @@ -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)); diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/effecthandlers/Fear.java b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/effecthandlers/Fear.java index 7525c0f5ec..78fc694005 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/effecthandlers/Fear.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/effecthandlers/Fear.java @@ -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); } } diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/effecthandlers/FlyAway.java b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/effecthandlers/FlyAway.java index 1da9965557..a4d5e7f74b 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/effecthandlers/FlyAway.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/effecthandlers/FlyAway.java @@ -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); diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/effecthandlers/KnockBack.java b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/effecthandlers/KnockBack.java index ad73aef663..e2ddb48286 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/effecthandlers/KnockBack.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/effecthandlers/KnockBack.java @@ -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)); diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/effecthandlers/PullBack.java b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/effecthandlers/PullBack.java index 7850b26d5d..07b43c83d3 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/effecthandlers/PullBack.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/effecthandlers/PullBack.java @@ -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); diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/effecthandlers/TeleportToSummon.java b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/effecthandlers/TeleportToSummon.java index 8144305363..bffc2aecce 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/effecthandlers/TeleportToSummon.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/effecthandlers/TeleportToSummon.java @@ -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)); diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/effecthandlers/TeleportToTarget.java b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/effecthandlers/TeleportToTarget.java index 93ffb3174d..81504f196e 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/effecthandlers/TeleportToTarget.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/effecthandlers/TeleportToTarget.java @@ -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)); diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/skillconditionhandlers/OpBlinkSkillCondition.java b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/skillconditionhandlers/OpBlinkSkillCondition.java index 4b33ad31b2..bea71eb6e5 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/skillconditionhandlers/OpBlinkSkillCondition.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/skillconditionhandlers/OpBlinkSkillCondition.java @@ -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()); } } diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/Enemy.java b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/Enemy.java index b16408fba4..91fc781e3f 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/Enemy.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/Enemy.java @@ -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) { diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/EnemyNot.java b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/EnemyNot.java index 005d4e0ee1..00d3d4d8e2 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/EnemyNot.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/EnemyNot.java @@ -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) { diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/EnemyOnly.java b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/EnemyOnly.java index 2f5a79d6f5..5815598285 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/EnemyOnly.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/EnemyOnly.java @@ -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) { diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/Ground.java b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/Ground.java index f3b38dcf71..280f19d239 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/Ground.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/Ground.java @@ -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) { diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/NpcBody.java b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/NpcBody.java index 699fa269c7..7f46507e5b 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/NpcBody.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/NpcBody.java @@ -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) { diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/PcBody.java b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/PcBody.java index 77a9c9edd3..0ef234b8ac 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/PcBody.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/PcBody.java @@ -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) { diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/Target.java b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/Target.java index b388976172..f8456ed9f9 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/Target.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/Target.java @@ -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) { diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/affectscope/Fan.java b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/affectscope/Fan.java index 2487c40d5e..59b2d086d5 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/affectscope/Fan.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/affectscope/Fan.java @@ -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; } diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/affectscope/FanPB.java b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/affectscope/FanPB.java index ec987c91eb..d6783cff58 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/affectscope/FanPB.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/affectscope/FanPB.java @@ -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; } diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/affectscope/PointBlank.java b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/affectscope/PointBlank.java index d6c63186a2..2f7568dd13 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/affectscope/PointBlank.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/affectscope/PointBlank.java @@ -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; } diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/affectscope/Range.java b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/affectscope/Range.java index 90abebd98f..1d8ccd51e8 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/affectscope/Range.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/affectscope/Range.java @@ -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; } diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/affectscope/RingRange.java b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/affectscope/RingRange.java index 6cbe61fe1c..24c89e82d5 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/affectscope/RingRange.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/affectscope/RingRange.java @@ -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; } diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/affectscope/Square.java b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/affectscope/Square.java index 3225de6245..c39a270d2c 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/affectscope/Square.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/affectscope/Square.java @@ -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; } diff --git a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/affectscope/SquarePB.java b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/affectscope/SquarePB.java index 7ffad78a8f..1f695cc99d 100644 --- a/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/affectscope/SquarePB.java +++ b/L2J_Mobius_Classic/dist/game/data/scripts/handlers/targethandlers/affectscope/SquarePB.java @@ -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; } diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/Config.java b/L2J_Mobius_Classic/java/com/l2jmobius/Config.java index e2c82422f5..4be0bc836a 100644 --- a/L2J_Mobius_Classic/java/com/l2jmobius/Config.java +++ b/L2J_Mobius_Classic/java/com/l2jmobius/Config.java @@ -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 @@ -925,22 +923,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 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 @@ -2256,41 +2258,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); diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/commons/util/MathUtil.java b/L2J_Mobius_Classic/java/com/l2jmobius/commons/util/MathUtil.java index 91dfcc4171..b0867bb70f 100644 --- a/L2J_Mobius_Classic/java/com/l2jmobius/commons/util/MathUtil.java +++ b/L2J_Mobius_Classic/java/com/l2jmobius/commons/util/MathUtil.java @@ -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); + } } diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/GameServer.java index e689672e27..a29b71894c 100644 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/GameServer.java @@ -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; @@ -279,12 +278,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; diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/ai/FriendlyNpcAI.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/ai/FriendlyNpcAI.java index 3eebee88ea..60fa4b1c8a 100644 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/ai/FriendlyNpcAI.java +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/ai/FriendlyNpcAI.java @@ -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()) { diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java index c363c397b5..46287d4e8e 100644 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java @@ -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) diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/ai/L2CharacterAI.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/ai/L2CharacterAI.java index 0d66c4a387..b046658f42 100644 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/ai/L2CharacterAI.java +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/ai/L2CharacterAI.java @@ -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; diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/ai/L2FortSiegeGuardAI.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/ai/L2FortSiegeGuardAI.java index 79f39cb51d..426228ee50 100644 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/ai/L2FortSiegeGuardAI.java +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/ai/L2FortSiegeGuardAI.java @@ -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 diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/ai/L2SiegeGuardAI.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/ai/L2SiegeGuardAI.java index caf5f39544..7cd4bb5dc1 100644 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/ai/L2SiegeGuardAI.java +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/ai/L2SiegeGuardAI.java @@ -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 diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/ai/L2SummonAI.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/ai/L2SummonAI.java index 00c00b8ff9..e29df8102b 100644 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/ai/L2SummonAI.java +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/ai/L2SummonAI.java @@ -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()); } diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/data/xml/impl/DoorData.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/data/xml/impl/DoorData.java index 973c82b4a8..592f3af578 100644 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/data/xml/impl/DoorData.java +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/data/xml/impl/DoorData.java @@ -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); } diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/GeoData.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/GeoData.java deleted file mode 100644 index a44ba3b703..0000000000 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/GeoData.java +++ /dev/null @@ -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 . - */ -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(); - } -} diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/Cell.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/Cell.java deleted file mode 100644 index 4914b1d72e..0000000000 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/Cell.java +++ /dev/null @@ -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 . - */ -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() - { - } -} diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/GeoDriver.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/GeoDriver.java deleted file mode 100644 index 2dc266df46..0000000000 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/GeoDriver.java +++ /dev/null @@ -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 . - */ -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 _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; - } -} diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/IBlock.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/IBlock.java deleted file mode 100644 index 21df97c40d..0000000000 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/IBlock.java +++ /dev/null @@ -1,42 +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 . - */ -package com.l2jmobius.gameserver.geodata.geodriver; - -/** - * @author HorridoJoho - */ -public interface IBlock -{ - int TYPE_FLAT = 0; - int TYPE_COMPLEX = 1; - int TYPE_MULTILAYER = 2; - - /** Cells in a block on the x axis */ - int BLOCK_CELLS_X = 8; - /** Cells in a block on the y axis */ - int BLOCK_CELLS_Y = 8; - /** Cells in a block */ - int BLOCK_CELLS = BLOCK_CELLS_X * BLOCK_CELLS_Y; - - boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe); - - int getNearestZ(int geoX, int geoY, int worldZ); - - int getNextLowerZ(int geoX, int geoY, int worldZ); - - int getNextHigherZ(int geoX, int geoY, int worldZ); -} diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/IRegion.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/IRegion.java deleted file mode 100644 index 3eb23da03e..0000000000 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/IRegion.java +++ /dev/null @@ -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 . - */ -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(); -} diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/ComplexBlock.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/ComplexBlock.java deleted file mode 100644 index 4d6410672e..0000000000 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/ComplexBlock.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/FlatBlock.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/FlatBlock.java deleted file mode 100644 index d5bcff094b..0000000000 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/FlatBlock.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/MultilayerBlock.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/MultilayerBlock.java deleted file mode 100644 index 313131bd5a..0000000000 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/MultilayerBlock.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/regions/NullRegion.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/regions/NullRegion.java deleted file mode 100644 index 60ecac873a..0000000000 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/regions/NullRegion.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/regions/Region.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/regions/Region.java deleted file mode 100644 index d2d02481ed..0000000000 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/geodriver/regions/Region.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNode.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNode.java deleted file mode 100644 index 83d0131910..0000000000 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNode.java +++ /dev/null @@ -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 . - */ -package com.l2jmobius.gameserver.geodata.pathfinding; - -public abstract class AbstractNode -{ - private T _loc; - private AbstractNode _parent; - - public AbstractNode(T loc) - { - _loc = loc; - } - - public void setParent(AbstractNode p) - { - _parent = p; - } - - public AbstractNode 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; - } -} \ No newline at end of file diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/PathFinding.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/PathFinding.java deleted file mode 100644 index e7b3093081..0000000000 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/PathFinding.java +++ /dev/null @@ -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 . - */ -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 findPath(int x, int y, int z, int tx, int ty, int tz, Instance instance, boolean playable); - - // @formatter:off - /* - public List 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 visited = new LinkedList(); - - // List of Nodes to Visit - LinkedList to_visit = new LinkedList(); - 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 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; - } -} diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNode.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNode.java deleted file mode 100644 index f903507286..0000000000 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNode.java +++ /dev/null @@ -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 . - */ -package com.l2jmobius.gameserver.geodata.pathfinding.cellnodes; - -import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNode; - -public class CellNode extends AbstractNode -{ - 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; - } -} \ No newline at end of file diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNodeBuffer.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNodeBuffer.java deleted file mode 100644 index 4eef566183..0000000000 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNodeBuffer.java +++ /dev/null @@ -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 . - */ -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 debugPath() - { - final List 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; - } -} \ No newline at end of file diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellPathFinding.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellPathFinding.java deleted file mode 100644 index 9eb6b0d04a..0000000000 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellPathFinding.java +++ /dev/null @@ -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 . - */ -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 _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 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 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 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 constructPath(AbstractNode node) - { - final LinkedList 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 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(); - } -} diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/NodeLoc.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/NodeLoc.java deleted file mode 100644 index 353dee1d7f..0000000000 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/NodeLoc.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNode.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNode.java deleted file mode 100644 index fb9d7fdd2e..0000000000 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNode.java +++ /dev/null @@ -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 . - */ -package com.l2jmobius.gameserver.geodata.pathfinding.geonodes; - -import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNode; - -/** - * @author -Nemesiss- - */ -public class GeoNode extends AbstractNode -{ - 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); - } - } -} diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNodeLoc.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNodeLoc.java deleted file mode 100644 index 9dabc50452..0000000000 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNodeLoc.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoPathFinding.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoPathFinding.java deleted file mode 100644 index f2d6c87e78..0000000000 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoPathFinding.java +++ /dev/null @@ -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 . - */ -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 _pathNodes = new ConcurrentHashMap<>(); - private static Map _pathNodesIndex = new ConcurrentHashMap<>(); - - public static GeoPathFinding getInstance() - { - return SingletonHolder._instance; - } - - @Override - public boolean pathNodesExist(short regionoffset) - { - return _pathNodesIndex.containsKey(regionoffset); - } - - @Override - public List 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 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 visited = new ArrayList<>(550); - - // List of Nodes to Visit - final LinkedList 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 constructPath2(AbstractNode node) - { - final LinkedList 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> 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(); - } -} diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/utils/BinaryNodeHeap.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/utils/BinaryNodeHeap.java deleted file mode 100644 index 665977f686..0000000000 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/utils/BinaryNodeHeap.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java new file mode 100644 index 0000000000..587aab48e2 --- /dev/null +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java @@ -0,0 +1,1311 @@ +/* + * 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 . + */ +package com.l2jmobius.gameserver.geoengine; + +import java.io.File; +import java.io.RandomAccessFile; +import java.nio.ByteOrder; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.util.List; +import java.util.logging.Logger; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.MathUtil; +import com.l2jmobius.gameserver.data.xml.impl.DoorData; +import com.l2jmobius.gameserver.geoengine.geodata.ABlock; +import com.l2jmobius.gameserver.geoengine.geodata.BlockComplex; +import com.l2jmobius.gameserver.geoengine.geodata.BlockComplexDynamic; +import com.l2jmobius.gameserver.geoengine.geodata.BlockFlat; +import com.l2jmobius.gameserver.geoengine.geodata.BlockMultilayer; +import com.l2jmobius.gameserver.geoengine.geodata.BlockMultilayerDynamic; +import com.l2jmobius.gameserver.geoengine.geodata.BlockNull; +import com.l2jmobius.gameserver.geoengine.geodata.GeoFormat; +import com.l2jmobius.gameserver.geoengine.geodata.GeoLocation; +import com.l2jmobius.gameserver.geoengine.geodata.GeoStructure; +import com.l2jmobius.gameserver.geoengine.geodata.IBlockDynamic; +import com.l2jmobius.gameserver.geoengine.geodata.IGeoObject; +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.actor.L2Character; +import com.l2jmobius.gameserver.model.actor.instance.L2DoorInstance; +import com.l2jmobius.gameserver.model.instancezone.Instance; + +/** + * @author Hasha + */ +public class GeoEngine +{ + protected static final Logger _log = Logger.getLogger(GeoEngine.class.getName()); + + private final ABlock[][] _blocks; + private final BlockNull _nullBlock; + + /** + * Returns the instance of the {@link GeoEngine}. + * @return {@link GeoEngine} : The instance. + */ + public static final GeoEngine getInstance() + { + return SingletonHolder._instance; + } + + /** + * GeoEngine contructor. Loads all geodata files of chosen geodata format. + */ + public GeoEngine() + { + _log.info("GeoEngine: Initializing..."); + + // initialize block container + _blocks = new ABlock[GeoStructure.GEO_BLOCKS_X][GeoStructure.GEO_BLOCKS_Y]; + + // load null block + _nullBlock = new BlockNull(); + + // initialize multilayer temporarily buffer + BlockMultilayer.initialize(); + + // load geo files according to geoengine config setup + int loaded = 0; + int failed = 0; + for (int rx = L2World.TILE_X_MIN; rx <= L2World.TILE_X_MAX; rx++) + { + for (int ry = L2World.TILE_Y_MIN; ry <= L2World.TILE_Y_MAX; ry++) + { + final String filename = String.format(GeoFormat.L2D.getFilename(), rx, ry); + final String filepath = Config.GEODATA_PATH; + File f = new File(filepath + filename); + if (f.exists() && !f.isDirectory()) + { + // region file is load-able, try to load it + if (loadGeoBlocks(rx, ry)) + { + loaded++; + } + else + { + failed++; + } + } + else + { + // region file is not load-able, load null blocks + loadNullBlocks(rx, ry); + } + } + } + _log.info("GeoEngine: Loaded " + loaded + " L2D region files."); + + // Avoid wrong config when no files loaded + if ((loaded == 0) && (Config.COORD_SYNCHRONIZE == 2)) + { + Config.COORD_SYNCHRONIZE = -1; + _log.info("GeoEngine: Forcing CoordSynchronize setting to -1."); + } + + // release multilayer block temporarily buffer + BlockMultilayer.release(); + + if (failed > 0) + { + _log.info("GeoEngine: Failed to load " + failed + " L2D region files. Please consider to check your \"GeoEngine.ini\" settings and location of \"XX_YY.L2D\" geodata files."); + System.exit(1); + } + } + + /** + * Loads geodata from a file. When file does not exist, is corrupted or not consistent, loads none geodata. + * @param regionX : Geodata file region X coordinate. + * @param regionY : Geodata file region Y coordinate. + * @return boolean : True, when geodata file was loaded without problem. + */ + private final boolean loadGeoBlocks(int regionX, int regionY) + { + final String filename = String.format(GeoFormat.L2D.getFilename(), regionX, regionY); + final String filepath = Config.GEODATA_PATH + filename; + + // standard load + try (RandomAccessFile raf = new RandomAccessFile(filepath, "r"); + FileChannel fc = raf.getChannel()) + { + // initialize file buffer + MappedByteBuffer buffer = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()).load(); + buffer.order(ByteOrder.LITTLE_ENDIAN); + + // get block indexes + final int blockX = (regionX - L2World.TILE_X_MIN) * GeoStructure.REGION_BLOCKS_X; + final int blockY = (regionY - L2World.TILE_Y_MIN) * GeoStructure.REGION_BLOCKS_Y; + + // loop over region blocks + for (int ix = 0; ix < GeoStructure.REGION_BLOCKS_X; ix++) + { + for (int iy = 0; iy < GeoStructure.REGION_BLOCKS_Y; iy++) + { + // get block type + final byte type = buffer.get(); + + // load block according to block type + switch (type) + { + case GeoStructure.TYPE_FLAT_L2D: + _blocks[blockX + ix][blockY + iy] = new BlockFlat(buffer, GeoFormat.L2D); + break; + + case GeoStructure.TYPE_COMPLEX_L2D: + _blocks[blockX + ix][blockY + iy] = new BlockComplex(buffer, GeoFormat.L2D); + break; + + case GeoStructure.TYPE_MULTILAYER_L2D: + _blocks[blockX + ix][blockY + iy] = new BlockMultilayer(buffer, GeoFormat.L2D); + break; + + default: + throw new IllegalArgumentException("Unknown block type: " + type); + } + } + } + + // check data consistency + if (buffer.remaining() > 0) + { + _log.warning("GeoEngine: Region file " + filename + " can be corrupted, remaining " + buffer.remaining() + " bytes to read."); + } + + // loading was successful + return true; + } + catch (Exception e) + { + // an error occured while loading, load null blocks + _log.warning("GeoEngine: Error while loading " + filename + " region file."); + _log.warning(e.getMessage()); + e.printStackTrace(); + + // replace whole region file with null blocks + loadNullBlocks(regionX, regionY); + + // loading was not successful + return false; + } + } + + /** + * Loads null blocks. Used when no region file is detected or an error occurs during loading. + * @param regionX : Geodata file region X coordinate. + * @param regionY : Geodata file region Y coordinate. + */ + private final void loadNullBlocks(int regionX, int regionY) + { + // get block indexes + final int blockX = (regionX - L2World.TILE_X_MIN) * GeoStructure.REGION_BLOCKS_X; + final int blockY = (regionY - L2World.TILE_Y_MIN) * GeoStructure.REGION_BLOCKS_Y; + + // load all null blocks + for (int ix = 0; ix < GeoStructure.REGION_BLOCKS_X; ix++) + { + for (int iy = 0; iy < GeoStructure.REGION_BLOCKS_Y; iy++) + { + _blocks[blockX + ix][blockY + iy] = _nullBlock; + } + } + } + + // GEODATA - GENERAL + + /** + * Converts world X to geodata X. + * @param worldX + * @return int : Geo X + */ + public final int getGeoX(int worldX) + { + return (MathUtil.limit(worldX, L2World.MAP_MIN_X, L2World.MAP_MAX_X) - L2World.MAP_MIN_X) >> 4; + } + + /** + * Converts world Y to geodata Y. + * @param worldY + * @return int : Geo Y + */ + public final int getGeoY(int worldY) + { + return (MathUtil.limit(worldY, L2World.MAP_MIN_Y, L2World.MAP_MAX_Y) - L2World.MAP_MIN_Y) >> 4; + } + + /** + * Converts geodata X to world X. + * @param geoX + * @return int : World X + */ + public final int getWorldX(int geoX) + { + return (MathUtil.limit(geoX, 0, GeoStructure.GEO_CELLS_X) << 4) + L2World.MAP_MIN_X + 8; + } + + /** + * Converts geodata Y to world Y. + * @param geoY + * @return int : World Y + */ + public final int getWorldY(int geoY) + { + return (MathUtil.limit(geoY, 0, GeoStructure.GEO_CELLS_Y) << 4) + L2World.MAP_MIN_Y + 8; + } + + /** + * Returns block of geodata on given coordinates. + * @param geoX : Geodata X + * @param geoY : Geodata Y + * @return {@link ABlock} : Bloack of geodata. + */ + public final ABlock getBlock(int geoX, int geoY) + { + return _blocks[geoX / GeoStructure.BLOCK_CELLS_X][geoY / GeoStructure.BLOCK_CELLS_Y]; + } + + /** + * Check if geo coordinates has geo. + * @param geoX : Geodata X + * @param geoY : Geodata Y + * @return boolean : True, if given geo coordinates have geodata + */ + public final boolean hasGeoPos(int geoX, int geoY) + { + return getBlock(geoX, geoY).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, closest to given coordinates. + */ + public final short getHeightNearest(int geoX, int geoY, int worldZ) + { + return getBlock(geoX, geoY).getHeightNearest(geoX, geoY, worldZ); + } + + /** + * Returns the height of cell, which is closest to given coordinates.
+ * 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, closest to given coordinates. + */ + public final short getHeightNearestOriginal(int geoX, int geoY, int worldZ) + { + return getBlock(geoX, geoY).getHeightNearestOriginal(geoX, geoY, worldZ); + } + + /** + * Returns the NSWE flag byte of cell, which is closes 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 coordinate, closest to given coordinates. + */ + public final byte getNsweNearest(int geoX, int geoY, int worldZ) + { + return getBlock(geoX, geoY).getNsweNearest(geoX, geoY, worldZ); + } + + /** + * Returns the NSWE flag byte of cell, which is closes to given coordinates.
+ * 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 coordinate, closest to given coordinates. + */ + public final byte getNsweNearestOriginal(int geoX, int geoY, int worldZ) + { + return getBlock(geoX, geoY).getNsweNearestOriginal(geoX, geoY, worldZ); + } + + /** + * Check if world coordinates has geo. + * @param worldX : World X + * @param worldY : World Y + * @return boolean : True, if given world coordinates have geodata + */ + public final boolean hasGeo(int worldX, int worldY) + { + return hasGeoPos(getGeoX(worldX), getGeoY(worldY)); + } + + /** + * Returns closest Z coordinate according to geodata. + * @param worldX : world x + * @param worldY : world y + * @param worldZ : world z + * @return short : nearest Z coordinates according to geodata + */ + public final short getHeight(int worldX, int worldY, int worldZ) + { + return getHeightNearest(getGeoX(worldX), getGeoY(worldY), worldZ); + } + + // GEODATA - DYNAMIC + + /** + * Returns calculated NSWE flag byte as a description of {@link IGeoObject}.
+ * The {@link IGeoObject} is defined by boolean 2D array, saying if the object is present on given cell or not. + * @param inside : 2D description of {@link IGeoObject} + * @return byte[][] : Returns NSWE flags of {@link IGeoObject}. + */ + public static final byte[][] calculateGeoObject(boolean inside[][]) + { + // get dimensions + final int width = inside.length; + final int height = inside[0].length; + + // create object flags for geodata, according to the geo object 2D description + final byte[][] result = new byte[width][height]; + + // loop over each cell of the geo object + for (int ix = 0; ix < width; ix++) + { + for (int iy = 0; iy < height; iy++) + { + if (inside[ix][iy]) + { + // cell is inside geo object, block whole movement (nswe = 0) + result[ix][iy] = 0; + } + else + { + // cell is outside of geo object, block only movement leading inside geo object + + // set initial value -> no geodata change + byte nswe = (byte) 0xFF; + + // perform axial and diagonal checks + if (iy < (height - 1)) + { + if (inside[ix][iy + 1]) + { + nswe &= ~GeoStructure.CELL_FLAG_S; + } + } + if (iy > 0) + { + if (inside[ix][iy - 1]) + { + nswe &= ~GeoStructure.CELL_FLAG_N; + } + } + if (ix < (width - 1)) + { + if (inside[ix + 1][iy]) + { + nswe &= ~GeoStructure.CELL_FLAG_E; + } + } + if (ix > 0) + { + if (inside[ix - 1][iy]) + { + nswe &= ~GeoStructure.CELL_FLAG_W; + } + } + if ((ix < (width - 1)) && (iy < (height - 1))) + { + if (inside[ix + 1][iy + 1] || inside[ix][iy + 1] || inside[ix + 1][iy]) + { + nswe &= ~GeoStructure.CELL_FLAG_SE; + } + } + if ((ix < (width - 1)) && (iy > 0)) + { + if (inside[ix + 1][iy - 1] || inside[ix][iy - 1] || inside[ix + 1][iy]) + { + nswe &= ~GeoStructure.CELL_FLAG_NE; + } + } + if ((ix > 0) && (iy < (height - 1))) + { + if (inside[ix - 1][iy + 1] || inside[ix][iy + 1] || inside[ix - 1][iy]) + { + nswe &= ~GeoStructure.CELL_FLAG_SW; + } + } + if ((ix > 0) && (iy > 0)) + { + if (inside[ix - 1][iy - 1] || inside[ix][iy - 1] || inside[ix - 1][iy]) + { + nswe &= ~GeoStructure.CELL_FLAG_NW; + } + } + + result[ix][iy] = nswe; + } + } + } + + return result; + } + + /** + * Add {@link IGeoObject} to the geodata. + * @param object : An object using {@link IGeoObject} interface. + */ + public final void addGeoObject(IGeoObject object) + { + toggleGeoObject(object, true); + } + + /** + * Remove {@link IGeoObject} from the geodata. + * @param object : An object using {@link IGeoObject} interface. + */ + public final void removeGeoObject(IGeoObject object) + { + toggleGeoObject(object, false); + } + + /** + * Toggles an {@link IGeoObject} in the geodata. + * @param object : An object using {@link IGeoObject} interface. + * @param add : Add/remove object. + */ + private final void toggleGeoObject(IGeoObject object, boolean add) + { + // get object geo coordinates and data + final int minGX = object.getGeoX(); + final int minGY = object.getGeoY(); + final byte[][] geoData = object.getObjectGeoData(); + + // get min/max block coordinates + int minBX = minGX / GeoStructure.BLOCK_CELLS_X; + int maxBX = ((minGX + geoData.length) - 1) / GeoStructure.BLOCK_CELLS_X; + int minBY = minGY / GeoStructure.BLOCK_CELLS_Y; + int maxBY = ((minGY + geoData[0].length) - 1) / GeoStructure.BLOCK_CELLS_Y; + + // loop over affected blocks in X direction + for (int bx = minBX; bx <= maxBX; bx++) + { + // loop over affected blocks in Y direction + for (int by = minBY; by <= maxBY; by++) + { + ABlock block; + + // conversion to dynamic block must be synchronized to prevent 2 independent threads converting same block + synchronized (_blocks) + { + // get related block + block = _blocks[bx][by]; + + // check for dynamic block + if (!(block instanceof IBlockDynamic)) + { + // null block means no geodata (particular region file is not loaded), no geodata means no geobjects + if (block instanceof BlockNull) + { + continue; + } + + // not a dynamic block, convert it + if (block instanceof BlockFlat) + { + // convert flat block to the dynamic complex block + block = new BlockComplexDynamic(bx, by, (BlockFlat) block); + _blocks[bx][by] = block; + } + else if (block instanceof BlockComplex) + { + // convert complex block to the dynamic complex block + block = new BlockComplexDynamic(bx, by, (BlockComplex) block); + _blocks[bx][by] = block; + } + else if (block instanceof BlockMultilayer) + { + // convert multilayer block to the dynamic multilayer block + block = new BlockMultilayerDynamic(bx, by, (BlockMultilayer) block); + _blocks[bx][by] = block; + } + } + } + + // add/remove geo object to/from dynamic block + if (add) + { + ((IBlockDynamic) block).addGeoObject(object); + } + else + { + ((IBlockDynamic) block).removeGeoObject(object); + } + } + } + } + + // PATHFINDING + + /** + * Check line of sight from {@link L2Object} to {@link L2Object}. + * @param origin : The origin object. + * @param target : The target object. + * @return {@code boolean} : True if origin can see target + */ + public final boolean canSeeTarget(L2Object origin, L2Object target) + { + // get origin and target world coordinates + final int ox = origin.getX(); + final int oy = origin.getY(); + final int oz = origin.getZ(); + final int tx = target.getX(); + final int ty = target.getY(); + final int tz = target.getZ(); + + // get origin and check existing geo coordinates + final int gox = getGeoX(ox); + final int goy = getGeoY(oy); + if (!hasGeoPos(gox, goy)) + { + return true; + } + + final short goz = getHeightNearest(gox, goy, oz); + + // get target and check existing geo coordinates + final int gtx = getGeoX(tx); + final int gty = getGeoY(ty); + if (!hasGeoPos(gtx, gty)) + { + return true; + } + + final boolean door = target.isDoor(); + final short gtz = door ? getHeightNearestOriginal(gtx, gty, tz) : getHeightNearest(gtx, gty, tz); + + // origin and target coordinates are same + if ((gox == gtx) && (goy == gty)) + { + return goz == gtz; + } + + // get origin and target height, real height = collision height * 2 + double oheight = 0; + if (origin.isCharacter()) + { + oheight = ((L2Character) origin).getCollisionHeight() * 2; + } + + double theight = 0; + if (target.isCharacter()) + { + theight = ((L2Character) target).getCollisionHeight() * 2; + } + + // perform geodata check + return door ? checkSeeOriginal(gox, goy, goz, oheight, gtx, gty, gtz, theight) : checkSee(gox, goy, goz, oheight, gtx, gty, gtz, theight); + } + + /** + * Check line of sight from {@link L2Object} to {@link Location}. + * @param origin : The origin object. + * @param position : The target position. + * @return {@code boolean} : True if object can see position + */ + public final boolean canSeeTarget(L2Object origin, Location position) + { + // get origin and target world coordinates + final int ox = origin.getX(); + final int oy = origin.getY(); + final int oz = origin.getZ(); + final int tx = position.getX(); + final int ty = position.getY(); + final int tz = position.getZ(); + + // get origin and check existing geo coordinates + final int gox = getGeoX(ox); + final int goy = getGeoY(oy); + if (!hasGeoPos(gox, goy)) + { + return true; + } + + final short goz = getHeightNearest(gox, goy, oz); + + // get target and check existing geo coordinates + final int gtx = getGeoX(tx); + final int gty = getGeoY(ty); + if (!hasGeoPos(gtx, gty)) + { + return true; + } + + final short gtz = getHeightNearest(gtx, gty, tz); + + // origin and target coordinates are same + if ((gox == gtx) && (goy == gty)) + { + return goz == gtz; + } + + // get origin and target height, real height = collision height * 2 + double oheight = 0; + if (origin instanceof L2Character) + { + oheight = ((L2Character) origin).getTemplate().getCollisionHeight(); + } + + // perform geodata check + return checkSee(gox, goy, goz, oheight, gtx, gty, gtz, 0); + } + + /** + * Simple check for origin to target visibility. + * @param gox : origin X geodata coordinate + * @param goy : origin Y geodata coordinate + * @param goz : origin Z geodata coordinate + * @param oheight : origin height (if instance of {@link Character}) + * @param gtx : target X geodata coordinate + * @param gty : target Y geodata coordinate + * @param gtz : target Z geodata coordinate + * @param theight : target height (if instance of {@link Character}) + * @return {@code boolean} : True, when target can be seen. + */ + protected final boolean checkSee(int gox, int goy, int goz, double oheight, int gtx, int gty, int gtz, double theight) + { + // get line of sight Z coordinates + double losoz = goz + ((oheight * Config.PART_OF_CHARACTER_HEIGHT) / 100); + double lostz = gtz + ((theight * Config.PART_OF_CHARACTER_HEIGHT) / 100); + + // get X delta and signum + final int dx = Math.abs(gtx - gox); + final int sx = gox < gtx ? 1 : -1; + final byte dirox = sx > 0 ? GeoStructure.CELL_FLAG_E : GeoStructure.CELL_FLAG_W; + final byte dirtx = sx > 0 ? GeoStructure.CELL_FLAG_W : GeoStructure.CELL_FLAG_E; + + // get Y delta and signum + final int dy = Math.abs(gty - goy); + final int sy = goy < gty ? 1 : -1; + final byte diroy = sy > 0 ? GeoStructure.CELL_FLAG_S : GeoStructure.CELL_FLAG_N; + final byte dirty = sy > 0 ? GeoStructure.CELL_FLAG_N : GeoStructure.CELL_FLAG_S; + + // get Z delta + final int dm = Math.max(dx, dy); + final double dz = (lostz - losoz) / dm; + + // get direction flag for diagonal movement + final byte diroxy = getDirXY(dirox, diroy); + final byte dirtxy = getDirXY(dirtx, dirty); + + // delta, determines axis to move on (+..X axis, -..Y axis) + int d = dx - dy; + + // NSWE direction of movement + byte diro; + byte dirt; + + // clearDebugItems(); + // dropDebugItem(728, 0, new GeoLocation(gox, goy, goz)); // blue potion + // dropDebugItem(728, 0, new GeoLocation(gtx, gty, gtz)); // blue potion + + // initialize node values + int nox = gox; + int noy = goy; + int ntx = gtx; + int nty = gty; + byte nsweo = getNsweNearest(gox, goy, goz); + byte nswet = getNsweNearest(gtx, gty, gtz); + + // loop + ABlock block; + int index; + for (int i = 0; i < ((dm + 1) / 2); i++) + { + // dropDebugItem(57, 0, new GeoLocation(gox, goy, goz)); // antidote + // dropDebugItem(1831, 0, new GeoLocation(gtx, gty, gtz)); // adena + + // reset direction flag + diro = 0; + dirt = 0; + + // calculate next point coordinates + int e2 = 2 * d; + if ((e2 > -dy) && (e2 < dx)) + { + // calculate next point XY coordinates + d -= dy; + d += dx; + nox += sx; + ntx -= sx; + noy += sy; + nty -= sy; + diro |= diroxy; + dirt |= dirtxy; + } + else if (e2 > -dy) + { + // calculate next point X coordinate + d -= dy; + nox += sx; + ntx -= sx; + diro |= dirox; + dirt |= dirtx; + } + else if (e2 < dx) + { + // calculate next point Y coordinate + d += dx; + noy += sy; + nty -= sy; + diro |= diroy; + dirt |= dirty; + } + + { + // get block of the next cell + block = getBlock(nox, noy); + + // get index of particular layer, based on movement conditions + if ((nsweo & diro) == 0) + { + index = block.getIndexAbove(nox, noy, goz - GeoStructure.CELL_IGNORE_HEIGHT); + } + else + { + index = block.getIndexBelow(nox, noy, goz + GeoStructure.CELL_IGNORE_HEIGHT); + } + + // layer does not exist, return + if (index == -1) + { + return false; + } + + // get layer and next line of sight Z coordinate + goz = block.getHeight(index); + losoz += dz; + + // perform line of sight check, return when fails + if ((goz - losoz) > Config.MAX_OBSTACLE_HEIGHT) + { + return false; + } + + // get layer nswe + nsweo = block.getNswe(index); + } + { + // get block of the next cell + block = getBlock(ntx, nty); + + // get index of particular layer, based on movement conditions + if ((nswet & dirt) == 0) + { + index = block.getIndexAbove(ntx, nty, gtz - GeoStructure.CELL_IGNORE_HEIGHT); + } + else + { + index = block.getIndexBelow(ntx, nty, gtz + GeoStructure.CELL_IGNORE_HEIGHT); + } + + // layer does not exist, return + if (index == -1) + { + return false; + } + + // get layer and next line of sight Z coordinate + gtz = block.getHeight(index); + lostz -= dz; + + // perform line of sight check, return when fails + if ((gtz - lostz) > Config.MAX_OBSTACLE_HEIGHT) + { + return false; + } + + // get layer nswe + nswet = block.getNswe(index); + } + + // update coords + gox = nox; + goy = noy; + gtx = ntx; + gty = nty; + } + + // when iteration is completed, compare final Z coordinates + return Math.abs(goz - gtz) < (GeoStructure.CELL_HEIGHT * 4); + } + + /** + * Simple check for origin to target visibility.
+ * Geodata without {@link IGeoObject} are taken in consideration.
+ * NOTE: When two doors close between each other and the LoS check of one doors is performed through another door, result will not be accurate (the other door are skipped). + * @param gox : origin X geodata coordinate + * @param goy : origin Y geodata coordinate + * @param goz : origin Z geodata coordinate + * @param oheight : origin height (if instance of {@link Character}) + * @param gtx : target X geodata coordinate + * @param gty : target Y geodata coordinate + * @param gtz : target Z geodata coordinate + * @param theight : target height (if instance of {@link Character} or {@link L2DoorInstance}) + * @return {@code boolean} : True, when target can be seen. + */ + protected final boolean checkSeeOriginal(int gox, int goy, int goz, double oheight, int gtx, int gty, int gtz, double theight) + { + // get line of sight Z coordinates + double losoz = goz + ((oheight * Config.PART_OF_CHARACTER_HEIGHT) / 100); + double lostz = gtz + ((theight * Config.PART_OF_CHARACTER_HEIGHT) / 100); + + // get X delta and signum + final int dx = Math.abs(gtx - gox); + final int sx = gox < gtx ? 1 : -1; + final byte dirox = sx > 0 ? GeoStructure.CELL_FLAG_E : GeoStructure.CELL_FLAG_W; + final byte dirtx = sx > 0 ? GeoStructure.CELL_FLAG_W : GeoStructure.CELL_FLAG_E; + + // get Y delta and signum + final int dy = Math.abs(gty - goy); + final int sy = goy < gty ? 1 : -1; + final byte diroy = sy > 0 ? GeoStructure.CELL_FLAG_S : GeoStructure.CELL_FLAG_N; + final byte dirty = sy > 0 ? GeoStructure.CELL_FLAG_N : GeoStructure.CELL_FLAG_S; + + // get Z delta + final int dm = Math.max(dx, dy); + final double dz = (lostz - losoz) / dm; + + // get direction flag for diagonal movement + final byte diroxy = getDirXY(dirox, diroy); + final byte dirtxy = getDirXY(dirtx, dirty); + + // delta, determines axis to move on (+..X axis, -..Y axis) + int d = dx - dy; + + // NSWE direction of movement + byte diro; + byte dirt; + + // clearDebugItems(); + // dropDebugItem(728, 0, new GeoLocation(gox, goy, goz)); // blue potion + // dropDebugItem(728, 0, new GeoLocation(gtx, gty, gtz)); // blue potion + + // initialize node values + int nox = gox; + int noy = goy; + int ntx = gtx; + int nty = gty; + byte nsweo = getNsweNearestOriginal(gox, goy, goz); + byte nswet = getNsweNearestOriginal(gtx, gty, gtz); + + // loop + ABlock block; + int index; + for (int i = 0; i < ((dm + 1) / 2); i++) + { + // dropDebugItem(57, 0, new GeoLocation(gox, goy, goz)); // antidote + // dropDebugItem(1831, 0, new GeoLocation(gtx, gty, gtz)); // adena + + // reset direction flag + diro = 0; + dirt = 0; + + // calculate next point coordinates + int e2 = 2 * d; + if ((e2 > -dy) && (e2 < dx)) + { + // calculate next point XY coordinates + d -= dy; + d += dx; + nox += sx; + ntx -= sx; + noy += sy; + nty -= sy; + diro |= diroxy; + dirt |= dirtxy; + } + else if (e2 > -dy) + { + // calculate next point X coordinate + d -= dy; + nox += sx; + ntx -= sx; + diro |= dirox; + dirt |= dirtx; + } + else if (e2 < dx) + { + // calculate next point Y coordinate + d += dx; + noy += sy; + nty -= sy; + diro |= diroy; + dirt |= dirty; + } + + { + // get block of the next cell + block = getBlock(nox, noy); + + // get index of particular layer, based on movement conditions + if ((nsweo & diro) == 0) + { + index = block.getIndexAboveOriginal(nox, noy, goz - GeoStructure.CELL_IGNORE_HEIGHT); + } + else + { + index = block.getIndexBelowOriginal(nox, noy, goz + GeoStructure.CELL_IGNORE_HEIGHT); + } + + // layer does not exist, return + if (index == -1) + { + return false; + } + + // get layer and next line of sight Z coordinate + goz = block.getHeightOriginal(index); + losoz += dz; + + // perform line of sight check, return when fails + if ((goz - losoz) > Config.MAX_OBSTACLE_HEIGHT) + { + return false; + } + + // get layer nswe + nsweo = block.getNsweOriginal(index); + } + { + // get block of the next cell + block = getBlock(ntx, nty); + + // get index of particular layer, based on movement conditions + if ((nswet & dirt) == 0) + { + index = block.getIndexAboveOriginal(ntx, nty, gtz - GeoStructure.CELL_IGNORE_HEIGHT); + } + else + { + index = block.getIndexBelowOriginal(ntx, nty, gtz + GeoStructure.CELL_IGNORE_HEIGHT); + } + + // layer does not exist, return + if (index == -1) + { + return false; + } + + // get layer and next line of sight Z coordinate + gtz = block.getHeightOriginal(index); + lostz -= dz; + + // perform line of sight check, return when fails + if ((gtz - lostz) > Config.MAX_OBSTACLE_HEIGHT) + { + return false; + } + + // get layer nswe + nswet = block.getNsweOriginal(index); + } + + // update coords + gox = nox; + goy = noy; + gtx = ntx; + gty = nty; + } + + // when iteration is completed, compare final Z coordinates + return Math.abs(goz - gtz) < (GeoStructure.CELL_HEIGHT * 4); + } + + /** + * Check movement from coordinates to coordinates. + * @param ox : origin X coordinate + * @param oy : origin Y coordinate + * @param oz : origin Z coordinate + * @param tx : target X coordinate + * @param ty : target Y coordinate + * @param tz : target Z coordinate + * @param instance + * @return {code boolean} : True if target coordinates are reachable from origin coordinates + */ + public final boolean canMoveToTarget(int ox, int oy, int oz, int tx, int ty, int tz, Instance instance) + { + if (DoorData.getInstance().checkIfDoorsBetween(ox, oy, oz, tx, ty, tz, instance, false)) + { + return false; + } + + if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(ox, oy, oz), new Location(tx, ty, tz), instance)) + { + return false; + } + + // get origin and check existing geo coordinates + final int gox = getGeoX(ox); + final int goy = getGeoY(oy); + if (!hasGeoPos(gox, goy)) + { + return true; + } + + final short goz = getHeightNearest(gox, goy, oz); + + // get target and check existing geo coordinates + final int gtx = getGeoX(tx); + final int gty = getGeoY(ty); + if (!hasGeoPos(gtx, gty)) + { + return true; + } + + final short gtz = getHeightNearest(gtx, gty, tz); + + // target coordinates reached + if ((gox == gtx) && (goy == gty) && (goz == gtz)) + { + return true; + } + + // perform geodata check + GeoLocation loc = checkMove(gox, goy, goz, gtx, gty, gtz, instance); + return (loc.getGeoX() == gtx) && (loc.getGeoY() == gty); + } + + /** + * Check movement from origin to target. Returns last available point in the checked path. + * @param ox : origin X coordinate + * @param oy : origin Y coordinate + * @param oz : origin Z coordinate + * @param tx : target X coordinate + * @param ty : target Y coordinate + * @param tz : target Z coordinate + * @param instance + * @return {@link Location} : Last point where object can walk (just before wall) + */ + public final Location canMoveToTargetLoc(int ox, int oy, int oz, int tx, int ty, int tz, Instance instance) + { + if (DoorData.getInstance().checkIfDoorsBetween(ox, oy, oz, tx, ty, tz, instance, false)) + { + return new Location(ox, oy, getHeight(ox, oy, oz)); + } + + if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(ox, oy, oz), new Location(tx, ty, tz), instance)) + { + return new Location(ox, oy, getHeight(ox, oy, oz)); + } + + // get origin and check existing geo coordinates + final int gox = getGeoX(ox); + final int goy = getGeoY(oy); + if (!hasGeoPos(gox, goy)) + { + return new Location(tx, ty, tz); + } + + final short goz = getHeightNearest(gox, goy, oz); + + // get target and check existing geo coordinates + final int gtx = getGeoX(tx); + final int gty = getGeoY(ty); + if (!hasGeoPos(gtx, gty)) + { + return new Location(tx, ty, tz); + } + + final short gtz = getHeightNearest(gtx, gty, tz); + + // target coordinates reached + if ((gox == gtx) && (goy == gty) && (goz == gtz)) + { + return new Location(tx, ty, tz); + } + + // perform geodata check + return checkMove(gox, goy, goz, gtx, gty, gtz, instance); + } + + /** + * With this method you can check if a position is visible or can be reached by beeline movement.
+ * Target X and Y reachable and Z is on same floor: + *
    + *
  • Location of the target with corrected Z value from geodata.
  • + *
+ * Target X and Y reachable but Z is on another floor: + *
    + *
  • Location of the origin with corrected Z value from geodata.
  • + *
+ * Target X and Y not reachable: + *
    + *
  • Last accessible location in destination to target.
  • + *
+ * @param gox : origin X geodata coordinate + * @param goy : origin Y geodata coordinate + * @param goz : origin Z geodata coordinate + * @param gtx : target X geodata coordinate + * @param gty : target Y geodata coordinate + * @param gtz : target Z geodata coordinate + * @param instance + * @return {@link GeoLocation} : The last allowed point of movement. + */ + protected final GeoLocation checkMove(int gox, int goy, int goz, int gtx, int gty, int gtz, Instance instance) + { + if (DoorData.getInstance().checkIfDoorsBetween(gox, goy, goz, gtx, gty, gtz, instance, false)) + { + return new GeoLocation(gox, goy, goz); + } + + if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(gox, goy, goz), new Location(gtx, gty, gtz), instance)) + { + return new GeoLocation(gox, goy, goz); + } + + // get X delta, signum and direction flag + final int dx = Math.abs(gtx - gox); + final int sx = gox < gtx ? 1 : -1; + final byte dirX = sx > 0 ? GeoStructure.CELL_FLAG_E : GeoStructure.CELL_FLAG_W; + + // get Y delta, signum and direction flag + final int dy = Math.abs(gty - goy); + final int sy = goy < gty ? 1 : -1; + final byte dirY = sy > 0 ? GeoStructure.CELL_FLAG_S : GeoStructure.CELL_FLAG_N; + + // get direction flag for diagonal movement + final byte dirXY = getDirXY(dirX, dirY); + + // delta, determines axis to move on (+..X axis, -..Y axis) + int d = dx - dy; + + // NSWE direction of movement + byte direction; + + // load pointer coordinates + int gpx = gox; + int gpy = goy; + int gpz = goz; + + // load next pointer + int nx = gpx; + int ny = gpy; + + // loop + do + { + direction = 0; + + // calculate next point coordinates + int e2 = 2 * d; + if ((e2 > -dy) && (e2 < dx)) + { + d -= dy; + d += dx; + nx += sx; + ny += sy; + direction |= dirXY; + } + else if (e2 > -dy) + { + d -= dy; + nx += sx; + direction |= dirX; + } + else if (e2 < dx) + { + d += dx; + ny += sy; + direction |= dirY; + } + + // obstacle found, return + if ((getNsweNearest(gpx, gpy, gpz) & direction) == 0) + { + return new GeoLocation(gpx, gpy, gpz); + } + + // update pointer coordinates + gpx = nx; + gpy = ny; + gpz = getHeightNearest(nx, ny, gpz); + + // target coordinates reached + if ((gpx == gtx) && (gpy == gty)) + { + if (gpz == gtz) + { + // path found, Z coordinates are okay, return target point + return new GeoLocation(gtx, gty, gtz); + } + + // path found, Z coordinates are not okay, return origin point + return new GeoLocation(gox, goy, goz); + } + } + while (true); + } + + /** + * Returns diagonal NSWE flag format of combined two NSWE flags. + * @param dirX : X direction NSWE flag + * @param dirY : Y direction NSWE flag + * @return byte : NSWE flag of combined direction + */ + private static final byte getDirXY(byte dirX, byte dirY) + { + // check axis directions + if (dirY == GeoStructure.CELL_FLAG_N) + { + if (dirX == GeoStructure.CELL_FLAG_W) + { + return GeoStructure.CELL_FLAG_NW; + } + + return GeoStructure.CELL_FLAG_NE; + } + + if (dirX == GeoStructure.CELL_FLAG_W) + { + return GeoStructure.CELL_FLAG_SW; + } + + return GeoStructure.CELL_FLAG_SE; + } + + /** + * Returns the list of location objects as a result of complete path calculation. + * @param ox : origin x + * @param oy : origin y + * @param oz : origin z + * @param tx : target x + * @param ty : target y + * @param tz : target z + * @param instance + * @param playable : moving object is playable? + * @return {@code List} : complete path from nodes + */ + public List findPath(int ox, int oy, int oz, int tx, int ty, int tz, Instance instance, boolean playable) + { + return null; + } + + private static class SingletonHolder + { + protected static final GeoEngine _instance = Config.PATHFINDING ? new GeoEnginePathfinding() : new GeoEngine(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/GeoEnginePathfinding.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/GeoEnginePathfinding.java new file mode 100644 index 0000000000..b9def83228 --- /dev/null +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/GeoEnginePathfinding.java @@ -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 . + */ +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 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 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 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 : list of node location + */ + private static final List constructPath(Node target) + { + // create empty list + LinkedList 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 _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(); + } + } +} \ No newline at end of file diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/ABlock.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/ABlock.java new file mode 100644 index 0000000000..7fca5a9f52 --- /dev/null +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/ABlock.java @@ -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 . + */ +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.
+ * 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.
+ * 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.
+ * 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.
+ * 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.
+ * 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.
+ * 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; +} \ No newline at end of file diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplex.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplex.java new file mode 100644 index 0000000000..de0a7b8524 --- /dev/null +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplex.java @@ -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 . + */ +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); + } +} \ No newline at end of file diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplexDynamic.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplexDynamic.java new file mode 100644 index 0000000000..9f49e41899 --- /dev/null +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplexDynamic.java @@ -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 . + */ +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 _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; + } + } + } + } + } +} \ No newline at end of file diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/BlockFlat.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/BlockFlat.java new file mode 100644 index 0000000000..e1d82814eb --- /dev/null +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/BlockFlat.java @@ -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 . + */ +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)); + } +} \ No newline at end of file diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayer.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayer.java new file mode 100644 index 0000000000..56d4de75e1 --- /dev/null +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayer.java @@ -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 . + */ +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; + } + } +} \ No newline at end of file diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayerDynamic.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayerDynamic.java new file mode 100644 index 0000000000..2361135de5 --- /dev/null +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayerDynamic.java @@ -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 . + */ +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 _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; + } + } + } + } + } +} \ No newline at end of file diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/BlockNull.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/BlockNull.java new file mode 100644 index 0000000000..225bdef947 --- /dev/null +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/BlockNull.java @@ -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 . + */ +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) + { + } +} \ No newline at end of file diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNodeLoc.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/GeoFormat.java similarity index 67% rename from L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNodeLoc.java rename to L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/GeoFormat.java index 0678b3cb3a..57885fc734 100644 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNodeLoc.java +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/GeoFormat.java @@ -14,20 +14,26 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -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; + } +} \ No newline at end of file diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/GeoLocation.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/GeoLocation.java new file mode 100644 index 0000000000..850fcdbfcd --- /dev/null +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/GeoLocation.java @@ -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 . + */ +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; + } +} \ No newline at end of file diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/GeoStructure.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/GeoStructure.java new file mode 100644 index 0000000000..e1925e6e57 --- /dev/null +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/GeoStructure.java @@ -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 . + */ +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; +} \ No newline at end of file diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/IBlockDynamic.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/IBlockDynamic.java new file mode 100644 index 0000000000..e241e73b1c --- /dev/null +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/IBlockDynamic.java @@ -0,0 +1,35 @@ +/* + * 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 . + */ +package com.l2jmobius.gameserver.geoengine.geodata; + +/** + * @author Hasha + */ +public interface IBlockDynamic +{ + /** + * 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); + + /** + * 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); +} \ No newline at end of file diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/IGeoObject.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/IGeoObject.java new file mode 100644 index 0000000000..2726378e3a --- /dev/null +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/geodata/IGeoObject.java @@ -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 . + */ +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(); +} diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/pathfinding/Node.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/pathfinding/Node.java new file mode 100644 index 0000000000..27430a65cd --- /dev/null +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/pathfinding/Node.java @@ -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 . + */ +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; + } +} \ No newline at end of file diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/pathfinding/NodeBuffer.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/pathfinding/NodeBuffer.java new file mode 100644 index 0000000000..300fe31190 --- /dev/null +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geoengine/pathfinding/NodeBuffer.java @@ -0,0 +1,351 @@ +/* + * 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 . + */ +package com.l2jmobius.gameserver.geoengine.pathfinding; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.locks.ReentrantLock; + +import com.l2jmobius.Config; +import com.l2jmobius.gameserver.geoengine.geodata.GeoStructure; + +/** + * @author DS, Hasha; Credits to Diamond + */ +public class NodeBuffer +{ + private final ReentrantLock _lock = new ReentrantLock(); + private final int _size; + private final Node[][] _buffer; + + // center coordinates + private int _cx = 0; + private int _cy = 0; + + // target coordinates + private int _gtx = 0; + private int _gty = 0; + private short _gtz = 0; + + // pathfinding statistics + private long _timeStamp = 0; + private long _lastElapsedTime = 0; + + private Node _current = null; + + /** + * Constructor of NodeBuffer. + * @param size : one dimension size of buffer + */ + public NodeBuffer(int size) + { + // set size + _size = size; + + // initialize buffer + _buffer = new Node[size][size]; + for (int x = 0; x < size; x++) + { + for (int y = 0; y < size; y++) + { + _buffer[x][y] = new Node(); + } + } + } + + /** + * Find path consisting of Nodes. Starts at origin coordinates, ends in target coordinates. + * @param gox : origin point x + * @param goy : origin point y + * @param goz : origin point z + * @param gtx : target point x + * @param gty : target point y + * @param gtz : target point z + * @return Node : first node of path + */ + public final Node findPath(int gox, int goy, short goz, int gtx, int gty, short gtz) + { + // load timestamp + _timeStamp = System.currentTimeMillis(); + + // set coordinates (middle of the line (gox,goy) - (gtx,gty), will be in the center of the buffer) + _cx = gox + ((gtx - gox - _size) / 2); + _cy = goy + ((gty - goy - _size) / 2); + + _gtx = gtx; + _gty = gty; + _gtz = gtz; + + _current = getNode(gox, goy, goz); + _current.setCost(getCostH(gox, goy, goz)); + + int count = 0; + do + { + // reached target? + if ((_current.getLoc().getGeoX() == _gtx) && (_current.getLoc().getGeoY() == _gty) && (Math.abs(_current.getLoc().getZ() - _gtz) < 8)) + { + return _current; + } + + // expand current node + expand(); + + // move pointer + _current = _current.getChild(); + } + while ((_current != null) && (++count < Config.MAX_ITERATIONS)); + + return null; + } + + /** + * Creates list of Nodes to show debug path. + * @return List : nodes + */ + public final List debugPath() + { + List result = new ArrayList<>(); + + for (Node n = _current; n.getParent() != null; n = n.getParent()) + { + result.add(n); + n.setCost(-n.getCost()); + } + + for (Node[] nodes : _buffer) + { + for (Node node : nodes) + { + if ((node.getLoc() == null) || (node.getCost() <= 0)) + { + continue; + } + + result.add(node); + } + } + + return result; + } + + public final boolean isLocked() + { + return _lock.tryLock(); + } + + public final void free() + { + _current = null; + + for (Node[] nodes : _buffer) + { + for (Node node : nodes) + { + if (node.getLoc() != null) + { + node.free(); + } + } + } + + _lock.unlock(); + _lastElapsedTime = System.currentTimeMillis() - _timeStamp; + } + + public final long getElapsedTime() + { + return _lastElapsedTime; + } + + /** + * Check _current Node and add its neighbors to the buffer. + */ + private final void expand() + { + // can't move anywhere, don't expand + byte nswe = _current.getLoc().getNSWE(); + if (nswe == 0) + { + return; + } + + // get geo coords of the node to be expanded + final int x = _current.getLoc().getGeoX(); + final int y = _current.getLoc().getGeoY(); + final short z = (short) _current.getLoc().getZ(); + + // can move north, expand + if ((nswe & GeoStructure.CELL_FLAG_N) != 0) + { + addNode(x, y - 1, z, Config.BASE_WEIGHT); + } + + // can move south, expand + if ((nswe & GeoStructure.CELL_FLAG_S) != 0) + { + addNode(x, y + 1, z, Config.BASE_WEIGHT); + } + + // can move west, expand + if ((nswe & GeoStructure.CELL_FLAG_W) != 0) + { + addNode(x - 1, y, z, Config.BASE_WEIGHT); + } + + // can move east, expand + if ((nswe & GeoStructure.CELL_FLAG_E) != 0) + { + addNode(x + 1, y, z, Config.BASE_WEIGHT); + } + + // can move north-west, expand + if ((nswe & GeoStructure.CELL_FLAG_NW) != 0) + { + addNode(x - 1, y - 1, z, Config.DIAGONAL_WEIGHT); + } + + // can move north-east, expand + if ((nswe & GeoStructure.CELL_FLAG_NE) != 0) + { + addNode(x + 1, y - 1, z, Config.DIAGONAL_WEIGHT); + } + + // can move south-west, expand + if ((nswe & GeoStructure.CELL_FLAG_SW) != 0) + { + addNode(x - 1, y + 1, z, Config.DIAGONAL_WEIGHT); + } + + // can move south-east, expand + if ((nswe & GeoStructure.CELL_FLAG_SE) != 0) + { + addNode(x + 1, y + 1, z, Config.DIAGONAL_WEIGHT); + } + } + + /** + * Returns node, if it exists in buffer. + * @param x : node X coord + * @param y : node Y coord + * @param z : node Z coord + * @return Node : node, if exits in buffer + */ + private final Node getNode(int x, int y, short z) + { + // check node X out of coordinates + final int ix = x - _cx; + if ((ix < 0) || (ix >= _size)) + { + return null; + } + + // check node Y out of coordinates + final int iy = y - _cy; + if ((iy < 0) || (iy >= _size)) + { + return null; + } + + // get node + Node result = _buffer[ix][iy]; + + // check and update + if (result.getLoc() == null) + { + result.setLoc(x, y, z); + } + + // return node + return result; + } + + /** + * Add node given by coordinates to the buffer. + * @param x : geo X coord + * @param y : geo Y coord + * @param z : geo Z coord + * @param weight : weight of movement to new node + */ + private final void addNode(int x, int y, short z, int weight) + { + // get node to be expanded + Node node = getNode(x, y, z); + if (node == null) + { + return; + } + + // Z distance between nearby cells is higher than cell size + if (node.getLoc().getZ() > (z + (2 * GeoStructure.CELL_HEIGHT))) + { + return; + } + + // node was already expanded, return + if (node.getCost() >= 0) + { + return; + } + + node.setParent(_current); + if (node.getLoc().getNSWE() != (byte) 0xFF) + { + node.setCost(getCostH(x, y, node.getLoc().getZ()) + (weight * Config.OBSTACLE_MULTIPLIER)); + } + else + { + node.setCost(getCostH(x, y, node.getLoc().getZ()) + weight); + } + + Node current = _current; + int count = 0; + while ((current.getChild() != null) && (count < (Config.MAX_ITERATIONS * 4))) + { + count++; + if (current.getChild().getCost() > node.getCost()) + { + node.setChild(current.getChild()); + break; + } + current = current.getChild(); + } + + if (count >= (Config.MAX_ITERATIONS * 4)) + { + System.err.println("Pathfinding: too long loop detected, cost:" + node.getCost()); + } + + current.setChild(node); + } + + /** + * @param x : node X coord + * @param y : node Y coord + * @param i : node Z coord + * @return double : node cost + */ + private final double getCostH(int x, int y, int i) + { + final int dX = x - _gtx; + final int dY = y - _gty; + final int dZ = (i - _gtz) / GeoStructure.CELL_HEIGHT; + + // return (Math.abs(dX) + Math.abs(dY) + Math.abs(dZ)) * Config.HEURISTIC_WEIGHT; // Manhattan distance + return Math.sqrt((dX * dX) + (dY * dY) + (dZ * dZ)) * Config.HEURISTIC_WEIGHT; // Direct distance + } +} \ No newline at end of file diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/instancemanager/WarpedSpaceManager.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/instancemanager/WarpedSpaceManager.java index 4f61421f83..cde24700ba 100644 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/instancemanager/WarpedSpaceManager.java +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/instancemanager/WarpedSpaceManager.java @@ -18,7 +18,6 @@ package com.l2jmobius.gameserver.instancemanager; import java.util.concurrent.ConcurrentHashMap; -import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNodeLoc; import com.l2jmobius.gameserver.model.Location; import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.holders.WarpedSpaceHolder; @@ -52,11 +51,6 @@ public class WarpedSpaceManager _warpedSpace.remove(creature); } - public boolean checkForWarpedSpace(AbstractNodeLoc start, AbstractNodeLoc end, Instance instance) - { - return checkForWarpedSpace(new Location(start.getX(), start.getY(), start.getZ()), new Location(end.getX(), end.getY(), end.getZ()), instance); - } - public boolean checkForWarpedSpace(Location origin, Location destination, Instance instance) { if (_warpedSpace != null) diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/Fishing.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/Fishing.java index 1cd211f36a..6559985934 100644 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/Fishing.java +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/Fishing.java @@ -25,7 +25,7 @@ import com.l2jmobius.commons.util.Rnd; import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.data.xml.impl.FishingData; import com.l2jmobius.gameserver.enums.ShotType; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.instancemanager.ZoneManager; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.events.EventDispatcher; @@ -420,19 +420,19 @@ public class Fishing // always use water zone, fishing zone high z is high in the air... final int baitZ = waterZone.getWaterZ(); - // if (!GeoData.getInstance().canSeeTarget(player.getX(), player.getY(), player.getZ(), baitX, baitY, baitZ)) + // if (!GeoEngine.getInstance().canSeeTarget(player.getX(), player.getY(), player.getZ(), baitX, baitY, baitZ)) // // return Integer.MIN_VALUE; // } - if (GeoData.getInstance().hasGeo(baitX, baitY)) + if (GeoEngine.getInstance().hasGeo(baitX, baitY)) { - if (GeoData.getInstance().getHeight(baitX, baitY, baitZ) > baitZ) + if (GeoEngine.getInstance().getHeight(baitX, baitY, baitZ) > baitZ) { return Integer.MIN_VALUE; } - if (GeoData.getInstance().getHeight(baitX, baitY, player.getZ()) > baitZ) + if (GeoEngine.getInstance().getHeight(baitX, baitY, player.getZ()) > baitZ) { return Integer.MIN_VALUE; } diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/L2Spawn.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/L2Spawn.java index 3ddb0761ac..e9978f7863 100644 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/L2Spawn.java +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/L2Spawn.java @@ -26,7 +26,7 @@ import java.util.logging.Logger; import com.l2jmobius.commons.util.Rnd; import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.data.xml.impl.NpcData; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2NpcInstance; import com.l2jmobius.gameserver.model.actor.templates.L2NpcTemplate; @@ -544,7 +544,7 @@ public class L2Spawn implements IPositionable, IIdentifiable, INamable // don't correct z of flying npc's if (!npc.isFlying()) { - newlocz = GeoData.getInstance().getSpawnHeight(newlocx, newlocy, newlocz); + newlocz = GeoEngine.getInstance().getHeight(newlocx, newlocy, newlocz); } // Set is not random walk default value diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/Location.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/Location.java index dd88541a50..4b5e290517 100644 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/Location.java +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/Location.java @@ -26,9 +26,9 @@ import com.l2jmobius.gameserver.model.interfaces.IPositionable; */ public class Location implements IPositionable { - private int _x; - private int _y; - private int _z; + protected int _x; + protected int _y; + protected int _z; private int _heading; public Location(int x, int y, int z) diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/actor/L2Character.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/actor/L2Character.java index 8ab8348d64..8d4e253ccc 100644 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/actor/L2Character.java +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/actor/L2Character.java @@ -63,9 +63,7 @@ import com.l2jmobius.gameserver.enums.ShotType; import com.l2jmobius.gameserver.enums.StatusUpdateType; import com.l2jmobius.gameserver.enums.Team; import com.l2jmobius.gameserver.enums.UserInfoType; -import com.l2jmobius.gameserver.geodata.GeoData; -import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNodeLoc; -import com.l2jmobius.gameserver.geodata.pathfinding.PathFinding; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.idfactory.IdFactory; import com.l2jmobius.gameserver.instancemanager.MapRegionManager; import com.l2jmobius.gameserver.instancemanager.TimersManager; @@ -1053,7 +1051,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe stopEffectsOnAction(); // GeoData Los Check here (or dz > 1000) - if (!GeoData.getInstance().canSeeTarget(this, target)) + if (!GeoEngine.getInstance().canSeeTarget(this, target)) { sendPacket(SystemMessageId.CANNOT_SEE_TARGET); getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE); @@ -2851,7 +2849,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe public boolean disregardingGeodata; public int onGeodataPathIndex; - public List geoPath; + public List geoPath; public int geoPathAccurateTx; public int geoPathAccurateTy; public int geoPathGtx; @@ -3269,9 +3267,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe // Z coordinate will follow geodata or client values if ((Config.COORD_SYNCHRONIZE == 2) && !isFloating && !m.disregardingGeodata && ((GameTimeController.getInstance().getGameTicks() % 10) == 0 // once a second to reduce possible cpu load - ) && GeoData.getInstance().hasGeo(xPrev, yPrev)) + ) && GeoEngine.getInstance().hasGeo(xPrev, yPrev)) { - final int geoHeight = GeoData.getInstance().getSpawnHeight(xPrev, yPrev, zPrev); + final int geoHeight = GeoEngine.getInstance().getHeight(xPrev, yPrev, zPrev); dz = m._zDestination - geoHeight; // quite a big difference, compare to validatePosition packet if (isPlayer() && (Math.abs(getActingPlayer().getClientZ() - geoHeight) > 200) && (Math.abs(getActingPlayer().getClientZ() - geoHeight) < 1500)) @@ -3554,9 +3552,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe { // Notify the AI that the L2Character is arrived at destination getAI().notifyEvent(CtrlEvent.EVT_ARRIVED); - return; } + // Calculate movement angles needed sin = dy / distance; cos = dx / distance; @@ -3581,7 +3579,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe m.onGeodataPathIndex = -1; // Initialize not on geodata path m.disregardingGeodata = false; - if (!isFlying() && !isInsideZone(ZoneId.WATER)) + if (!isFlying() && !isInsideZone(ZoneId.WATER) && !isWalker()) { final boolean isInVehicle = isPlayer() && (getActingPlayer().getVehicle() != null); if (isInVehicle) @@ -3596,16 +3594,11 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe final int gtx = (originalX - L2World.MAP_MIN_X) >> 4; final int gty = (originalY - L2World.MAP_MIN_Y) >> 4; - final Location destiny = GeoData.getInstance().moveCheck(curX, curY, curZ, x, y, z, getInstanceWorld()); - - // location different if destination wasn't reached (or just z coord is different) - x = destiny.getX(); - y = destiny.getY(); - z = destiny.getZ(); - // Movement checks: - // when PATHFINDING > 0, for all characters except mobs returning home (could be changed later to teleport if pathfinding fails) - if (Config.PATHFINDING > 0) + // when geodata == 2, for all characters except mobs returning home (could be changed later to teleport if pathfinding fails) + // when geodata == 1, for l2playableinstance + // assuming intention_follow only when following owner + if ((Config.PATHFINDING && !(isAttackable() && ((L2Attackable) this).isReturningToSpawnPoint())) || (isPlayer() && !(isInVehicle && (distance > 1500))) || (isSummon() && !(getAI().getIntention() == CtrlIntention.AI_INTENTION_FOLLOW))) { if (isOnGeodataPath()) { @@ -3634,7 +3627,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe } else if (isSummon()) { - return; // preventation when summon get out of world coords, player will not loose him, unsummon handled from pcinstance + return; // prevention when summon get out of world coords, player will not loose him, unsummon handled from pcinstance } else { @@ -3643,6 +3636,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe return; } // location different if destination wasn't reached (or just z coord is different) + Location destiny = GeoEngine.getInstance().canMoveToTargetLoc(curX, curY, curZ, x, y, z, getInstanceWorld()); x = destiny.getX(); y = destiny.getY(); z = destiny.getZ(); @@ -3651,85 +3645,86 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe dz = z - curZ; distance = verticalMovementOnly ? Math.pow(dz, 2) : Math.hypot(dx, dy); } - // Pathfinding checks. Only when geodata setting is 2, the LoS check gives shorter result - // than the original movement was and the LoS gives a shorter distance than 2000 + // Pathfinding checks. Only when geodata setting is 2, the LoS check gives shorter result than the original movement was and the LoS gives a shorter distance than 2000 // This way of detecting need for pathfinding could be changed. - if ((Config.PATHFINDING > 0) && ((originalDistance - distance) > 30) && !isControlBlocked() && !isInVehicle) + if (Config.PATHFINDING && ((originalDistance - distance) > 30) && (distance < 2000) && !isControlBlocked() && !isInVehicle) { - m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayable()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + // Path calculation -- overrides previous movement check + if (isPlayable() || isMinion() || isInCombat()) { - // * Even though there's no path found (remember geonodes aren't perfect), - // the mob is attacking and right now we set it so that the mob will go - // after target anyway, is dz is small enough. - // * With cellpathfinding this approach could be changed but would require taking - // off the geonodes and some more checks. - // * Summons will follow their masters no matter what. - // * Currently minions also must move freely since L2AttackableAI commands - // them to move along with their leader - if (isPlayer() || (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) || (isSummon() && !((L2Summon) this).getFollowStatus())) + m.geoPath = GeoEngine.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayable()); + if ((m.geoPath == null) || (m.geoPath.size() < 2)) { - getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); - return; + // No path found + // Even though there's no path found (remember geonodes aren't perfect), the mob is attacking and right now we set it so that the mob will go after target anyway, is dz is small enough. + // With cellpathfinding this approach could be changed but would require taking off the geonodes and some more checks. + // Summons will follow their masters no matter what. + // Currently minions also must move freely since L2AttackableAI commands them to move along with their leader + if (isPlayer() || (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) || (isSummon() && !((L2Summon) this).getFollowStatus())) + { + getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); + return; + } + + m.disregardingGeodata = true; + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; } - - m.disregardingGeodata = true; - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; - } - else - { - m.onGeodataPathIndex = 0; // on first segment - m.geoPathGtx = gtx; - m.geoPathGty = gty; - m.geoPathAccurateTx = originalX; - m.geoPathAccurateTy = originalY; - - x = m.geoPath.get(m.onGeodataPathIndex).getX(); - y = m.geoPath.get(m.onGeodataPathIndex).getY(); - z = m.geoPath.get(m.onGeodataPathIndex).getZ(); - - // check for doors in the route - if (DoorData.getInstance().checkIfDoorsBetween(curX, curY, curZ, x, y, z, getInstanceWorld())) + else { - m.geoPath = null; - getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); - return; - } - if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(curX, curY, curZ), new Location(x, y, z), getInstanceWorld())) - { - m.geoPath = null; - getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); - return; - } - for (int i = 0; i < (m.geoPath.size() - 1); i++) - { - if (DoorData.getInstance().checkIfDoorsBetween(m.geoPath.get(i), m.geoPath.get(i + 1), getInstanceWorld())) + m.onGeodataPathIndex = 0; // on first segment + m.geoPathGtx = gtx; + m.geoPathGty = gty; + m.geoPathAccurateTx = originalX; + m.geoPathAccurateTy = originalY; + + x = m.geoPath.get(m.onGeodataPathIndex).getX(); + y = m.geoPath.get(m.onGeodataPathIndex).getY(); + z = m.geoPath.get(m.onGeodataPathIndex).getZ(); + + // check for doors in the route + if (DoorData.getInstance().checkIfDoorsBetween(curX, curY, curZ, x, y, z, getInstanceWorld())) { m.geoPath = null; getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); return; } - if (WarpedSpaceManager.getInstance().checkForWarpedSpace(m.geoPath.get(i), m.geoPath.get(i + 1), getInstanceWorld())) + if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(curX, curY, curZ), new Location(x, y, z), getInstanceWorld())) { m.geoPath = null; getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); return; } + for (int i = 0; i < (m.geoPath.size() - 1); i++) + { + if (DoorData.getInstance().checkIfDoorsBetween(m.geoPath.get(i), m.geoPath.get(i + 1), getInstanceWorld())) + { + m.geoPath = null; + getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); + return; + } + if (WarpedSpaceManager.getInstance().checkForWarpedSpace(m.geoPath.get(i), m.geoPath.get(i + 1), getInstanceWorld())) + { + m.geoPath = null; + getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); + return; + } + } + + dx = x - curX; + dy = y - curY; + dz = z - curZ; + distance = verticalMovementOnly ? Math.pow(dz, 2) : Math.hypot(dx, dy); + sin = dy / distance; + cos = dx / distance; } - - dx = x - curX; - dy = y - curY; - dz = z - curZ; - distance = verticalMovementOnly ? Math.pow(dz, 2) : Math.hypot(dx, dy); - sin = dy / distance; - cos = dx / distance; } } + // If no distance to go through, the movement is canceled - if ((distance < 1) && ((Config.PATHFINDING > 0) || isPlayable())) + if ((distance < 1) && (Config.PATHFINDING || isPlayable() || isControlBlocked())) { if (isSummon()) { @@ -3751,7 +3746,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe final int ticksToMove = 1 + (int) ((GameTimeController.TICKS_PER_SECOND * distance) / speed); m._xDestination = x; m._yDestination = y; - m._zDestination = z; // this is what was requested from client + m._zDestination = z; // Calculate and set the heading of the L2Character m._heading = 0; // initial value for coordinate sync @@ -4240,7 +4235,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe return; } // GeoData Los Check or dz > 1000 - if (!GeoData.getInstance().canSeeTarget(player, this)) + if (!GeoEngine.getInstance().canSeeTarget(player, this)) { player.sendPacket(SystemMessageId.CANNOT_SEE_TARGET); player.sendPacket(ActionFailed.STATIC_PACKET); diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/actor/L2Tower.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/actor/L2Tower.java index ac1d703e27..8390083019 100644 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/actor/L2Tower.java +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/actor/L2Tower.java @@ -17,7 +17,7 @@ package com.l2jmobius.gameserver.model.actor; import com.l2jmobius.gameserver.ai.CtrlIntention; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.actor.templates.L2NpcTemplate; import com.l2jmobius.gameserver.network.serverpackets.ActionFailed; @@ -63,7 +63,7 @@ public abstract class L2Tower extends L2Npc } else if (interact) { - if (isAutoAttackable(player) && (Math.abs(player.getZ() - getZ()) < 100) && GeoData.getInstance().canSeeTarget(player, this)) + if (isAutoAttackable(player) && (Math.abs(player.getZ() - getZ()) < 100) && GeoEngine.getInstance().canSeeTarget(player, this)) { // Notify the L2PcInstance AI with AI_INTENTION_INTERACT player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this); diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java index 28803d4bb9..fccf6a4983 100644 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java @@ -97,7 +97,7 @@ import com.l2jmobius.gameserver.enums.StatusUpdateType; import com.l2jmobius.gameserver.enums.SubclassInfoType; import com.l2jmobius.gameserver.enums.Team; import com.l2jmobius.gameserver.enums.UserInfoType; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.handler.AdminCommandHandler; import com.l2jmobius.gameserver.handler.IAdminCommandHandler; import com.l2jmobius.gameserver.handler.IItemHandler; @@ -12476,7 +12476,7 @@ public final class L2PcInstance extends L2Playable } // If there is no geodata loaded for the place we are client Z correction might cause falling damage. - if (!GeoData.getInstance().hasGeo(getX(), getY())) + if (!GeoEngine.getInstance().hasGeo(getX(), getY())) { return false; } diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java index af1054767c..2337da2419 100644 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java @@ -49,7 +49,7 @@ import com.l2jmobius.gameserver.enums.ItemLocation; import com.l2jmobius.gameserver.enums.ItemSkillType; import com.l2jmobius.gameserver.enums.ShotType; import com.l2jmobius.gameserver.enums.UserInfoType; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.idfactory.IdFactory; import com.l2jmobius.gameserver.instancemanager.CastleManager; import com.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager; @@ -1512,7 +1512,7 @@ public final class L2ItemInstance extends L2Object if (_dropper != null) { final Instance instance = _dropper.getInstanceWorld(); - final Location dropDest = GeoData.getInstance().moveCheck(_dropper.getX(), _dropper.getY(), _dropper.getZ(), _x, _y, _z, instance); + final Location dropDest = GeoEngine.getInstance().canMoveToTargetLoc(_dropper.getX(), _dropper.getY(), _dropper.getZ(), _x, _y, _z, instance); _x = dropDest.getX(); _y = dropDest.getY(); _z = dropDest.getZ(); diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java index 9780892efe..9c70018363 100644 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java @@ -37,7 +37,7 @@ import com.l2jmobius.gameserver.datatables.ItemTable; import com.l2jmobius.gameserver.enums.ItemSkillType; import com.l2jmobius.gameserver.enums.NextActionType; import com.l2jmobius.gameserver.enums.StatusUpdateType; -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; @@ -1009,7 +1009,7 @@ public class SkillCaster implements Runnable } } - final Location destination = GeoData.getInstance().moveCheck(creature.getX(), creature.getY(), creature.getZ(), x, y, z, creature.getInstanceWorld()); + final Location destination = GeoEngine.getInstance().canMoveToTargetLoc(creature.getX(), creature.getY(), creature.getZ(), x, y, z, creature.getInstanceWorld()); creature.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); creature.broadcastPacket(new FlyToLocation(creature, destination, flyType, 0, 0, 333)); diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/skills/SkillChannelizer.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/skills/SkillChannelizer.java index 3875eb6830..cc1667a637 100644 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/skills/SkillChannelizer.java +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/skills/SkillChannelizer.java @@ -25,7 +25,7 @@ import java.util.logging.Logger; import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.data.xml.impl.SkillData; import com.l2jmobius.gameserver.enums.ShotType; -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.instance.L2PcInstance; @@ -185,7 +185,7 @@ public class SkillChannelizer implements Runnable { continue; } - else if (!GeoData.getInstance().canSeeTarget(_channelizer, character)) + else if (!GeoEngine.getInstance().canSeeTarget(_channelizer, character)) { continue; } diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/zone/form/ZoneCuboid.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/zone/form/ZoneCuboid.java index 58d967f84d..4433e97b28 100644 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/zone/form/ZoneCuboid.java +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/zone/form/ZoneCuboid.java @@ -19,7 +19,7 @@ package com.l2jmobius.gameserver.model.zone.form; import java.awt.Rectangle; import com.l2jmobius.commons.util.Rnd; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.model.Location; import com.l2jmobius.gameserver.model.itemcontainer.Inventory; import com.l2jmobius.gameserver.model.zone.L2ZoneForm; @@ -131,6 +131,6 @@ public class ZoneCuboid extends L2ZoneForm final int x = Rnd.get(_r.x, _r.x + _r.width); final int y = Rnd.get(_r.y, _r.y + _r.height); - return new Location(x, y, GeoData.getInstance().getHeight(x, y, _z1)); + return new Location(x, y, GeoEngine.getInstance().getHeight(x, y, _z1)); } } diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/zone/form/ZoneCylinder.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/zone/form/ZoneCylinder.java index 969dd7d029..afdfd3fade 100644 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/zone/form/ZoneCylinder.java +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/zone/form/ZoneCylinder.java @@ -17,7 +17,7 @@ package com.l2jmobius.gameserver.model.zone.form; import com.l2jmobius.commons.util.Rnd; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.model.Location; import com.l2jmobius.gameserver.model.itemcontainer.Inventory; import com.l2jmobius.gameserver.model.zone.L2ZoneForm; @@ -146,6 +146,6 @@ public class ZoneCylinder extends L2ZoneForm x = (int) ((_rad * r * Math.cos(q)) + _x); y = (int) ((_rad * r * Math.sin(q)) + _y); - return new Location(x, y, GeoData.getInstance().getHeight(x, y, _z1)); + return new Location(x, y, GeoEngine.getInstance().getHeight(x, y, _z1)); } } diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/zone/form/ZoneNPoly.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/zone/form/ZoneNPoly.java index 6da33d788e..2340c1b218 100644 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/zone/form/ZoneNPoly.java +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/model/zone/form/ZoneNPoly.java @@ -19,7 +19,7 @@ package com.l2jmobius.gameserver.model.zone.form; import java.awt.Polygon; import com.l2jmobius.commons.util.Rnd; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.model.Location; import com.l2jmobius.gameserver.model.itemcontainer.Inventory; import com.l2jmobius.gameserver.model.zone.L2ZoneForm; @@ -138,7 +138,7 @@ public class ZoneNPoly extends L2ZoneForm y = Rnd.get(_minY, _maxY); } - return new Location(x, y, GeoData.getInstance().getHeight(x, y, _z1)); + return new Location(x, y, GeoEngine.getInstance().getHeight(x, y, _z1)); } public int[] getX() diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/util/GeoUtils.java b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/util/GeoUtils.java index 21540f2215..dba01759ef 100644 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/util/GeoUtils.java +++ b/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/util/GeoUtils.java @@ -18,8 +18,8 @@ package com.l2jmobius.gameserver.util; import java.awt.Color; -import com.l2jmobius.gameserver.geodata.GeoData; -import com.l2jmobius.gameserver.geodata.geodriver.Cell; +import com.l2jmobius.gameserver.geoengine.GeoEngine; +import com.l2jmobius.gameserver.geoengine.geodata.GeoStructure; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.network.serverpackets.ExServerPrimitive; @@ -30,21 +30,21 @@ public final class GeoUtils { public static void debug2DLine(L2PcInstance player, int x, int y, int tx, int ty, int z) { - final int gx = GeoData.getInstance().getGeoX(x); - final int gy = GeoData.getInstance().getGeoY(y); + final int gx = GeoEngine.getInstance().getGeoX(x); + final int gy = GeoEngine.getInstance().getGeoY(y); - final int tgx = GeoData.getInstance().getGeoX(tx); - final int tgy = GeoData.getInstance().getGeoY(ty); + final int tgx = GeoEngine.getInstance().getGeoX(tx); + final int tgy = GeoEngine.getInstance().getGeoY(ty); final ExServerPrimitive prim = new ExServerPrimitive("Debug2DLine", x, y, z); - prim.addLine(Color.BLUE, GeoData.getInstance().getWorldX(gx), GeoData.getInstance().getWorldY(gy), z, GeoData.getInstance().getWorldX(tgx), GeoData.getInstance().getWorldY(tgy), z); + prim.addLine(Color.BLUE, GeoEngine.getInstance().getWorldX(gx), GeoEngine.getInstance().getWorldY(gy), z, GeoEngine.getInstance().getWorldX(tgx), GeoEngine.getInstance().getWorldY(tgy), z); final LinePointIterator iter = new LinePointIterator(gx, gy, tgx, tgy); while (iter.next()) { - final int wx = GeoData.getInstance().getWorldX(iter.x()); - final int wy = GeoData.getInstance().getWorldY(iter.y()); + final int wx = GeoEngine.getInstance().getWorldX(iter.x()); + final int wy = GeoEngine.getInstance().getWorldY(iter.y()); prim.addPoint(Color.RED, wx, wy, z); } @@ -53,21 +53,21 @@ public final class GeoUtils public static void debug3DLine(L2PcInstance player, int x, int y, int z, int tx, int ty, int tz) { - final int gx = GeoData.getInstance().getGeoX(x); - final int gy = GeoData.getInstance().getGeoY(y); + final int gx = GeoEngine.getInstance().getGeoX(x); + final int gy = GeoEngine.getInstance().getGeoY(y); - final int tgx = GeoData.getInstance().getGeoX(tx); - final int tgy = GeoData.getInstance().getGeoY(ty); + final int tgx = GeoEngine.getInstance().getGeoX(tx); + final int tgy = GeoEngine.getInstance().getGeoY(ty); final ExServerPrimitive prim = new ExServerPrimitive("Debug3DLine", x, y, z); - prim.addLine(Color.BLUE, GeoData.getInstance().getWorldX(gx), GeoData.getInstance().getWorldY(gy), z, GeoData.getInstance().getWorldX(tgx), GeoData.getInstance().getWorldY(tgy), tz); + prim.addLine(Color.BLUE, GeoEngine.getInstance().getWorldX(gx), GeoEngine.getInstance().getWorldY(gy), z, GeoEngine.getInstance().getWorldX(tgx), GeoEngine.getInstance().getWorldY(tgy), tz); final LinePointIterator3D iter = new LinePointIterator3D(gx, gy, z, tgx, tgy, tz); iter.next(); int prevX = iter.x(); int prevY = iter.y(); - int wx = GeoData.getInstance().getWorldX(prevX); - int wy = GeoData.getInstance().getWorldY(prevY); + int wx = GeoEngine.getInstance().getWorldX(prevX); + int wy = GeoEngine.getInstance().getWorldY(prevY); int wz = iter.z(); prim.addPoint(Color.RED, wx, wy, wz); @@ -78,8 +78,8 @@ public final class GeoUtils if ((curX != prevX) || (curY != prevY)) { - wx = GeoData.getInstance().getWorldX(curX); - wy = GeoData.getInstance().getWorldY(curY); + wx = GeoEngine.getInstance().getWorldX(curX); + wy = GeoEngine.getInstance().getWorldY(curY); wz = iter.z(); prim.addPoint(Color.RED, wx, wy, wz); @@ -93,7 +93,7 @@ public final class GeoUtils private static Color getDirectionColor(int x, int y, int z, int nswe) { - if (GeoData.getInstance().checkNearestNswe(x, y, z, nswe)) + if ((GeoEngine.getInstance().getNsweNearest(x, y, z) & nswe) == nswe) { return Color.GREEN; } @@ -109,7 +109,7 @@ public final class GeoUtils int iPacket = 0; ExServerPrimitive exsp = null; - final GeoData gd = GeoData.getInstance(); + final GeoEngine gd = GeoEngine.getInstance(); final int playerGx = gd.getGeoX(player.getX()); final int playerGy = gd.getGeoY(player.getY()); for (int dx = -geoRadius; dx <= geoRadius; ++dx) @@ -137,30 +137,30 @@ public final class GeoUtils final int x = gd.getWorldX(gx); final int y = gd.getWorldY(gy); - final int z = gd.getNearestZ(gx, gy, player.getZ()); + final int z = gd.getHeightNearest(gx, gy, player.getZ()); // north arrow - Color col = getDirectionColor(gx, gy, z, Cell.NSWE_NORTH); + Color col = getDirectionColor(gx, gy, z, GeoStructure.CELL_FLAG_N); exsp.addLine(col, x - 1, y - 7, z, x + 1, y - 7, z); exsp.addLine(col, x - 2, y - 6, z, x + 2, y - 6, z); exsp.addLine(col, x - 3, y - 5, z, x + 3, y - 5, z); exsp.addLine(col, x - 4, y - 4, z, x + 4, y - 4, z); // east arrow - col = getDirectionColor(gx, gy, z, Cell.NSWE_EAST); + col = getDirectionColor(gx, gy, z, GeoStructure.CELL_FLAG_E); exsp.addLine(col, x + 7, y - 1, z, x + 7, y + 1, z); exsp.addLine(col, x + 6, y - 2, z, x + 6, y + 2, z); exsp.addLine(col, x + 5, y - 3, z, x + 5, y + 3, z); exsp.addLine(col, x + 4, y - 4, z, x + 4, y + 4, z); // south arrow - col = getDirectionColor(gx, gy, z, Cell.NSWE_SOUTH); + col = getDirectionColor(gx, gy, z, GeoStructure.CELL_FLAG_S); exsp.addLine(col, x - 1, y + 7, z, x + 1, y + 7, z); exsp.addLine(col, x - 2, y + 6, z, x + 2, y + 6, z); exsp.addLine(col, x - 3, y + 5, z, x + 3, y + 5, z); exsp.addLine(col, x - 4, y + 4, z, x + 4, y + 4, z); - col = getDirectionColor(gx, gy, z, Cell.NSWE_WEST); + col = getDirectionColor(gx, gy, z, GeoStructure.CELL_FLAG_W); exsp.addLine(col, x - 7, y - 1, z, x - 7, y + 1, z); exsp.addLine(col, x - 6, y - 2, z, x - 6, y + 2, z); exsp.addLine(col, x - 5, y - 3, z, x - 5, y + 3, z); @@ -188,30 +188,30 @@ public final class GeoUtils { if (y > lastY) { - return Cell.NSWE_SOUTH_EAST; // Direction.SOUTH_EAST; + return GeoStructure.CELL_FLAG_SE; // Direction.SOUTH_EAST; } else if (y < lastY) { - return Cell.NSWE_NORTH_EAST; // Direction.NORTH_EAST; + return GeoStructure.CELL_FLAG_NE; // Direction.NORTH_EAST; } else { - return Cell.NSWE_EAST; // Direction.EAST; + return GeoStructure.CELL_FLAG_E; // Direction.EAST; } } else if (x < lastX) // west { if (y > lastY) { - return Cell.NSWE_SOUTH_WEST; // Direction.SOUTH_WEST; + return GeoStructure.CELL_FLAG_SW; // Direction.SOUTH_WEST; } else if (y < lastY) { - return Cell.NSWE_NORTH_WEST; // Direction.NORTH_WEST; + return GeoStructure.CELL_FLAG_NW; // Direction.NORTH_WEST; } else { - return Cell.NSWE_WEST; // Direction.WEST; + return GeoStructure.CELL_FLAG_W; // Direction.WEST; } } else @@ -219,11 +219,11 @@ public final class GeoUtils { if (y > lastY) { - return Cell.NSWE_SOUTH; // Direction.SOUTH; + return GeoStructure.CELL_FLAG_S; // Direction.SOUTH; } else if (y < lastY) { - return Cell.NSWE_NORTH; // Direction.NORTH; + return GeoStructure.CELL_FLAG_N; // Direction.NORTH; } else { diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/tools/geodataconverter/GeoDataConverter.java b/L2J_Mobius_Classic/java/com/l2jmobius/tools/geodataconverter/GeoDataConverter.java new file mode 100644 index 0000000000..81621d8ee6 --- /dev/null +++ b/L2J_Mobius_Classic/java/com/l2jmobius/tools/geodataconverter/GeoDataConverter.java @@ -0,0 +1,375 @@ +/* + * 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 . + */ +package com.l2jmobius.tools.geodataconverter; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.RandomAccessFile; +import java.nio.ByteOrder; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.util.Scanner; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.PropertiesParser; +import com.l2jmobius.gameserver.geoengine.geodata.ABlock; +import com.l2jmobius.gameserver.geoengine.geodata.BlockComplex; +import com.l2jmobius.gameserver.geoengine.geodata.BlockFlat; +import com.l2jmobius.gameserver.geoengine.geodata.BlockMultilayer; +import com.l2jmobius.gameserver.geoengine.geodata.GeoFormat; +import com.l2jmobius.gameserver.geoengine.geodata.GeoStructure; +import com.l2jmobius.gameserver.model.L2World; + +/** + * @author Hasha + */ +public final class GeoDataConverter +{ + private static GeoFormat _format; + private static ABlock[][] _blocks; + + public static void main(String[] args) + { + // initialize config + loadGeoengineConfigs(); + + // get geodata format + String type = ""; + try (Scanner scn = new Scanner(System.in)) + { + while (!(type.equalsIgnoreCase("J") || type.equalsIgnoreCase("O") || type.equalsIgnoreCase("E"))) + { + System.out.println("GeoDataConverter: Select source geodata type:"); + System.out.println(" J: L2J (e.g. 23_22.l2j)"); + System.out.println(" O: L2OFF (e.g. 23_22_conv.dat)"); + System.out.println(" E: Exit"); + System.out.print("Choice: "); + type = scn.next(); + } + } + if (type.equalsIgnoreCase("E")) + { + System.exit(0); + } + + _format = type.equalsIgnoreCase("J") ? GeoFormat.L2J : GeoFormat.L2OFF; + + // start conversion + System.out.println("GeoDataConverter: Converting all " + _format.toString() + " files."); + + // initialize geodata container + _blocks = new ABlock[GeoStructure.REGION_BLOCKS_X][GeoStructure.REGION_BLOCKS_Y]; + + // initialize multilayer temporarily buffer + BlockMultilayer.initialize(); + + // load geo files + int converted = 0; + for (int rx = L2World.TILE_X_MIN; rx <= L2World.TILE_X_MAX; rx++) + { + for (int ry = L2World.TILE_Y_MIN; ry <= L2World.TILE_Y_MAX; ry++) + { + final String input = String.format(_format.getFilename(), rx, ry); + final String filepath = Config.GEODATA_PATH; + File f = new File(filepath + input); + if (f.exists() && !f.isDirectory()) + { + // load geodata + if (!loadGeoBlocks(input)) + { + System.out.println("GeoDataConverter: Unable to load " + input + " region file."); + continue; + } + + // recalculate nswe + if (!recalculateNswe()) + { + System.out.println("GeoDataConverter: Unable to convert " + input + " region file."); + continue; + } + + // save geodata + final String output = String.format(GeoFormat.L2D.getFilename(), rx, ry); + if (!saveGeoBlocks(output)) + { + System.out.println("GeoDataConverter: Unable to save " + output + " region file."); + continue; + } + + converted++; + System.out.println("GeoDataConverter: Created " + output + " region file."); + } + } + } + System.out.println("GeoDataConverter: Converted " + converted + " " + _format.toString() + " to L2D region file(s)."); + + // release multilayer block temporarily buffer + BlockMultilayer.release(); + } + + /** + * Loads geo blocks from buffer of the region file. + * @param filename : The name of the to load. + * @return boolean : True when successful. + */ + private static final boolean loadGeoBlocks(String filename) + { + // region file is load-able, try to load it + try (RandomAccessFile raf = new RandomAccessFile(Config.GEODATA_PATH + filename, "r"); + FileChannel fc = raf.getChannel()) + { + MappedByteBuffer buffer = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()).load(); + buffer.order(ByteOrder.LITTLE_ENDIAN); + + // load 18B header for L2off geodata (1st and 2nd byte...region X and Y) + if (_format == GeoFormat.L2OFF) + { + for (int i = 0; i < 18; i++) + { + buffer.get(); + } + } + + // loop over region blocks + for (int ix = 0; ix < GeoStructure.REGION_BLOCKS_X; ix++) + { + for (int iy = 0; iy < GeoStructure.REGION_BLOCKS_Y; iy++) + { + if (_format == GeoFormat.L2J) + { + // get block type + final byte type = buffer.get(); + + // load block according to block type + switch (type) + { + case GeoStructure.TYPE_FLAT_L2J_L2OFF: + _blocks[ix][iy] = new BlockFlat(buffer, _format); + break; + + case GeoStructure.TYPE_COMPLEX_L2J: + _blocks[ix][iy] = new BlockComplex(buffer, _format); + break; + + case GeoStructure.TYPE_MULTILAYER_L2J: + _blocks[ix][iy] = new BlockMultilayer(buffer, _format); + break; + + default: + throw new IllegalArgumentException("Unknown block type: " + type); + } + } + else + { + // get block type + final short type = buffer.getShort(); + + // load block according to block type + switch (type) + { + case GeoStructure.TYPE_FLAT_L2J_L2OFF: + _blocks[ix][iy] = new BlockFlat(buffer, _format); + break; + + case GeoStructure.TYPE_COMPLEX_L2OFF: + _blocks[ix][iy] = new BlockComplex(buffer, _format); + break; + + default: + _blocks[ix][iy] = new BlockMultilayer(buffer, _format); + break; + } + } + } + } + + if (buffer.remaining() > 0) + { + System.out.println("GeoDataConverter: Region file " + filename + " can be corrupted, remaining " + buffer.remaining() + " bytes to read."); + return false; + } + + return true; + } + catch (Exception e) + { + System.out.println("GeoDataConverter: Error while loading " + filename + " region file."); + return false; + } + } + + /** + * Recalculate diagonal flags for the region file. + * @return boolean : True when successful. + */ + private static final boolean recalculateNswe() + { + try + { + for (int x = 0; x < GeoStructure.REGION_CELLS_X; x++) + { + for (int y = 0; y < GeoStructure.REGION_CELLS_Y; y++) + { + // get block + ABlock block = _blocks[x / GeoStructure.BLOCK_CELLS_X][y / GeoStructure.BLOCK_CELLS_Y]; + + // skip flat blocks + if (block instanceof BlockFlat) + { + continue; + } + + // for complex and multilayer blocks go though all layers + short height = Short.MAX_VALUE; + int index; + while ((index = block.getIndexBelow(x, y, height)) != -1) + { + // get height and nswe + height = block.getHeight(index); + byte nswe = block.getNswe(index); + + // update nswe with diagonal flags + nswe = updateNsweBelow(x, y, height, nswe); + + // set nswe of the cell + block.setNswe(index, nswe); + } + } + } + + return true; + } + catch (Exception e) + { + return false; + } + } + + /** + * Updates the NSWE flag with diagonal flags. + * @param x : Geodata X coordinate. + * @param y : Geodata Y coordinate. + * @param z : Geodata Z coordinate. + * @param nswe : NSWE flag to be updated. + * @return byte : Updated NSWE flag. + */ + private static final byte updateNsweBelow(int x, int y, short z, byte nswe) + { + // calculate virtual layer height + short height = (short) (z + GeoStructure.CELL_IGNORE_HEIGHT); + + // get NSWE of neighbor cells below virtual layer (NPC/PC can fall down of clif, but can not climb it -> NSWE of cell below) + byte nsweN = getNsweBelow(x, y - 1, height); + byte nsweS = getNsweBelow(x, y + 1, height); + byte nsweW = getNsweBelow(x - 1, y, height); + byte nsweE = getNsweBelow(x + 1, y, height); + + // north-west + if ((((nswe & GeoStructure.CELL_FLAG_N) != 0) && ((nsweN & GeoStructure.CELL_FLAG_W) != 0)) || (((nswe & GeoStructure.CELL_FLAG_W) != 0) && ((nsweW & GeoStructure.CELL_FLAG_N) != 0))) + { + nswe |= GeoStructure.CELL_FLAG_NW; + } + + // north-east + if ((((nswe & GeoStructure.CELL_FLAG_N) != 0) && ((nsweN & GeoStructure.CELL_FLAG_E) != 0)) || (((nswe & GeoStructure.CELL_FLAG_E) != 0) && ((nsweE & GeoStructure.CELL_FLAG_N) != 0))) + { + nswe |= GeoStructure.CELL_FLAG_NE; + } + + // south-west + if ((((nswe & GeoStructure.CELL_FLAG_S) != 0) && ((nsweS & GeoStructure.CELL_FLAG_W) != 0)) || (((nswe & GeoStructure.CELL_FLAG_W) != 0) && ((nsweW & GeoStructure.CELL_FLAG_S) != 0))) + { + nswe |= GeoStructure.CELL_FLAG_SW; + } + + // south-east + if ((((nswe & GeoStructure.CELL_FLAG_S) != 0) && ((nsweS & GeoStructure.CELL_FLAG_E) != 0)) || (((nswe & GeoStructure.CELL_FLAG_E) != 0) && ((nsweE & GeoStructure.CELL_FLAG_S) != 0))) + { + nswe |= GeoStructure.CELL_FLAG_SE; + } + + return nswe; + } + + private static final byte getNsweBelow(int geoX, int geoY, short worldZ) + { + // out of geo coordinates + if ((geoX < 0) || (geoX >= GeoStructure.REGION_CELLS_X)) + { + return 0; + } + + // out of geo coordinates + if ((geoY < 0) || (geoY >= GeoStructure.REGION_CELLS_Y)) + { + return 0; + } + + // get block + final ABlock block = _blocks[geoX / GeoStructure.BLOCK_CELLS_X][geoY / GeoStructure.BLOCK_CELLS_Y]; + + // get index, when valid, return nswe + final int index = block.getIndexBelow(geoX, geoY, worldZ); + return index == -1 ? 0 : block.getNswe(index); + } + + /** + * Save region file to file. + * @param filename : The name of file to save. + * @return boolean : True when successful. + */ + private static final boolean saveGeoBlocks(String filename) + { + try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(Config.GEODATA_PATH + filename), GeoStructure.REGION_BLOCKS * GeoStructure.BLOCK_CELLS * 3)) + { + // loop over region blocks and save each block + for (int ix = 0; ix < GeoStructure.REGION_BLOCKS_X; ix++) + { + for (int iy = 0; iy < GeoStructure.REGION_BLOCKS_Y; iy++) + { + _blocks[ix][iy].saveBlock(bos); + } + } + + // flush data to file + bos.flush(); + + return true; + } + catch (Exception e) + { + return false; + } + } + + private static final void loadGeoengineConfigs() + { + final PropertiesParser geoData = new PropertiesParser(Config.GEODATA_FILE); + Config.GEODATA_PATH = geoData.getString("GeoDataPath", "./data/geodata/"); + Config.COORD_SYNCHRONIZE = geoData.getInt("CoordSynchronize", -1); + Config.PART_OF_CHARACTER_HEIGHT = geoData.getInt("PartOfCharacterHeight", 75); + Config.MAX_OBSTACLE_HEIGHT = geoData.getInt("MaxObstacleHeight", 32); + Config.PATHFINDING = geoData.getBoolean("PathFinding", true); + Config.PATHFIND_BUFFERS = geoData.getString("PathFindBuffers", "100x6;128x6;192x6;256x4;320x4;384x4;500x2"); + Config.BASE_WEIGHT = geoData.getInt("BaseWeight", 10); + Config.DIAGONAL_WEIGHT = geoData.getInt("DiagonalWeight", 14); + Config.OBSTACLE_MULTIPLIER = geoData.getInt("ObstacleMultiplier", 10); + Config.HEURISTIC_WEIGHT = geoData.getInt("HeuristicWeight", 20); + Config.MAX_ITERATIONS = geoData.getInt("MaxIterations", 3500); + } +} \ No newline at end of file diff --git a/L2J_Mobius_Ertheia/build.xml b/L2J_Mobius_Ertheia/build.xml index 354f09c918..c0699ee61e 100644 --- a/L2J_Mobius_Ertheia/build.xml +++ b/L2J_Mobius_Ertheia/build.xml @@ -74,6 +74,7 @@ + diff --git a/L2J_Mobius_Ertheia/dist/game/GeoDataConverter.bat b/L2J_Mobius_Ertheia/dist/game/GeoDataConverter.bat new file mode 100644 index 0000000000..1f199613e9 --- /dev/null +++ b/L2J_Mobius_Ertheia/dist/game/GeoDataConverter.bat @@ -0,0 +1,6 @@ +@echo off +title L2D geodata converter + +java -Xmx512m -cp ./../libs/*;GameServer.jar com.l2jmobius.tools.geodataconverter.GeoDataConverter + +pause diff --git a/L2J_Mobius_Ertheia/dist/game/GeoDataConverter.sh b/L2J_Mobius_Ertheia/dist/game/GeoDataConverter.sh new file mode 100644 index 0000000000..b039beec34 --- /dev/null +++ b/L2J_Mobius_Ertheia/dist/game/GeoDataConverter.sh @@ -0,0 +1,4 @@ +#! /bin/sh + +java -Xmx512m -cp ./../libs/*;GameServer.jar com.l2jmobius.tools.geodataconverter.GeoDataConverter > log/stdout.log 2>&1 + diff --git a/L2J_Mobius_Ertheia/dist/game/config/AdminCommands.xml b/L2J_Mobius_Ertheia/dist/game/config/AdminCommands.xml index d2ff6c880f..1cca083da9 100644 --- a/L2J_Mobius_Ertheia/dist/game/config/AdminCommands.xml +++ b/L2J_Mobius_Ertheia/dist/game/config/AdminCommands.xml @@ -413,11 +413,7 @@ - - - - - + diff --git a/L2J_Mobius_Ertheia/dist/game/config/GeoData.ini b/L2J_Mobius_Ertheia/dist/game/config/GeoData.ini deleted file mode 100644 index 52ef701461..0000000000 --- a/L2J_Mobius_Ertheia/dist/game/config/GeoData.ini +++ /dev/null @@ -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 diff --git a/L2J_Mobius_Ertheia/dist/game/config/GeoEngine.ini b/L2J_Mobius_Ertheia/dist/game/config/GeoEngine.ini new file mode 100644 index 0000000000..94a0b1ac44 --- /dev/null +++ b/L2J_Mobius_Ertheia/dist/game/config/GeoEngine.ini @@ -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 diff --git a/L2J_Mobius_Ertheia/dist/game/data/geodata/Readme.txt b/L2J_Mobius_Ertheia/dist/game/data/geodata/Readme.txt index bf1f2071aa..8b18814e82 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/geodata/Readme.txt +++ b/L2J_Mobius_Ertheia/dist/game/data/geodata/Readme.txt @@ -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 # -# # -##################################################### \ No newline at end of file +############################################## +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. diff --git a/L2J_Mobius_Ertheia/dist/game/data/pathnode/Readme.txt b/L2J_Mobius_Ertheia/dist/game/data/pathnode/Readme.txt deleted file mode 100644 index 2dfdaa8aab..0000000000 --- a/L2J_Mobius_Ertheia/dist/game/data/pathnode/Readme.txt +++ /dev/null @@ -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 # -# # -##################################################### \ No newline at end of file diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/ImperialTomb/FourSepulchers/FourSepulchers.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/ImperialTomb/FourSepulchers/FourSepulchers.java index d53bc8c351..954afd0819 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/ImperialTomb/FourSepulchers/FourSepulchers.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/ImperialTomb/FourSepulchers/FourSepulchers.java @@ -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); diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/KartiasLabyrinth/KartiaHelperAdolph.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/KartiasLabyrinth/KartiaHelperAdolph.java index 2a3e8902fa..1e7527c930 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/KartiasLabyrinth/KartiaHelperAdolph.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/KartiasLabyrinth/KartiaHelperAdolph.java @@ -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)) { diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/KartiasLabyrinth/KartiaSupportTroop.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/KartiasLabyrinth/KartiaSupportTroop.java index 4359ebca01..0b6462a39e 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/KartiasLabyrinth/KartiaSupportTroop.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/KartiasLabyrinth/KartiaSupportTroop.java @@ -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); } diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/PlainsOfDion/PlainsOfDion.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/PlainsOfDion/PlainsOfDion.java index d6334e36c2..c1387a6527 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/PlainsOfDion/PlainsOfDion.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/PlainsOfDion/PlainsOfDion.java @@ -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)]); diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/PrimevalIsle/PrimevalIsle.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/PrimevalIsle/PrimevalIsle.java index d02786fc20..1ccd0b2a99 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/PrimevalIsle/PrimevalIsle.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/PrimevalIsle/PrimevalIsle.java @@ -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) diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/BoyAndGirl.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/BoyAndGirl.java index 64c6501bd8..594ba85809 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/BoyAndGirl.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/BoyAndGirl.java @@ -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); } diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/Devno.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/Devno.java index 3dd3b671cb..5b67a2a2e7 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/Devno.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/Devno.java @@ -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); } diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/Eleve.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/Eleve.java index 7900817585..2258392af4 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/Eleve.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/Eleve.java @@ -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); } diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/Handermonkey.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/Handermonkey.java index cb173a5030..e66acd12da 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/Handermonkey.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/Handermonkey.java @@ -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 diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/Karonf.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/Karonf.java index 7297eeca95..0cd3444fd8 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/Karonf.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/Karonf.java @@ -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); } diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/Marsha.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/Marsha.java index dbbba8d5f0..bae9a9253a 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/Marsha.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/Marsha.java @@ -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); } diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/Morgan.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/Morgan.java index f976d88263..fc7164bd5f 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/Morgan.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/Morgan.java @@ -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); } diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/Rubentis.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/Rubentis.java index 19b9fd7893..e50e2bc306 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/Rubentis.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/areas/TalkingIsland/Rubentis.java @@ -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); } diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/bosses/Frintezza/ScarletVanHalisha.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/bosses/Frintezza/ScarletVanHalisha.java index 175973cc3d..139154e05a 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/bosses/Frintezza/ScarletVanHalisha.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/bosses/Frintezza/ScarletVanHalisha.java @@ -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; } diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/bosses/Tiat/Stage1.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/bosses/Tiat/Stage1.java index 6eb16f838e..a852734cb4 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/bosses/Tiat/Stage1.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/bosses/Tiat/Stage1.java @@ -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); } } } diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/bosses/Valakas/Valakas.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/bosses/Valakas/Valakas.java index 9f5375d349..4275a803e2 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/bosses/Valakas/Valakas.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/bosses/Valakas/Valakas.java @@ -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)); } diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/others/FleeMonsters.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/others/FleeMonsters.java index b377af5c37..632e19d481 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/others/FleeMonsters.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/ai/others/FleeMonsters.java @@ -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); } diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/actionhandlers/L2PcInstanceAction.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/actionhandlers/L2PcInstanceAction.java index eb06ec5594..13902652f4 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/actionhandlers/L2PcInstanceAction.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/actionhandlers/L2PcInstanceAction.java @@ -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); } diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/actionhandlers/L2PetInstanceAction.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/actionhandlers/L2PetInstanceAction.java index c21b0e6ca1..5c2fe5e762 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/actionhandlers/L2PetInstanceAction.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/actionhandlers/L2PetInstanceAction.java @@ -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(); diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/actionhandlers/L2SummonAction.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/actionhandlers/L2SummonAction.java index b6af1a7ca4..11b1192023 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/actionhandlers/L2SummonAction.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/actionhandlers/L2SummonAction.java @@ -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); } diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminGeodata.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminGeodata.java index bfa36a76d5..551e52bbb0 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminGeodata.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminGeodata.java @@ -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."); } diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminPathNode.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminPathNode.java index 03b3ca8902..9cb85c282f 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminPathNode.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminPathNode.java @@ -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 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 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; } diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminServerInfo.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminServerInfo.java index 6796381333..867836c680 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminServerInfo.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminServerInfo.java @@ -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")); diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminTeleport.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminTeleport.java index 1b738a0264..fbf049aae5 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminTeleport.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminTeleport.java @@ -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); } diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminZones.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminZones.java index d6949af214..d5baa52a73 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminZones.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminZones.java @@ -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); } diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/effecthandlers/Blink.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/effecthandlers/Blink.java index 0e1c1d1aca..db1463c04d 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/effecthandlers/Blink.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/effecthandlers/Blink.java @@ -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)); diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/effecthandlers/Fear.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/effecthandlers/Fear.java index 7525c0f5ec..78fc694005 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/effecthandlers/Fear.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/effecthandlers/Fear.java @@ -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); } } diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/effecthandlers/FlyAway.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/effecthandlers/FlyAway.java index 1da9965557..a4d5e7f74b 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/effecthandlers/FlyAway.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/effecthandlers/FlyAway.java @@ -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); diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/effecthandlers/KnockBack.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/effecthandlers/KnockBack.java index ad73aef663..e2ddb48286 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/effecthandlers/KnockBack.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/effecthandlers/KnockBack.java @@ -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)); diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/effecthandlers/PullBack.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/effecthandlers/PullBack.java index 7850b26d5d..07b43c83d3 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/effecthandlers/PullBack.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/effecthandlers/PullBack.java @@ -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); diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/effecthandlers/TeleportToSummon.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/effecthandlers/TeleportToSummon.java index 8144305363..bffc2aecce 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/effecthandlers/TeleportToSummon.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/effecthandlers/TeleportToSummon.java @@ -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)); diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/effecthandlers/TeleportToTarget.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/effecthandlers/TeleportToTarget.java index 93ffb3174d..81504f196e 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/effecthandlers/TeleportToTarget.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/effecthandlers/TeleportToTarget.java @@ -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)); diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/skillconditionhandlers/OpBlinkSkillCondition.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/skillconditionhandlers/OpBlinkSkillCondition.java index 4b33ad31b2..bea71eb6e5 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/skillconditionhandlers/OpBlinkSkillCondition.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/skillconditionhandlers/OpBlinkSkillCondition.java @@ -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()); } } diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/Enemy.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/Enemy.java index b16408fba4..91fc781e3f 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/Enemy.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/Enemy.java @@ -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) { diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/EnemyNot.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/EnemyNot.java index 005d4e0ee1..00d3d4d8e2 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/EnemyNot.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/EnemyNot.java @@ -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) { diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/EnemyOnly.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/EnemyOnly.java index 2f5a79d6f5..5815598285 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/EnemyOnly.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/EnemyOnly.java @@ -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) { diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/Ground.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/Ground.java index f3b38dcf71..280f19d239 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/Ground.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/Ground.java @@ -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) { diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/NpcBody.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/NpcBody.java index 699fa269c7..7f46507e5b 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/NpcBody.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/NpcBody.java @@ -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) { diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/PcBody.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/PcBody.java index 77a9c9edd3..0ef234b8ac 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/PcBody.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/PcBody.java @@ -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) { diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/Target.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/Target.java index b388976172..f8456ed9f9 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/Target.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/Target.java @@ -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) { diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/affectscope/Fan.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/affectscope/Fan.java index 2487c40d5e..59b2d086d5 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/affectscope/Fan.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/affectscope/Fan.java @@ -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; } diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/affectscope/FanPB.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/affectscope/FanPB.java index ec987c91eb..d6783cff58 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/affectscope/FanPB.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/affectscope/FanPB.java @@ -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; } diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/affectscope/PointBlank.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/affectscope/PointBlank.java index d6c63186a2..2f7568dd13 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/affectscope/PointBlank.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/affectscope/PointBlank.java @@ -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; } diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/affectscope/Range.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/affectscope/Range.java index 90abebd98f..1d8ccd51e8 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/affectscope/Range.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/affectscope/Range.java @@ -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; } diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/affectscope/RingRange.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/affectscope/RingRange.java index 6cbe61fe1c..24c89e82d5 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/affectscope/RingRange.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/affectscope/RingRange.java @@ -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; } diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/affectscope/Square.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/affectscope/Square.java index 3225de6245..c39a270d2c 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/affectscope/Square.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/affectscope/Square.java @@ -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; } diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/affectscope/SquarePB.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/affectscope/SquarePB.java index 7ffad78a8f..1f695cc99d 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/affectscope/SquarePB.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/handlers/targethandlers/affectscope/SquarePB.java @@ -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; } diff --git a/L2J_Mobius_Ertheia/dist/game/data/scripts/quests/Q10753_WindsOfFateChoices/Q10753_WindsOfFateChoices.java b/L2J_Mobius_Ertheia/dist/game/data/scripts/quests/Q10753_WindsOfFateChoices/Q10753_WindsOfFateChoices.java index 27db36439a..a7b209b403 100644 --- a/L2J_Mobius_Ertheia/dist/game/data/scripts/quests/Q10753_WindsOfFateChoices/Q10753_WindsOfFateChoices.java +++ b/L2J_Mobius_Ertheia/dist/game/data/scripts/quests/Q10753_WindsOfFateChoices/Q10753_WindsOfFateChoices.java @@ -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(); } diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/Config.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/Config.java index ec2adcc0d6..d22501feda 100644 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/Config.java +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/Config.java @@ -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 @@ -922,22 +920,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 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 @@ -2250,41 +2252,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); diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/commons/util/MathUtil.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/commons/util/MathUtil.java index 91dfcc4171..b0867bb70f 100644 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/commons/util/MathUtil.java +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/commons/util/MathUtil.java @@ -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); + } } diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/GameServer.java index d0cc037cb0..032fd33167 100644 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/GameServer.java @@ -95,8 +95,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.EffectHandler; import com.l2jmobius.gameserver.handler.SkillConditionHandler; @@ -275,12 +274,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; diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/ai/FriendlyNpcAI.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/ai/FriendlyNpcAI.java index 3eebee88ea..60fa4b1c8a 100644 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/ai/FriendlyNpcAI.java +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/ai/FriendlyNpcAI.java @@ -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()) { diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java index c363c397b5..46287d4e8e 100644 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java @@ -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) diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/ai/L2CharacterAI.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/ai/L2CharacterAI.java index 0d66c4a387..b046658f42 100644 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/ai/L2CharacterAI.java +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/ai/L2CharacterAI.java @@ -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; diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/ai/L2FortSiegeGuardAI.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/ai/L2FortSiegeGuardAI.java index 79f39cb51d..426228ee50 100644 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/ai/L2FortSiegeGuardAI.java +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/ai/L2FortSiegeGuardAI.java @@ -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 diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/ai/L2SiegeGuardAI.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/ai/L2SiegeGuardAI.java index caf5f39544..7cd4bb5dc1 100644 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/ai/L2SiegeGuardAI.java +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/ai/L2SiegeGuardAI.java @@ -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 diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/ai/L2SummonAI.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/ai/L2SummonAI.java index 00c00b8ff9..e29df8102b 100644 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/ai/L2SummonAI.java +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/ai/L2SummonAI.java @@ -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()); } diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/data/xml/impl/DoorData.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/data/xml/impl/DoorData.java index 973c82b4a8..592f3af578 100644 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/data/xml/impl/DoorData.java +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/data/xml/impl/DoorData.java @@ -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); } diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/GeoData.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/GeoData.java deleted file mode 100644 index a44ba3b703..0000000000 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/GeoData.java +++ /dev/null @@ -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 . - */ -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(); - } -} diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/Cell.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/Cell.java deleted file mode 100644 index 4914b1d72e..0000000000 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/Cell.java +++ /dev/null @@ -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 . - */ -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() - { - } -} diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/GeoDriver.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/GeoDriver.java deleted file mode 100644 index ffef644f31..0000000000 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/GeoDriver.java +++ /dev/null @@ -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 . - */ -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 _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; - } -} diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/IBlock.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/IBlock.java deleted file mode 100644 index 21df97c40d..0000000000 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/IBlock.java +++ /dev/null @@ -1,42 +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 . - */ -package com.l2jmobius.gameserver.geodata.geodriver; - -/** - * @author HorridoJoho - */ -public interface IBlock -{ - int TYPE_FLAT = 0; - int TYPE_COMPLEX = 1; - int TYPE_MULTILAYER = 2; - - /** Cells in a block on the x axis */ - int BLOCK_CELLS_X = 8; - /** Cells in a block on the y axis */ - int BLOCK_CELLS_Y = 8; - /** Cells in a block */ - int BLOCK_CELLS = BLOCK_CELLS_X * BLOCK_CELLS_Y; - - boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe); - - int getNearestZ(int geoX, int geoY, int worldZ); - - int getNextLowerZ(int geoX, int geoY, int worldZ); - - int getNextHigherZ(int geoX, int geoY, int worldZ); -} diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/IRegion.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/IRegion.java deleted file mode 100644 index 3eb23da03e..0000000000 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/IRegion.java +++ /dev/null @@ -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 . - */ -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(); -} diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/ComplexBlock.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/ComplexBlock.java deleted file mode 100644 index 4d6410672e..0000000000 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/ComplexBlock.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/FlatBlock.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/FlatBlock.java deleted file mode 100644 index d5bcff094b..0000000000 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/FlatBlock.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/MultilayerBlock.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/MultilayerBlock.java deleted file mode 100644 index 313131bd5a..0000000000 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/MultilayerBlock.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/regions/NullRegion.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/regions/NullRegion.java deleted file mode 100644 index 60ecac873a..0000000000 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/regions/NullRegion.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/regions/Region.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/regions/Region.java deleted file mode 100644 index d2d02481ed..0000000000 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/geodriver/regions/Region.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNode.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNode.java deleted file mode 100644 index e3476f28c2..0000000000 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNode.java +++ /dev/null @@ -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 . - */ -package com.l2jmobius.gameserver.geodata.pathfinding; - -public abstract class AbstractNode -{ - private T _loc; - private AbstractNode _parent; - - public AbstractNode(T loc) - { - _loc = loc; - } - - public void setParent(AbstractNode p) - { - _parent = p; - } - - public AbstractNode 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; - } -} \ No newline at end of file diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/PathFinding.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/PathFinding.java deleted file mode 100644 index c1fbd19084..0000000000 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/PathFinding.java +++ /dev/null @@ -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 . - */ -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 findPath(int x, int y, int z, int tx, int ty, int tz, Instance instance, boolean playable); - - // @formatter:off - /* - public List 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 visited = new LinkedList(); - - // List of Nodes to Visit - LinkedList to_visit = new LinkedList(); - 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 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; - } -} diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNode.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNode.java deleted file mode 100644 index dd2c0f2d8e..0000000000 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNode.java +++ /dev/null @@ -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 . - */ -package com.l2jmobius.gameserver.geodata.pathfinding.cellnodes; - -import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNode; - -public class CellNode extends AbstractNode -{ - 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; - } -} \ No newline at end of file diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNodeBuffer.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNodeBuffer.java deleted file mode 100644 index 5747e430ea..0000000000 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNodeBuffer.java +++ /dev/null @@ -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 . - */ -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 debugPath() - { - final List 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; - } -} \ No newline at end of file diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellPathFinding.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellPathFinding.java deleted file mode 100644 index 1e7da4ca3b..0000000000 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellPathFinding.java +++ /dev/null @@ -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 . - */ -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 _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 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 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 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 constructPath(AbstractNode node) - { - final LinkedList 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 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(); - } -} diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/NodeLoc.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/NodeLoc.java deleted file mode 100644 index f0720ae1ae..0000000000 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/NodeLoc.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNode.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNode.java deleted file mode 100644 index e9461b122a..0000000000 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNode.java +++ /dev/null @@ -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 . - */ -package com.l2jmobius.gameserver.geodata.pathfinding.geonodes; - -import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNode; - -/** - * @author -Nemesiss- - */ -public class GeoNode extends AbstractNode -{ - 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); - } - } -} diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNodeLoc.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNodeLoc.java deleted file mode 100644 index 3721b3a75e..0000000000 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNodeLoc.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoPathFinding.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoPathFinding.java deleted file mode 100644 index 8641ce07e0..0000000000 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoPathFinding.java +++ /dev/null @@ -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 . - */ -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 _pathNodes = new ConcurrentHashMap<>(); - private static Map _pathNodesIndex = new ConcurrentHashMap<>(); - - public static GeoPathFinding getInstance() - { - return SingletonHolder._instance; - } - - @Override - public boolean pathNodesExist(short regionoffset) - { - return _pathNodesIndex.containsKey(regionoffset); - } - - @Override - public List 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 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 visited = new ArrayList<>(550); - - // List of Nodes to Visit - final LinkedList 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 constructPath2(AbstractNode node) - { - final LinkedList 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> 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(); - } -} diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/utils/BinaryNodeHeap.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/utils/BinaryNodeHeap.java deleted file mode 100644 index a6aae4c662..0000000000 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/utils/BinaryNodeHeap.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java new file mode 100644 index 0000000000..587aab48e2 --- /dev/null +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java @@ -0,0 +1,1311 @@ +/* + * 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 . + */ +package com.l2jmobius.gameserver.geoengine; + +import java.io.File; +import java.io.RandomAccessFile; +import java.nio.ByteOrder; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.util.List; +import java.util.logging.Logger; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.MathUtil; +import com.l2jmobius.gameserver.data.xml.impl.DoorData; +import com.l2jmobius.gameserver.geoengine.geodata.ABlock; +import com.l2jmobius.gameserver.geoengine.geodata.BlockComplex; +import com.l2jmobius.gameserver.geoengine.geodata.BlockComplexDynamic; +import com.l2jmobius.gameserver.geoengine.geodata.BlockFlat; +import com.l2jmobius.gameserver.geoengine.geodata.BlockMultilayer; +import com.l2jmobius.gameserver.geoengine.geodata.BlockMultilayerDynamic; +import com.l2jmobius.gameserver.geoengine.geodata.BlockNull; +import com.l2jmobius.gameserver.geoengine.geodata.GeoFormat; +import com.l2jmobius.gameserver.geoengine.geodata.GeoLocation; +import com.l2jmobius.gameserver.geoengine.geodata.GeoStructure; +import com.l2jmobius.gameserver.geoengine.geodata.IBlockDynamic; +import com.l2jmobius.gameserver.geoengine.geodata.IGeoObject; +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.actor.L2Character; +import com.l2jmobius.gameserver.model.actor.instance.L2DoorInstance; +import com.l2jmobius.gameserver.model.instancezone.Instance; + +/** + * @author Hasha + */ +public class GeoEngine +{ + protected static final Logger _log = Logger.getLogger(GeoEngine.class.getName()); + + private final ABlock[][] _blocks; + private final BlockNull _nullBlock; + + /** + * Returns the instance of the {@link GeoEngine}. + * @return {@link GeoEngine} : The instance. + */ + public static final GeoEngine getInstance() + { + return SingletonHolder._instance; + } + + /** + * GeoEngine contructor. Loads all geodata files of chosen geodata format. + */ + public GeoEngine() + { + _log.info("GeoEngine: Initializing..."); + + // initialize block container + _blocks = new ABlock[GeoStructure.GEO_BLOCKS_X][GeoStructure.GEO_BLOCKS_Y]; + + // load null block + _nullBlock = new BlockNull(); + + // initialize multilayer temporarily buffer + BlockMultilayer.initialize(); + + // load geo files according to geoengine config setup + int loaded = 0; + int failed = 0; + for (int rx = L2World.TILE_X_MIN; rx <= L2World.TILE_X_MAX; rx++) + { + for (int ry = L2World.TILE_Y_MIN; ry <= L2World.TILE_Y_MAX; ry++) + { + final String filename = String.format(GeoFormat.L2D.getFilename(), rx, ry); + final String filepath = Config.GEODATA_PATH; + File f = new File(filepath + filename); + if (f.exists() && !f.isDirectory()) + { + // region file is load-able, try to load it + if (loadGeoBlocks(rx, ry)) + { + loaded++; + } + else + { + failed++; + } + } + else + { + // region file is not load-able, load null blocks + loadNullBlocks(rx, ry); + } + } + } + _log.info("GeoEngine: Loaded " + loaded + " L2D region files."); + + // Avoid wrong config when no files loaded + if ((loaded == 0) && (Config.COORD_SYNCHRONIZE == 2)) + { + Config.COORD_SYNCHRONIZE = -1; + _log.info("GeoEngine: Forcing CoordSynchronize setting to -1."); + } + + // release multilayer block temporarily buffer + BlockMultilayer.release(); + + if (failed > 0) + { + _log.info("GeoEngine: Failed to load " + failed + " L2D region files. Please consider to check your \"GeoEngine.ini\" settings and location of \"XX_YY.L2D\" geodata files."); + System.exit(1); + } + } + + /** + * Loads geodata from a file. When file does not exist, is corrupted or not consistent, loads none geodata. + * @param regionX : Geodata file region X coordinate. + * @param regionY : Geodata file region Y coordinate. + * @return boolean : True, when geodata file was loaded without problem. + */ + private final boolean loadGeoBlocks(int regionX, int regionY) + { + final String filename = String.format(GeoFormat.L2D.getFilename(), regionX, regionY); + final String filepath = Config.GEODATA_PATH + filename; + + // standard load + try (RandomAccessFile raf = new RandomAccessFile(filepath, "r"); + FileChannel fc = raf.getChannel()) + { + // initialize file buffer + MappedByteBuffer buffer = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()).load(); + buffer.order(ByteOrder.LITTLE_ENDIAN); + + // get block indexes + final int blockX = (regionX - L2World.TILE_X_MIN) * GeoStructure.REGION_BLOCKS_X; + final int blockY = (regionY - L2World.TILE_Y_MIN) * GeoStructure.REGION_BLOCKS_Y; + + // loop over region blocks + for (int ix = 0; ix < GeoStructure.REGION_BLOCKS_X; ix++) + { + for (int iy = 0; iy < GeoStructure.REGION_BLOCKS_Y; iy++) + { + // get block type + final byte type = buffer.get(); + + // load block according to block type + switch (type) + { + case GeoStructure.TYPE_FLAT_L2D: + _blocks[blockX + ix][blockY + iy] = new BlockFlat(buffer, GeoFormat.L2D); + break; + + case GeoStructure.TYPE_COMPLEX_L2D: + _blocks[blockX + ix][blockY + iy] = new BlockComplex(buffer, GeoFormat.L2D); + break; + + case GeoStructure.TYPE_MULTILAYER_L2D: + _blocks[blockX + ix][blockY + iy] = new BlockMultilayer(buffer, GeoFormat.L2D); + break; + + default: + throw new IllegalArgumentException("Unknown block type: " + type); + } + } + } + + // check data consistency + if (buffer.remaining() > 0) + { + _log.warning("GeoEngine: Region file " + filename + " can be corrupted, remaining " + buffer.remaining() + " bytes to read."); + } + + // loading was successful + return true; + } + catch (Exception e) + { + // an error occured while loading, load null blocks + _log.warning("GeoEngine: Error while loading " + filename + " region file."); + _log.warning(e.getMessage()); + e.printStackTrace(); + + // replace whole region file with null blocks + loadNullBlocks(regionX, regionY); + + // loading was not successful + return false; + } + } + + /** + * Loads null blocks. Used when no region file is detected or an error occurs during loading. + * @param regionX : Geodata file region X coordinate. + * @param regionY : Geodata file region Y coordinate. + */ + private final void loadNullBlocks(int regionX, int regionY) + { + // get block indexes + final int blockX = (regionX - L2World.TILE_X_MIN) * GeoStructure.REGION_BLOCKS_X; + final int blockY = (regionY - L2World.TILE_Y_MIN) * GeoStructure.REGION_BLOCKS_Y; + + // load all null blocks + for (int ix = 0; ix < GeoStructure.REGION_BLOCKS_X; ix++) + { + for (int iy = 0; iy < GeoStructure.REGION_BLOCKS_Y; iy++) + { + _blocks[blockX + ix][blockY + iy] = _nullBlock; + } + } + } + + // GEODATA - GENERAL + + /** + * Converts world X to geodata X. + * @param worldX + * @return int : Geo X + */ + public final int getGeoX(int worldX) + { + return (MathUtil.limit(worldX, L2World.MAP_MIN_X, L2World.MAP_MAX_X) - L2World.MAP_MIN_X) >> 4; + } + + /** + * Converts world Y to geodata Y. + * @param worldY + * @return int : Geo Y + */ + public final int getGeoY(int worldY) + { + return (MathUtil.limit(worldY, L2World.MAP_MIN_Y, L2World.MAP_MAX_Y) - L2World.MAP_MIN_Y) >> 4; + } + + /** + * Converts geodata X to world X. + * @param geoX + * @return int : World X + */ + public final int getWorldX(int geoX) + { + return (MathUtil.limit(geoX, 0, GeoStructure.GEO_CELLS_X) << 4) + L2World.MAP_MIN_X + 8; + } + + /** + * Converts geodata Y to world Y. + * @param geoY + * @return int : World Y + */ + public final int getWorldY(int geoY) + { + return (MathUtil.limit(geoY, 0, GeoStructure.GEO_CELLS_Y) << 4) + L2World.MAP_MIN_Y + 8; + } + + /** + * Returns block of geodata on given coordinates. + * @param geoX : Geodata X + * @param geoY : Geodata Y + * @return {@link ABlock} : Bloack of geodata. + */ + public final ABlock getBlock(int geoX, int geoY) + { + return _blocks[geoX / GeoStructure.BLOCK_CELLS_X][geoY / GeoStructure.BLOCK_CELLS_Y]; + } + + /** + * Check if geo coordinates has geo. + * @param geoX : Geodata X + * @param geoY : Geodata Y + * @return boolean : True, if given geo coordinates have geodata + */ + public final boolean hasGeoPos(int geoX, int geoY) + { + return getBlock(geoX, geoY).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, closest to given coordinates. + */ + public final short getHeightNearest(int geoX, int geoY, int worldZ) + { + return getBlock(geoX, geoY).getHeightNearest(geoX, geoY, worldZ); + } + + /** + * Returns the height of cell, which is closest to given coordinates.
+ * 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, closest to given coordinates. + */ + public final short getHeightNearestOriginal(int geoX, int geoY, int worldZ) + { + return getBlock(geoX, geoY).getHeightNearestOriginal(geoX, geoY, worldZ); + } + + /** + * Returns the NSWE flag byte of cell, which is closes 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 coordinate, closest to given coordinates. + */ + public final byte getNsweNearest(int geoX, int geoY, int worldZ) + { + return getBlock(geoX, geoY).getNsweNearest(geoX, geoY, worldZ); + } + + /** + * Returns the NSWE flag byte of cell, which is closes to given coordinates.
+ * 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 coordinate, closest to given coordinates. + */ + public final byte getNsweNearestOriginal(int geoX, int geoY, int worldZ) + { + return getBlock(geoX, geoY).getNsweNearestOriginal(geoX, geoY, worldZ); + } + + /** + * Check if world coordinates has geo. + * @param worldX : World X + * @param worldY : World Y + * @return boolean : True, if given world coordinates have geodata + */ + public final boolean hasGeo(int worldX, int worldY) + { + return hasGeoPos(getGeoX(worldX), getGeoY(worldY)); + } + + /** + * Returns closest Z coordinate according to geodata. + * @param worldX : world x + * @param worldY : world y + * @param worldZ : world z + * @return short : nearest Z coordinates according to geodata + */ + public final short getHeight(int worldX, int worldY, int worldZ) + { + return getHeightNearest(getGeoX(worldX), getGeoY(worldY), worldZ); + } + + // GEODATA - DYNAMIC + + /** + * Returns calculated NSWE flag byte as a description of {@link IGeoObject}.
+ * The {@link IGeoObject} is defined by boolean 2D array, saying if the object is present on given cell or not. + * @param inside : 2D description of {@link IGeoObject} + * @return byte[][] : Returns NSWE flags of {@link IGeoObject}. + */ + public static final byte[][] calculateGeoObject(boolean inside[][]) + { + // get dimensions + final int width = inside.length; + final int height = inside[0].length; + + // create object flags for geodata, according to the geo object 2D description + final byte[][] result = new byte[width][height]; + + // loop over each cell of the geo object + for (int ix = 0; ix < width; ix++) + { + for (int iy = 0; iy < height; iy++) + { + if (inside[ix][iy]) + { + // cell is inside geo object, block whole movement (nswe = 0) + result[ix][iy] = 0; + } + else + { + // cell is outside of geo object, block only movement leading inside geo object + + // set initial value -> no geodata change + byte nswe = (byte) 0xFF; + + // perform axial and diagonal checks + if (iy < (height - 1)) + { + if (inside[ix][iy + 1]) + { + nswe &= ~GeoStructure.CELL_FLAG_S; + } + } + if (iy > 0) + { + if (inside[ix][iy - 1]) + { + nswe &= ~GeoStructure.CELL_FLAG_N; + } + } + if (ix < (width - 1)) + { + if (inside[ix + 1][iy]) + { + nswe &= ~GeoStructure.CELL_FLAG_E; + } + } + if (ix > 0) + { + if (inside[ix - 1][iy]) + { + nswe &= ~GeoStructure.CELL_FLAG_W; + } + } + if ((ix < (width - 1)) && (iy < (height - 1))) + { + if (inside[ix + 1][iy + 1] || inside[ix][iy + 1] || inside[ix + 1][iy]) + { + nswe &= ~GeoStructure.CELL_FLAG_SE; + } + } + if ((ix < (width - 1)) && (iy > 0)) + { + if (inside[ix + 1][iy - 1] || inside[ix][iy - 1] || inside[ix + 1][iy]) + { + nswe &= ~GeoStructure.CELL_FLAG_NE; + } + } + if ((ix > 0) && (iy < (height - 1))) + { + if (inside[ix - 1][iy + 1] || inside[ix][iy + 1] || inside[ix - 1][iy]) + { + nswe &= ~GeoStructure.CELL_FLAG_SW; + } + } + if ((ix > 0) && (iy > 0)) + { + if (inside[ix - 1][iy - 1] || inside[ix][iy - 1] || inside[ix - 1][iy]) + { + nswe &= ~GeoStructure.CELL_FLAG_NW; + } + } + + result[ix][iy] = nswe; + } + } + } + + return result; + } + + /** + * Add {@link IGeoObject} to the geodata. + * @param object : An object using {@link IGeoObject} interface. + */ + public final void addGeoObject(IGeoObject object) + { + toggleGeoObject(object, true); + } + + /** + * Remove {@link IGeoObject} from the geodata. + * @param object : An object using {@link IGeoObject} interface. + */ + public final void removeGeoObject(IGeoObject object) + { + toggleGeoObject(object, false); + } + + /** + * Toggles an {@link IGeoObject} in the geodata. + * @param object : An object using {@link IGeoObject} interface. + * @param add : Add/remove object. + */ + private final void toggleGeoObject(IGeoObject object, boolean add) + { + // get object geo coordinates and data + final int minGX = object.getGeoX(); + final int minGY = object.getGeoY(); + final byte[][] geoData = object.getObjectGeoData(); + + // get min/max block coordinates + int minBX = minGX / GeoStructure.BLOCK_CELLS_X; + int maxBX = ((minGX + geoData.length) - 1) / GeoStructure.BLOCK_CELLS_X; + int minBY = minGY / GeoStructure.BLOCK_CELLS_Y; + int maxBY = ((minGY + geoData[0].length) - 1) / GeoStructure.BLOCK_CELLS_Y; + + // loop over affected blocks in X direction + for (int bx = minBX; bx <= maxBX; bx++) + { + // loop over affected blocks in Y direction + for (int by = minBY; by <= maxBY; by++) + { + ABlock block; + + // conversion to dynamic block must be synchronized to prevent 2 independent threads converting same block + synchronized (_blocks) + { + // get related block + block = _blocks[bx][by]; + + // check for dynamic block + if (!(block instanceof IBlockDynamic)) + { + // null block means no geodata (particular region file is not loaded), no geodata means no geobjects + if (block instanceof BlockNull) + { + continue; + } + + // not a dynamic block, convert it + if (block instanceof BlockFlat) + { + // convert flat block to the dynamic complex block + block = new BlockComplexDynamic(bx, by, (BlockFlat) block); + _blocks[bx][by] = block; + } + else if (block instanceof BlockComplex) + { + // convert complex block to the dynamic complex block + block = new BlockComplexDynamic(bx, by, (BlockComplex) block); + _blocks[bx][by] = block; + } + else if (block instanceof BlockMultilayer) + { + // convert multilayer block to the dynamic multilayer block + block = new BlockMultilayerDynamic(bx, by, (BlockMultilayer) block); + _blocks[bx][by] = block; + } + } + } + + // add/remove geo object to/from dynamic block + if (add) + { + ((IBlockDynamic) block).addGeoObject(object); + } + else + { + ((IBlockDynamic) block).removeGeoObject(object); + } + } + } + } + + // PATHFINDING + + /** + * Check line of sight from {@link L2Object} to {@link L2Object}. + * @param origin : The origin object. + * @param target : The target object. + * @return {@code boolean} : True if origin can see target + */ + public final boolean canSeeTarget(L2Object origin, L2Object target) + { + // get origin and target world coordinates + final int ox = origin.getX(); + final int oy = origin.getY(); + final int oz = origin.getZ(); + final int tx = target.getX(); + final int ty = target.getY(); + final int tz = target.getZ(); + + // get origin and check existing geo coordinates + final int gox = getGeoX(ox); + final int goy = getGeoY(oy); + if (!hasGeoPos(gox, goy)) + { + return true; + } + + final short goz = getHeightNearest(gox, goy, oz); + + // get target and check existing geo coordinates + final int gtx = getGeoX(tx); + final int gty = getGeoY(ty); + if (!hasGeoPos(gtx, gty)) + { + return true; + } + + final boolean door = target.isDoor(); + final short gtz = door ? getHeightNearestOriginal(gtx, gty, tz) : getHeightNearest(gtx, gty, tz); + + // origin and target coordinates are same + if ((gox == gtx) && (goy == gty)) + { + return goz == gtz; + } + + // get origin and target height, real height = collision height * 2 + double oheight = 0; + if (origin.isCharacter()) + { + oheight = ((L2Character) origin).getCollisionHeight() * 2; + } + + double theight = 0; + if (target.isCharacter()) + { + theight = ((L2Character) target).getCollisionHeight() * 2; + } + + // perform geodata check + return door ? checkSeeOriginal(gox, goy, goz, oheight, gtx, gty, gtz, theight) : checkSee(gox, goy, goz, oheight, gtx, gty, gtz, theight); + } + + /** + * Check line of sight from {@link L2Object} to {@link Location}. + * @param origin : The origin object. + * @param position : The target position. + * @return {@code boolean} : True if object can see position + */ + public final boolean canSeeTarget(L2Object origin, Location position) + { + // get origin and target world coordinates + final int ox = origin.getX(); + final int oy = origin.getY(); + final int oz = origin.getZ(); + final int tx = position.getX(); + final int ty = position.getY(); + final int tz = position.getZ(); + + // get origin and check existing geo coordinates + final int gox = getGeoX(ox); + final int goy = getGeoY(oy); + if (!hasGeoPos(gox, goy)) + { + return true; + } + + final short goz = getHeightNearest(gox, goy, oz); + + // get target and check existing geo coordinates + final int gtx = getGeoX(tx); + final int gty = getGeoY(ty); + if (!hasGeoPos(gtx, gty)) + { + return true; + } + + final short gtz = getHeightNearest(gtx, gty, tz); + + // origin and target coordinates are same + if ((gox == gtx) && (goy == gty)) + { + return goz == gtz; + } + + // get origin and target height, real height = collision height * 2 + double oheight = 0; + if (origin instanceof L2Character) + { + oheight = ((L2Character) origin).getTemplate().getCollisionHeight(); + } + + // perform geodata check + return checkSee(gox, goy, goz, oheight, gtx, gty, gtz, 0); + } + + /** + * Simple check for origin to target visibility. + * @param gox : origin X geodata coordinate + * @param goy : origin Y geodata coordinate + * @param goz : origin Z geodata coordinate + * @param oheight : origin height (if instance of {@link Character}) + * @param gtx : target X geodata coordinate + * @param gty : target Y geodata coordinate + * @param gtz : target Z geodata coordinate + * @param theight : target height (if instance of {@link Character}) + * @return {@code boolean} : True, when target can be seen. + */ + protected final boolean checkSee(int gox, int goy, int goz, double oheight, int gtx, int gty, int gtz, double theight) + { + // get line of sight Z coordinates + double losoz = goz + ((oheight * Config.PART_OF_CHARACTER_HEIGHT) / 100); + double lostz = gtz + ((theight * Config.PART_OF_CHARACTER_HEIGHT) / 100); + + // get X delta and signum + final int dx = Math.abs(gtx - gox); + final int sx = gox < gtx ? 1 : -1; + final byte dirox = sx > 0 ? GeoStructure.CELL_FLAG_E : GeoStructure.CELL_FLAG_W; + final byte dirtx = sx > 0 ? GeoStructure.CELL_FLAG_W : GeoStructure.CELL_FLAG_E; + + // get Y delta and signum + final int dy = Math.abs(gty - goy); + final int sy = goy < gty ? 1 : -1; + final byte diroy = sy > 0 ? GeoStructure.CELL_FLAG_S : GeoStructure.CELL_FLAG_N; + final byte dirty = sy > 0 ? GeoStructure.CELL_FLAG_N : GeoStructure.CELL_FLAG_S; + + // get Z delta + final int dm = Math.max(dx, dy); + final double dz = (lostz - losoz) / dm; + + // get direction flag for diagonal movement + final byte diroxy = getDirXY(dirox, diroy); + final byte dirtxy = getDirXY(dirtx, dirty); + + // delta, determines axis to move on (+..X axis, -..Y axis) + int d = dx - dy; + + // NSWE direction of movement + byte diro; + byte dirt; + + // clearDebugItems(); + // dropDebugItem(728, 0, new GeoLocation(gox, goy, goz)); // blue potion + // dropDebugItem(728, 0, new GeoLocation(gtx, gty, gtz)); // blue potion + + // initialize node values + int nox = gox; + int noy = goy; + int ntx = gtx; + int nty = gty; + byte nsweo = getNsweNearest(gox, goy, goz); + byte nswet = getNsweNearest(gtx, gty, gtz); + + // loop + ABlock block; + int index; + for (int i = 0; i < ((dm + 1) / 2); i++) + { + // dropDebugItem(57, 0, new GeoLocation(gox, goy, goz)); // antidote + // dropDebugItem(1831, 0, new GeoLocation(gtx, gty, gtz)); // adena + + // reset direction flag + diro = 0; + dirt = 0; + + // calculate next point coordinates + int e2 = 2 * d; + if ((e2 > -dy) && (e2 < dx)) + { + // calculate next point XY coordinates + d -= dy; + d += dx; + nox += sx; + ntx -= sx; + noy += sy; + nty -= sy; + diro |= diroxy; + dirt |= dirtxy; + } + else if (e2 > -dy) + { + // calculate next point X coordinate + d -= dy; + nox += sx; + ntx -= sx; + diro |= dirox; + dirt |= dirtx; + } + else if (e2 < dx) + { + // calculate next point Y coordinate + d += dx; + noy += sy; + nty -= sy; + diro |= diroy; + dirt |= dirty; + } + + { + // get block of the next cell + block = getBlock(nox, noy); + + // get index of particular layer, based on movement conditions + if ((nsweo & diro) == 0) + { + index = block.getIndexAbove(nox, noy, goz - GeoStructure.CELL_IGNORE_HEIGHT); + } + else + { + index = block.getIndexBelow(nox, noy, goz + GeoStructure.CELL_IGNORE_HEIGHT); + } + + // layer does not exist, return + if (index == -1) + { + return false; + } + + // get layer and next line of sight Z coordinate + goz = block.getHeight(index); + losoz += dz; + + // perform line of sight check, return when fails + if ((goz - losoz) > Config.MAX_OBSTACLE_HEIGHT) + { + return false; + } + + // get layer nswe + nsweo = block.getNswe(index); + } + { + // get block of the next cell + block = getBlock(ntx, nty); + + // get index of particular layer, based on movement conditions + if ((nswet & dirt) == 0) + { + index = block.getIndexAbove(ntx, nty, gtz - GeoStructure.CELL_IGNORE_HEIGHT); + } + else + { + index = block.getIndexBelow(ntx, nty, gtz + GeoStructure.CELL_IGNORE_HEIGHT); + } + + // layer does not exist, return + if (index == -1) + { + return false; + } + + // get layer and next line of sight Z coordinate + gtz = block.getHeight(index); + lostz -= dz; + + // perform line of sight check, return when fails + if ((gtz - lostz) > Config.MAX_OBSTACLE_HEIGHT) + { + return false; + } + + // get layer nswe + nswet = block.getNswe(index); + } + + // update coords + gox = nox; + goy = noy; + gtx = ntx; + gty = nty; + } + + // when iteration is completed, compare final Z coordinates + return Math.abs(goz - gtz) < (GeoStructure.CELL_HEIGHT * 4); + } + + /** + * Simple check for origin to target visibility.
+ * Geodata without {@link IGeoObject} are taken in consideration.
+ * NOTE: When two doors close between each other and the LoS check of one doors is performed through another door, result will not be accurate (the other door are skipped). + * @param gox : origin X geodata coordinate + * @param goy : origin Y geodata coordinate + * @param goz : origin Z geodata coordinate + * @param oheight : origin height (if instance of {@link Character}) + * @param gtx : target X geodata coordinate + * @param gty : target Y geodata coordinate + * @param gtz : target Z geodata coordinate + * @param theight : target height (if instance of {@link Character} or {@link L2DoorInstance}) + * @return {@code boolean} : True, when target can be seen. + */ + protected final boolean checkSeeOriginal(int gox, int goy, int goz, double oheight, int gtx, int gty, int gtz, double theight) + { + // get line of sight Z coordinates + double losoz = goz + ((oheight * Config.PART_OF_CHARACTER_HEIGHT) / 100); + double lostz = gtz + ((theight * Config.PART_OF_CHARACTER_HEIGHT) / 100); + + // get X delta and signum + final int dx = Math.abs(gtx - gox); + final int sx = gox < gtx ? 1 : -1; + final byte dirox = sx > 0 ? GeoStructure.CELL_FLAG_E : GeoStructure.CELL_FLAG_W; + final byte dirtx = sx > 0 ? GeoStructure.CELL_FLAG_W : GeoStructure.CELL_FLAG_E; + + // get Y delta and signum + final int dy = Math.abs(gty - goy); + final int sy = goy < gty ? 1 : -1; + final byte diroy = sy > 0 ? GeoStructure.CELL_FLAG_S : GeoStructure.CELL_FLAG_N; + final byte dirty = sy > 0 ? GeoStructure.CELL_FLAG_N : GeoStructure.CELL_FLAG_S; + + // get Z delta + final int dm = Math.max(dx, dy); + final double dz = (lostz - losoz) / dm; + + // get direction flag for diagonal movement + final byte diroxy = getDirXY(dirox, diroy); + final byte dirtxy = getDirXY(dirtx, dirty); + + // delta, determines axis to move on (+..X axis, -..Y axis) + int d = dx - dy; + + // NSWE direction of movement + byte diro; + byte dirt; + + // clearDebugItems(); + // dropDebugItem(728, 0, new GeoLocation(gox, goy, goz)); // blue potion + // dropDebugItem(728, 0, new GeoLocation(gtx, gty, gtz)); // blue potion + + // initialize node values + int nox = gox; + int noy = goy; + int ntx = gtx; + int nty = gty; + byte nsweo = getNsweNearestOriginal(gox, goy, goz); + byte nswet = getNsweNearestOriginal(gtx, gty, gtz); + + // loop + ABlock block; + int index; + for (int i = 0; i < ((dm + 1) / 2); i++) + { + // dropDebugItem(57, 0, new GeoLocation(gox, goy, goz)); // antidote + // dropDebugItem(1831, 0, new GeoLocation(gtx, gty, gtz)); // adena + + // reset direction flag + diro = 0; + dirt = 0; + + // calculate next point coordinates + int e2 = 2 * d; + if ((e2 > -dy) && (e2 < dx)) + { + // calculate next point XY coordinates + d -= dy; + d += dx; + nox += sx; + ntx -= sx; + noy += sy; + nty -= sy; + diro |= diroxy; + dirt |= dirtxy; + } + else if (e2 > -dy) + { + // calculate next point X coordinate + d -= dy; + nox += sx; + ntx -= sx; + diro |= dirox; + dirt |= dirtx; + } + else if (e2 < dx) + { + // calculate next point Y coordinate + d += dx; + noy += sy; + nty -= sy; + diro |= diroy; + dirt |= dirty; + } + + { + // get block of the next cell + block = getBlock(nox, noy); + + // get index of particular layer, based on movement conditions + if ((nsweo & diro) == 0) + { + index = block.getIndexAboveOriginal(nox, noy, goz - GeoStructure.CELL_IGNORE_HEIGHT); + } + else + { + index = block.getIndexBelowOriginal(nox, noy, goz + GeoStructure.CELL_IGNORE_HEIGHT); + } + + // layer does not exist, return + if (index == -1) + { + return false; + } + + // get layer and next line of sight Z coordinate + goz = block.getHeightOriginal(index); + losoz += dz; + + // perform line of sight check, return when fails + if ((goz - losoz) > Config.MAX_OBSTACLE_HEIGHT) + { + return false; + } + + // get layer nswe + nsweo = block.getNsweOriginal(index); + } + { + // get block of the next cell + block = getBlock(ntx, nty); + + // get index of particular layer, based on movement conditions + if ((nswet & dirt) == 0) + { + index = block.getIndexAboveOriginal(ntx, nty, gtz - GeoStructure.CELL_IGNORE_HEIGHT); + } + else + { + index = block.getIndexBelowOriginal(ntx, nty, gtz + GeoStructure.CELL_IGNORE_HEIGHT); + } + + // layer does not exist, return + if (index == -1) + { + return false; + } + + // get layer and next line of sight Z coordinate + gtz = block.getHeightOriginal(index); + lostz -= dz; + + // perform line of sight check, return when fails + if ((gtz - lostz) > Config.MAX_OBSTACLE_HEIGHT) + { + return false; + } + + // get layer nswe + nswet = block.getNsweOriginal(index); + } + + // update coords + gox = nox; + goy = noy; + gtx = ntx; + gty = nty; + } + + // when iteration is completed, compare final Z coordinates + return Math.abs(goz - gtz) < (GeoStructure.CELL_HEIGHT * 4); + } + + /** + * Check movement from coordinates to coordinates. + * @param ox : origin X coordinate + * @param oy : origin Y coordinate + * @param oz : origin Z coordinate + * @param tx : target X coordinate + * @param ty : target Y coordinate + * @param tz : target Z coordinate + * @param instance + * @return {code boolean} : True if target coordinates are reachable from origin coordinates + */ + public final boolean canMoveToTarget(int ox, int oy, int oz, int tx, int ty, int tz, Instance instance) + { + if (DoorData.getInstance().checkIfDoorsBetween(ox, oy, oz, tx, ty, tz, instance, false)) + { + return false; + } + + if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(ox, oy, oz), new Location(tx, ty, tz), instance)) + { + return false; + } + + // get origin and check existing geo coordinates + final int gox = getGeoX(ox); + final int goy = getGeoY(oy); + if (!hasGeoPos(gox, goy)) + { + return true; + } + + final short goz = getHeightNearest(gox, goy, oz); + + // get target and check existing geo coordinates + final int gtx = getGeoX(tx); + final int gty = getGeoY(ty); + if (!hasGeoPos(gtx, gty)) + { + return true; + } + + final short gtz = getHeightNearest(gtx, gty, tz); + + // target coordinates reached + if ((gox == gtx) && (goy == gty) && (goz == gtz)) + { + return true; + } + + // perform geodata check + GeoLocation loc = checkMove(gox, goy, goz, gtx, gty, gtz, instance); + return (loc.getGeoX() == gtx) && (loc.getGeoY() == gty); + } + + /** + * Check movement from origin to target. Returns last available point in the checked path. + * @param ox : origin X coordinate + * @param oy : origin Y coordinate + * @param oz : origin Z coordinate + * @param tx : target X coordinate + * @param ty : target Y coordinate + * @param tz : target Z coordinate + * @param instance + * @return {@link Location} : Last point where object can walk (just before wall) + */ + public final Location canMoveToTargetLoc(int ox, int oy, int oz, int tx, int ty, int tz, Instance instance) + { + if (DoorData.getInstance().checkIfDoorsBetween(ox, oy, oz, tx, ty, tz, instance, false)) + { + return new Location(ox, oy, getHeight(ox, oy, oz)); + } + + if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(ox, oy, oz), new Location(tx, ty, tz), instance)) + { + return new Location(ox, oy, getHeight(ox, oy, oz)); + } + + // get origin and check existing geo coordinates + final int gox = getGeoX(ox); + final int goy = getGeoY(oy); + if (!hasGeoPos(gox, goy)) + { + return new Location(tx, ty, tz); + } + + final short goz = getHeightNearest(gox, goy, oz); + + // get target and check existing geo coordinates + final int gtx = getGeoX(tx); + final int gty = getGeoY(ty); + if (!hasGeoPos(gtx, gty)) + { + return new Location(tx, ty, tz); + } + + final short gtz = getHeightNearest(gtx, gty, tz); + + // target coordinates reached + if ((gox == gtx) && (goy == gty) && (goz == gtz)) + { + return new Location(tx, ty, tz); + } + + // perform geodata check + return checkMove(gox, goy, goz, gtx, gty, gtz, instance); + } + + /** + * With this method you can check if a position is visible or can be reached by beeline movement.
+ * Target X and Y reachable and Z is on same floor: + *
    + *
  • Location of the target with corrected Z value from geodata.
  • + *
+ * Target X and Y reachable but Z is on another floor: + *
    + *
  • Location of the origin with corrected Z value from geodata.
  • + *
+ * Target X and Y not reachable: + *
    + *
  • Last accessible location in destination to target.
  • + *
+ * @param gox : origin X geodata coordinate + * @param goy : origin Y geodata coordinate + * @param goz : origin Z geodata coordinate + * @param gtx : target X geodata coordinate + * @param gty : target Y geodata coordinate + * @param gtz : target Z geodata coordinate + * @param instance + * @return {@link GeoLocation} : The last allowed point of movement. + */ + protected final GeoLocation checkMove(int gox, int goy, int goz, int gtx, int gty, int gtz, Instance instance) + { + if (DoorData.getInstance().checkIfDoorsBetween(gox, goy, goz, gtx, gty, gtz, instance, false)) + { + return new GeoLocation(gox, goy, goz); + } + + if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(gox, goy, goz), new Location(gtx, gty, gtz), instance)) + { + return new GeoLocation(gox, goy, goz); + } + + // get X delta, signum and direction flag + final int dx = Math.abs(gtx - gox); + final int sx = gox < gtx ? 1 : -1; + final byte dirX = sx > 0 ? GeoStructure.CELL_FLAG_E : GeoStructure.CELL_FLAG_W; + + // get Y delta, signum and direction flag + final int dy = Math.abs(gty - goy); + final int sy = goy < gty ? 1 : -1; + final byte dirY = sy > 0 ? GeoStructure.CELL_FLAG_S : GeoStructure.CELL_FLAG_N; + + // get direction flag for diagonal movement + final byte dirXY = getDirXY(dirX, dirY); + + // delta, determines axis to move on (+..X axis, -..Y axis) + int d = dx - dy; + + // NSWE direction of movement + byte direction; + + // load pointer coordinates + int gpx = gox; + int gpy = goy; + int gpz = goz; + + // load next pointer + int nx = gpx; + int ny = gpy; + + // loop + do + { + direction = 0; + + // calculate next point coordinates + int e2 = 2 * d; + if ((e2 > -dy) && (e2 < dx)) + { + d -= dy; + d += dx; + nx += sx; + ny += sy; + direction |= dirXY; + } + else if (e2 > -dy) + { + d -= dy; + nx += sx; + direction |= dirX; + } + else if (e2 < dx) + { + d += dx; + ny += sy; + direction |= dirY; + } + + // obstacle found, return + if ((getNsweNearest(gpx, gpy, gpz) & direction) == 0) + { + return new GeoLocation(gpx, gpy, gpz); + } + + // update pointer coordinates + gpx = nx; + gpy = ny; + gpz = getHeightNearest(nx, ny, gpz); + + // target coordinates reached + if ((gpx == gtx) && (gpy == gty)) + { + if (gpz == gtz) + { + // path found, Z coordinates are okay, return target point + return new GeoLocation(gtx, gty, gtz); + } + + // path found, Z coordinates are not okay, return origin point + return new GeoLocation(gox, goy, goz); + } + } + while (true); + } + + /** + * Returns diagonal NSWE flag format of combined two NSWE flags. + * @param dirX : X direction NSWE flag + * @param dirY : Y direction NSWE flag + * @return byte : NSWE flag of combined direction + */ + private static final byte getDirXY(byte dirX, byte dirY) + { + // check axis directions + if (dirY == GeoStructure.CELL_FLAG_N) + { + if (dirX == GeoStructure.CELL_FLAG_W) + { + return GeoStructure.CELL_FLAG_NW; + } + + return GeoStructure.CELL_FLAG_NE; + } + + if (dirX == GeoStructure.CELL_FLAG_W) + { + return GeoStructure.CELL_FLAG_SW; + } + + return GeoStructure.CELL_FLAG_SE; + } + + /** + * Returns the list of location objects as a result of complete path calculation. + * @param ox : origin x + * @param oy : origin y + * @param oz : origin z + * @param tx : target x + * @param ty : target y + * @param tz : target z + * @param instance + * @param playable : moving object is playable? + * @return {@code List} : complete path from nodes + */ + public List findPath(int ox, int oy, int oz, int tx, int ty, int tz, Instance instance, boolean playable) + { + return null; + } + + private static class SingletonHolder + { + protected static final GeoEngine _instance = Config.PATHFINDING ? new GeoEnginePathfinding() : new GeoEngine(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/GeoEnginePathfinding.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/GeoEnginePathfinding.java new file mode 100644 index 0000000000..b9def83228 --- /dev/null +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/GeoEnginePathfinding.java @@ -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 . + */ +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 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 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 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 : list of node location + */ + private static final List constructPath(Node target) + { + // create empty list + LinkedList 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 _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(); + } + } +} \ No newline at end of file diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/ABlock.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/ABlock.java new file mode 100644 index 0000000000..7fca5a9f52 --- /dev/null +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/ABlock.java @@ -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 . + */ +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.
+ * 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.
+ * 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.
+ * 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.
+ * 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.
+ * 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.
+ * 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; +} \ No newline at end of file diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplex.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplex.java new file mode 100644 index 0000000000..de0a7b8524 --- /dev/null +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplex.java @@ -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 . + */ +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); + } +} \ No newline at end of file diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplexDynamic.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplexDynamic.java new file mode 100644 index 0000000000..9f49e41899 --- /dev/null +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplexDynamic.java @@ -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 . + */ +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 _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; + } + } + } + } + } +} \ No newline at end of file diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/BlockFlat.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/BlockFlat.java new file mode 100644 index 0000000000..e1d82814eb --- /dev/null +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/BlockFlat.java @@ -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 . + */ +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)); + } +} \ No newline at end of file diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayer.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayer.java new file mode 100644 index 0000000000..56d4de75e1 --- /dev/null +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayer.java @@ -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 . + */ +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; + } + } +} \ No newline at end of file diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayerDynamic.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayerDynamic.java new file mode 100644 index 0000000000..2361135de5 --- /dev/null +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayerDynamic.java @@ -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 . + */ +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 _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; + } + } + } + } + } +} \ No newline at end of file diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/BlockNull.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/BlockNull.java new file mode 100644 index 0000000000..225bdef947 --- /dev/null +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/BlockNull.java @@ -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 . + */ +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) + { + } +} \ No newline at end of file diff --git a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNodeLoc.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/GeoFormat.java similarity index 67% rename from L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNodeLoc.java rename to L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/GeoFormat.java index 0678b3cb3a..57885fc734 100644 --- a/L2J_Mobius_Classic/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNodeLoc.java +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/GeoFormat.java @@ -14,20 +14,26 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -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; + } +} \ No newline at end of file diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/GeoLocation.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/GeoLocation.java new file mode 100644 index 0000000000..850fcdbfcd --- /dev/null +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/GeoLocation.java @@ -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 . + */ +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; + } +} \ No newline at end of file diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/GeoStructure.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/GeoStructure.java new file mode 100644 index 0000000000..e1925e6e57 --- /dev/null +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/GeoStructure.java @@ -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 . + */ +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; +} \ No newline at end of file diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/IBlockDynamic.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/IBlockDynamic.java new file mode 100644 index 0000000000..e241e73b1c --- /dev/null +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/IBlockDynamic.java @@ -0,0 +1,35 @@ +/* + * 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 . + */ +package com.l2jmobius.gameserver.geoengine.geodata; + +/** + * @author Hasha + */ +public interface IBlockDynamic +{ + /** + * 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); + + /** + * 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); +} \ No newline at end of file diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/IGeoObject.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/IGeoObject.java new file mode 100644 index 0000000000..2726378e3a --- /dev/null +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/geodata/IGeoObject.java @@ -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 . + */ +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(); +} diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/pathfinding/Node.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/pathfinding/Node.java new file mode 100644 index 0000000000..27430a65cd --- /dev/null +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/pathfinding/Node.java @@ -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 . + */ +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; + } +} \ No newline at end of file diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/pathfinding/NodeBuffer.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/pathfinding/NodeBuffer.java new file mode 100644 index 0000000000..300fe31190 --- /dev/null +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geoengine/pathfinding/NodeBuffer.java @@ -0,0 +1,351 @@ +/* + * 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 . + */ +package com.l2jmobius.gameserver.geoengine.pathfinding; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.locks.ReentrantLock; + +import com.l2jmobius.Config; +import com.l2jmobius.gameserver.geoengine.geodata.GeoStructure; + +/** + * @author DS, Hasha; Credits to Diamond + */ +public class NodeBuffer +{ + private final ReentrantLock _lock = new ReentrantLock(); + private final int _size; + private final Node[][] _buffer; + + // center coordinates + private int _cx = 0; + private int _cy = 0; + + // target coordinates + private int _gtx = 0; + private int _gty = 0; + private short _gtz = 0; + + // pathfinding statistics + private long _timeStamp = 0; + private long _lastElapsedTime = 0; + + private Node _current = null; + + /** + * Constructor of NodeBuffer. + * @param size : one dimension size of buffer + */ + public NodeBuffer(int size) + { + // set size + _size = size; + + // initialize buffer + _buffer = new Node[size][size]; + for (int x = 0; x < size; x++) + { + for (int y = 0; y < size; y++) + { + _buffer[x][y] = new Node(); + } + } + } + + /** + * Find path consisting of Nodes. Starts at origin coordinates, ends in target coordinates. + * @param gox : origin point x + * @param goy : origin point y + * @param goz : origin point z + * @param gtx : target point x + * @param gty : target point y + * @param gtz : target point z + * @return Node : first node of path + */ + public final Node findPath(int gox, int goy, short goz, int gtx, int gty, short gtz) + { + // load timestamp + _timeStamp = System.currentTimeMillis(); + + // set coordinates (middle of the line (gox,goy) - (gtx,gty), will be in the center of the buffer) + _cx = gox + ((gtx - gox - _size) / 2); + _cy = goy + ((gty - goy - _size) / 2); + + _gtx = gtx; + _gty = gty; + _gtz = gtz; + + _current = getNode(gox, goy, goz); + _current.setCost(getCostH(gox, goy, goz)); + + int count = 0; + do + { + // reached target? + if ((_current.getLoc().getGeoX() == _gtx) && (_current.getLoc().getGeoY() == _gty) && (Math.abs(_current.getLoc().getZ() - _gtz) < 8)) + { + return _current; + } + + // expand current node + expand(); + + // move pointer + _current = _current.getChild(); + } + while ((_current != null) && (++count < Config.MAX_ITERATIONS)); + + return null; + } + + /** + * Creates list of Nodes to show debug path. + * @return List : nodes + */ + public final List debugPath() + { + List result = new ArrayList<>(); + + for (Node n = _current; n.getParent() != null; n = n.getParent()) + { + result.add(n); + n.setCost(-n.getCost()); + } + + for (Node[] nodes : _buffer) + { + for (Node node : nodes) + { + if ((node.getLoc() == null) || (node.getCost() <= 0)) + { + continue; + } + + result.add(node); + } + } + + return result; + } + + public final boolean isLocked() + { + return _lock.tryLock(); + } + + public final void free() + { + _current = null; + + for (Node[] nodes : _buffer) + { + for (Node node : nodes) + { + if (node.getLoc() != null) + { + node.free(); + } + } + } + + _lock.unlock(); + _lastElapsedTime = System.currentTimeMillis() - _timeStamp; + } + + public final long getElapsedTime() + { + return _lastElapsedTime; + } + + /** + * Check _current Node and add its neighbors to the buffer. + */ + private final void expand() + { + // can't move anywhere, don't expand + byte nswe = _current.getLoc().getNSWE(); + if (nswe == 0) + { + return; + } + + // get geo coords of the node to be expanded + final int x = _current.getLoc().getGeoX(); + final int y = _current.getLoc().getGeoY(); + final short z = (short) _current.getLoc().getZ(); + + // can move north, expand + if ((nswe & GeoStructure.CELL_FLAG_N) != 0) + { + addNode(x, y - 1, z, Config.BASE_WEIGHT); + } + + // can move south, expand + if ((nswe & GeoStructure.CELL_FLAG_S) != 0) + { + addNode(x, y + 1, z, Config.BASE_WEIGHT); + } + + // can move west, expand + if ((nswe & GeoStructure.CELL_FLAG_W) != 0) + { + addNode(x - 1, y, z, Config.BASE_WEIGHT); + } + + // can move east, expand + if ((nswe & GeoStructure.CELL_FLAG_E) != 0) + { + addNode(x + 1, y, z, Config.BASE_WEIGHT); + } + + // can move north-west, expand + if ((nswe & GeoStructure.CELL_FLAG_NW) != 0) + { + addNode(x - 1, y - 1, z, Config.DIAGONAL_WEIGHT); + } + + // can move north-east, expand + if ((nswe & GeoStructure.CELL_FLAG_NE) != 0) + { + addNode(x + 1, y - 1, z, Config.DIAGONAL_WEIGHT); + } + + // can move south-west, expand + if ((nswe & GeoStructure.CELL_FLAG_SW) != 0) + { + addNode(x - 1, y + 1, z, Config.DIAGONAL_WEIGHT); + } + + // can move south-east, expand + if ((nswe & GeoStructure.CELL_FLAG_SE) != 0) + { + addNode(x + 1, y + 1, z, Config.DIAGONAL_WEIGHT); + } + } + + /** + * Returns node, if it exists in buffer. + * @param x : node X coord + * @param y : node Y coord + * @param z : node Z coord + * @return Node : node, if exits in buffer + */ + private final Node getNode(int x, int y, short z) + { + // check node X out of coordinates + final int ix = x - _cx; + if ((ix < 0) || (ix >= _size)) + { + return null; + } + + // check node Y out of coordinates + final int iy = y - _cy; + if ((iy < 0) || (iy >= _size)) + { + return null; + } + + // get node + Node result = _buffer[ix][iy]; + + // check and update + if (result.getLoc() == null) + { + result.setLoc(x, y, z); + } + + // return node + return result; + } + + /** + * Add node given by coordinates to the buffer. + * @param x : geo X coord + * @param y : geo Y coord + * @param z : geo Z coord + * @param weight : weight of movement to new node + */ + private final void addNode(int x, int y, short z, int weight) + { + // get node to be expanded + Node node = getNode(x, y, z); + if (node == null) + { + return; + } + + // Z distance between nearby cells is higher than cell size + if (node.getLoc().getZ() > (z + (2 * GeoStructure.CELL_HEIGHT))) + { + return; + } + + // node was already expanded, return + if (node.getCost() >= 0) + { + return; + } + + node.setParent(_current); + if (node.getLoc().getNSWE() != (byte) 0xFF) + { + node.setCost(getCostH(x, y, node.getLoc().getZ()) + (weight * Config.OBSTACLE_MULTIPLIER)); + } + else + { + node.setCost(getCostH(x, y, node.getLoc().getZ()) + weight); + } + + Node current = _current; + int count = 0; + while ((current.getChild() != null) && (count < (Config.MAX_ITERATIONS * 4))) + { + count++; + if (current.getChild().getCost() > node.getCost()) + { + node.setChild(current.getChild()); + break; + } + current = current.getChild(); + } + + if (count >= (Config.MAX_ITERATIONS * 4)) + { + System.err.println("Pathfinding: too long loop detected, cost:" + node.getCost()); + } + + current.setChild(node); + } + + /** + * @param x : node X coord + * @param y : node Y coord + * @param i : node Z coord + * @return double : node cost + */ + private final double getCostH(int x, int y, int i) + { + final int dX = x - _gtx; + final int dY = y - _gty; + final int dZ = (i - _gtz) / GeoStructure.CELL_HEIGHT; + + // return (Math.abs(dX) + Math.abs(dY) + Math.abs(dZ)) * Config.HEURISTIC_WEIGHT; // Manhattan distance + return Math.sqrt((dX * dX) + (dY * dY) + (dZ * dZ)) * Config.HEURISTIC_WEIGHT; // Direct distance + } +} \ No newline at end of file diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/instancemanager/WarpedSpaceManager.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/instancemanager/WarpedSpaceManager.java index 4f61421f83..cde24700ba 100644 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/instancemanager/WarpedSpaceManager.java +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/instancemanager/WarpedSpaceManager.java @@ -18,7 +18,6 @@ package com.l2jmobius.gameserver.instancemanager; import java.util.concurrent.ConcurrentHashMap; -import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNodeLoc; import com.l2jmobius.gameserver.model.Location; import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.holders.WarpedSpaceHolder; @@ -52,11 +51,6 @@ public class WarpedSpaceManager _warpedSpace.remove(creature); } - public boolean checkForWarpedSpace(AbstractNodeLoc start, AbstractNodeLoc end, Instance instance) - { - return checkForWarpedSpace(new Location(start.getX(), start.getY(), start.getZ()), new Location(end.getX(), end.getY(), end.getZ()), instance); - } - public boolean checkForWarpedSpace(Location origin, Location destination, Instance instance) { if (_warpedSpace != null) diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/Fishing.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/Fishing.java index e9cfd27a75..d0b69fa3e9 100644 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/Fishing.java +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/Fishing.java @@ -25,7 +25,7 @@ import com.l2jmobius.commons.util.Rnd; import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.data.xml.impl.FishingData; import com.l2jmobius.gameserver.enums.ShotType; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.instancemanager.ZoneManager; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.events.EventDispatcher; @@ -420,19 +420,19 @@ public class Fishing // always use water zone, fishing zone high z is high in the air... final int baitZ = waterZone.getWaterZ(); - // if (!GeoData.getInstance().canSeeTarget(player.getX(), player.getY(), player.getZ(), baitX, baitY, baitZ)) + // if (!GeoEngine.getInstance().canSeeTarget(player.getX(), player.getY(), player.getZ(), baitX, baitY, baitZ)) // // return Integer.MIN_VALUE; // } - if (GeoData.getInstance().hasGeo(baitX, baitY)) + if (GeoEngine.getInstance().hasGeo(baitX, baitY)) { - if (GeoData.getInstance().getHeight(baitX, baitY, baitZ) > baitZ) + if (GeoEngine.getInstance().getHeight(baitX, baitY, baitZ) > baitZ) { return Integer.MIN_VALUE; } - if (GeoData.getInstance().getHeight(baitX, baitY, player.getZ()) > baitZ) + if (GeoEngine.getInstance().getHeight(baitX, baitY, player.getZ()) > baitZ) { return Integer.MIN_VALUE; } diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/L2Spawn.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/L2Spawn.java index 3ddb0761ac..e9978f7863 100644 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/L2Spawn.java +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/L2Spawn.java @@ -26,7 +26,7 @@ import java.util.logging.Logger; import com.l2jmobius.commons.util.Rnd; import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.data.xml.impl.NpcData; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2NpcInstance; import com.l2jmobius.gameserver.model.actor.templates.L2NpcTemplate; @@ -544,7 +544,7 @@ public class L2Spawn implements IPositionable, IIdentifiable, INamable // don't correct z of flying npc's if (!npc.isFlying()) { - newlocz = GeoData.getInstance().getSpawnHeight(newlocx, newlocy, newlocz); + newlocz = GeoEngine.getInstance().getHeight(newlocx, newlocy, newlocz); } // Set is not random walk default value diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/Location.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/Location.java index dd88541a50..4b5e290517 100644 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/Location.java +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/Location.java @@ -26,9 +26,9 @@ import com.l2jmobius.gameserver.model.interfaces.IPositionable; */ public class Location implements IPositionable { - private int _x; - private int _y; - private int _z; + protected int _x; + protected int _y; + protected int _z; private int _heading; public Location(int x, int y, int z) diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Character.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Character.java index 8ab8348d64..8d4e253ccc 100644 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Character.java +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Character.java @@ -63,9 +63,7 @@ import com.l2jmobius.gameserver.enums.ShotType; import com.l2jmobius.gameserver.enums.StatusUpdateType; import com.l2jmobius.gameserver.enums.Team; import com.l2jmobius.gameserver.enums.UserInfoType; -import com.l2jmobius.gameserver.geodata.GeoData; -import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNodeLoc; -import com.l2jmobius.gameserver.geodata.pathfinding.PathFinding; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.idfactory.IdFactory; import com.l2jmobius.gameserver.instancemanager.MapRegionManager; import com.l2jmobius.gameserver.instancemanager.TimersManager; @@ -1053,7 +1051,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe stopEffectsOnAction(); // GeoData Los Check here (or dz > 1000) - if (!GeoData.getInstance().canSeeTarget(this, target)) + if (!GeoEngine.getInstance().canSeeTarget(this, target)) { sendPacket(SystemMessageId.CANNOT_SEE_TARGET); getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE); @@ -2851,7 +2849,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe public boolean disregardingGeodata; public int onGeodataPathIndex; - public List geoPath; + public List geoPath; public int geoPathAccurateTx; public int geoPathAccurateTy; public int geoPathGtx; @@ -3269,9 +3267,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe // Z coordinate will follow geodata or client values if ((Config.COORD_SYNCHRONIZE == 2) && !isFloating && !m.disregardingGeodata && ((GameTimeController.getInstance().getGameTicks() % 10) == 0 // once a second to reduce possible cpu load - ) && GeoData.getInstance().hasGeo(xPrev, yPrev)) + ) && GeoEngine.getInstance().hasGeo(xPrev, yPrev)) { - final int geoHeight = GeoData.getInstance().getSpawnHeight(xPrev, yPrev, zPrev); + final int geoHeight = GeoEngine.getInstance().getHeight(xPrev, yPrev, zPrev); dz = m._zDestination - geoHeight; // quite a big difference, compare to validatePosition packet if (isPlayer() && (Math.abs(getActingPlayer().getClientZ() - geoHeight) > 200) && (Math.abs(getActingPlayer().getClientZ() - geoHeight) < 1500)) @@ -3554,9 +3552,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe { // Notify the AI that the L2Character is arrived at destination getAI().notifyEvent(CtrlEvent.EVT_ARRIVED); - return; } + // Calculate movement angles needed sin = dy / distance; cos = dx / distance; @@ -3581,7 +3579,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe m.onGeodataPathIndex = -1; // Initialize not on geodata path m.disregardingGeodata = false; - if (!isFlying() && !isInsideZone(ZoneId.WATER)) + if (!isFlying() && !isInsideZone(ZoneId.WATER) && !isWalker()) { final boolean isInVehicle = isPlayer() && (getActingPlayer().getVehicle() != null); if (isInVehicle) @@ -3596,16 +3594,11 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe final int gtx = (originalX - L2World.MAP_MIN_X) >> 4; final int gty = (originalY - L2World.MAP_MIN_Y) >> 4; - final Location destiny = GeoData.getInstance().moveCheck(curX, curY, curZ, x, y, z, getInstanceWorld()); - - // location different if destination wasn't reached (or just z coord is different) - x = destiny.getX(); - y = destiny.getY(); - z = destiny.getZ(); - // Movement checks: - // when PATHFINDING > 0, for all characters except mobs returning home (could be changed later to teleport if pathfinding fails) - if (Config.PATHFINDING > 0) + // when geodata == 2, for all characters except mobs returning home (could be changed later to teleport if pathfinding fails) + // when geodata == 1, for l2playableinstance + // assuming intention_follow only when following owner + if ((Config.PATHFINDING && !(isAttackable() && ((L2Attackable) this).isReturningToSpawnPoint())) || (isPlayer() && !(isInVehicle && (distance > 1500))) || (isSummon() && !(getAI().getIntention() == CtrlIntention.AI_INTENTION_FOLLOW))) { if (isOnGeodataPath()) { @@ -3634,7 +3627,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe } else if (isSummon()) { - return; // preventation when summon get out of world coords, player will not loose him, unsummon handled from pcinstance + return; // prevention when summon get out of world coords, player will not loose him, unsummon handled from pcinstance } else { @@ -3643,6 +3636,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe return; } // location different if destination wasn't reached (or just z coord is different) + Location destiny = GeoEngine.getInstance().canMoveToTargetLoc(curX, curY, curZ, x, y, z, getInstanceWorld()); x = destiny.getX(); y = destiny.getY(); z = destiny.getZ(); @@ -3651,85 +3645,86 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe dz = z - curZ; distance = verticalMovementOnly ? Math.pow(dz, 2) : Math.hypot(dx, dy); } - // Pathfinding checks. Only when geodata setting is 2, the LoS check gives shorter result - // than the original movement was and the LoS gives a shorter distance than 2000 + // Pathfinding checks. Only when geodata setting is 2, the LoS check gives shorter result than the original movement was and the LoS gives a shorter distance than 2000 // This way of detecting need for pathfinding could be changed. - if ((Config.PATHFINDING > 0) && ((originalDistance - distance) > 30) && !isControlBlocked() && !isInVehicle) + if (Config.PATHFINDING && ((originalDistance - distance) > 30) && (distance < 2000) && !isControlBlocked() && !isInVehicle) { - m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayable()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + // Path calculation -- overrides previous movement check + if (isPlayable() || isMinion() || isInCombat()) { - // * Even though there's no path found (remember geonodes aren't perfect), - // the mob is attacking and right now we set it so that the mob will go - // after target anyway, is dz is small enough. - // * With cellpathfinding this approach could be changed but would require taking - // off the geonodes and some more checks. - // * Summons will follow their masters no matter what. - // * Currently minions also must move freely since L2AttackableAI commands - // them to move along with their leader - if (isPlayer() || (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) || (isSummon() && !((L2Summon) this).getFollowStatus())) + m.geoPath = GeoEngine.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayable()); + if ((m.geoPath == null) || (m.geoPath.size() < 2)) { - getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); - return; + // No path found + // Even though there's no path found (remember geonodes aren't perfect), the mob is attacking and right now we set it so that the mob will go after target anyway, is dz is small enough. + // With cellpathfinding this approach could be changed but would require taking off the geonodes and some more checks. + // Summons will follow their masters no matter what. + // Currently minions also must move freely since L2AttackableAI commands them to move along with their leader + if (isPlayer() || (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) || (isSummon() && !((L2Summon) this).getFollowStatus())) + { + getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); + return; + } + + m.disregardingGeodata = true; + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; } - - m.disregardingGeodata = true; - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; - } - else - { - m.onGeodataPathIndex = 0; // on first segment - m.geoPathGtx = gtx; - m.geoPathGty = gty; - m.geoPathAccurateTx = originalX; - m.geoPathAccurateTy = originalY; - - x = m.geoPath.get(m.onGeodataPathIndex).getX(); - y = m.geoPath.get(m.onGeodataPathIndex).getY(); - z = m.geoPath.get(m.onGeodataPathIndex).getZ(); - - // check for doors in the route - if (DoorData.getInstance().checkIfDoorsBetween(curX, curY, curZ, x, y, z, getInstanceWorld())) + else { - m.geoPath = null; - getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); - return; - } - if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(curX, curY, curZ), new Location(x, y, z), getInstanceWorld())) - { - m.geoPath = null; - getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); - return; - } - for (int i = 0; i < (m.geoPath.size() - 1); i++) - { - if (DoorData.getInstance().checkIfDoorsBetween(m.geoPath.get(i), m.geoPath.get(i + 1), getInstanceWorld())) + m.onGeodataPathIndex = 0; // on first segment + m.geoPathGtx = gtx; + m.geoPathGty = gty; + m.geoPathAccurateTx = originalX; + m.geoPathAccurateTy = originalY; + + x = m.geoPath.get(m.onGeodataPathIndex).getX(); + y = m.geoPath.get(m.onGeodataPathIndex).getY(); + z = m.geoPath.get(m.onGeodataPathIndex).getZ(); + + // check for doors in the route + if (DoorData.getInstance().checkIfDoorsBetween(curX, curY, curZ, x, y, z, getInstanceWorld())) { m.geoPath = null; getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); return; } - if (WarpedSpaceManager.getInstance().checkForWarpedSpace(m.geoPath.get(i), m.geoPath.get(i + 1), getInstanceWorld())) + if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(curX, curY, curZ), new Location(x, y, z), getInstanceWorld())) { m.geoPath = null; getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); return; } + for (int i = 0; i < (m.geoPath.size() - 1); i++) + { + if (DoorData.getInstance().checkIfDoorsBetween(m.geoPath.get(i), m.geoPath.get(i + 1), getInstanceWorld())) + { + m.geoPath = null; + getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); + return; + } + if (WarpedSpaceManager.getInstance().checkForWarpedSpace(m.geoPath.get(i), m.geoPath.get(i + 1), getInstanceWorld())) + { + m.geoPath = null; + getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); + return; + } + } + + dx = x - curX; + dy = y - curY; + dz = z - curZ; + distance = verticalMovementOnly ? Math.pow(dz, 2) : Math.hypot(dx, dy); + sin = dy / distance; + cos = dx / distance; } - - dx = x - curX; - dy = y - curY; - dz = z - curZ; - distance = verticalMovementOnly ? Math.pow(dz, 2) : Math.hypot(dx, dy); - sin = dy / distance; - cos = dx / distance; } } + // If no distance to go through, the movement is canceled - if ((distance < 1) && ((Config.PATHFINDING > 0) || isPlayable())) + if ((distance < 1) && (Config.PATHFINDING || isPlayable() || isControlBlocked())) { if (isSummon()) { @@ -3751,7 +3746,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe final int ticksToMove = 1 + (int) ((GameTimeController.TICKS_PER_SECOND * distance) / speed); m._xDestination = x; m._yDestination = y; - m._zDestination = z; // this is what was requested from client + m._zDestination = z; // Calculate and set the heading of the L2Character m._heading = 0; // initial value for coordinate sync @@ -4240,7 +4235,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe return; } // GeoData Los Check or dz > 1000 - if (!GeoData.getInstance().canSeeTarget(player, this)) + if (!GeoEngine.getInstance().canSeeTarget(player, this)) { player.sendPacket(SystemMessageId.CANNOT_SEE_TARGET); player.sendPacket(ActionFailed.STATIC_PACKET); diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Tower.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Tower.java index ac1d703e27..8390083019 100644 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Tower.java +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Tower.java @@ -17,7 +17,7 @@ package com.l2jmobius.gameserver.model.actor; import com.l2jmobius.gameserver.ai.CtrlIntention; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.actor.templates.L2NpcTemplate; import com.l2jmobius.gameserver.network.serverpackets.ActionFailed; @@ -63,7 +63,7 @@ public abstract class L2Tower extends L2Npc } else if (interact) { - if (isAutoAttackable(player) && (Math.abs(player.getZ() - getZ()) < 100) && GeoData.getInstance().canSeeTarget(player, this)) + if (isAutoAttackable(player) && (Math.abs(player.getZ() - getZ()) < 100) && GeoEngine.getInstance().canSeeTarget(player, this)) { // Notify the L2PcInstance AI with AI_INTENTION_INTERACT player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this); diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java index 0fff1d465e..ac058e3da4 100644 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java @@ -97,7 +97,7 @@ import com.l2jmobius.gameserver.enums.StatusUpdateType; import com.l2jmobius.gameserver.enums.SubclassInfoType; import com.l2jmobius.gameserver.enums.Team; import com.l2jmobius.gameserver.enums.UserInfoType; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.handler.AdminCommandHandler; import com.l2jmobius.gameserver.handler.IAdminCommandHandler; import com.l2jmobius.gameserver.handler.IItemHandler; @@ -12474,7 +12474,7 @@ public final class L2PcInstance extends L2Playable } // If there is no geodata loaded for the place we are client Z correction might cause falling damage. - if (!GeoData.getInstance().hasGeo(getX(), getY())) + if (!GeoEngine.getInstance().hasGeo(getX(), getY())) { return false; } diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java index 4d68c1314c..186a60aa46 100644 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java @@ -46,7 +46,7 @@ import com.l2jmobius.gameserver.enums.ItemLocation; import com.l2jmobius.gameserver.enums.ItemSkillType; import com.l2jmobius.gameserver.enums.ShotType; import com.l2jmobius.gameserver.enums.UserInfoType; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.idfactory.IdFactory; import com.l2jmobius.gameserver.instancemanager.CastleManager; import com.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager; @@ -1505,7 +1505,7 @@ public final class L2ItemInstance extends L2Object if (_dropper != null) { final Instance instance = _dropper.getInstanceWorld(); - final Location dropDest = GeoData.getInstance().moveCheck(_dropper.getX(), _dropper.getY(), _dropper.getZ(), _x, _y, _z, instance); + final Location dropDest = GeoEngine.getInstance().canMoveToTargetLoc(_dropper.getX(), _dropper.getY(), _dropper.getZ(), _x, _y, _z, instance); _x = dropDest.getX(); _y = dropDest.getY(); _z = dropDest.getZ(); diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java index 9780892efe..9c70018363 100644 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java @@ -37,7 +37,7 @@ import com.l2jmobius.gameserver.datatables.ItemTable; import com.l2jmobius.gameserver.enums.ItemSkillType; import com.l2jmobius.gameserver.enums.NextActionType; import com.l2jmobius.gameserver.enums.StatusUpdateType; -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; @@ -1009,7 +1009,7 @@ public class SkillCaster implements Runnable } } - final Location destination = GeoData.getInstance().moveCheck(creature.getX(), creature.getY(), creature.getZ(), x, y, z, creature.getInstanceWorld()); + final Location destination = GeoEngine.getInstance().canMoveToTargetLoc(creature.getX(), creature.getY(), creature.getZ(), x, y, z, creature.getInstanceWorld()); creature.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); creature.broadcastPacket(new FlyToLocation(creature, destination, flyType, 0, 0, 333)); diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/skills/SkillChannelizer.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/skills/SkillChannelizer.java index 3875eb6830..cc1667a637 100644 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/skills/SkillChannelizer.java +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/skills/SkillChannelizer.java @@ -25,7 +25,7 @@ import java.util.logging.Logger; import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.data.xml.impl.SkillData; import com.l2jmobius.gameserver.enums.ShotType; -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.instance.L2PcInstance; @@ -185,7 +185,7 @@ public class SkillChannelizer implements Runnable { continue; } - else if (!GeoData.getInstance().canSeeTarget(_channelizer, character)) + else if (!GeoEngine.getInstance().canSeeTarget(_channelizer, character)) { continue; } diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/zone/form/ZoneCuboid.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/zone/form/ZoneCuboid.java index 58d967f84d..4433e97b28 100644 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/zone/form/ZoneCuboid.java +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/zone/form/ZoneCuboid.java @@ -19,7 +19,7 @@ package com.l2jmobius.gameserver.model.zone.form; import java.awt.Rectangle; import com.l2jmobius.commons.util.Rnd; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.model.Location; import com.l2jmobius.gameserver.model.itemcontainer.Inventory; import com.l2jmobius.gameserver.model.zone.L2ZoneForm; @@ -131,6 +131,6 @@ public class ZoneCuboid extends L2ZoneForm final int x = Rnd.get(_r.x, _r.x + _r.width); final int y = Rnd.get(_r.y, _r.y + _r.height); - return new Location(x, y, GeoData.getInstance().getHeight(x, y, _z1)); + return new Location(x, y, GeoEngine.getInstance().getHeight(x, y, _z1)); } } diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/zone/form/ZoneCylinder.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/zone/form/ZoneCylinder.java index 969dd7d029..afdfd3fade 100644 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/zone/form/ZoneCylinder.java +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/zone/form/ZoneCylinder.java @@ -17,7 +17,7 @@ package com.l2jmobius.gameserver.model.zone.form; import com.l2jmobius.commons.util.Rnd; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.model.Location; import com.l2jmobius.gameserver.model.itemcontainer.Inventory; import com.l2jmobius.gameserver.model.zone.L2ZoneForm; @@ -146,6 +146,6 @@ public class ZoneCylinder extends L2ZoneForm x = (int) ((_rad * r * Math.cos(q)) + _x); y = (int) ((_rad * r * Math.sin(q)) + _y); - return new Location(x, y, GeoData.getInstance().getHeight(x, y, _z1)); + return new Location(x, y, GeoEngine.getInstance().getHeight(x, y, _z1)); } } diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/zone/form/ZoneNPoly.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/zone/form/ZoneNPoly.java index 6da33d788e..2340c1b218 100644 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/zone/form/ZoneNPoly.java +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/model/zone/form/ZoneNPoly.java @@ -19,7 +19,7 @@ package com.l2jmobius.gameserver.model.zone.form; import java.awt.Polygon; import com.l2jmobius.commons.util.Rnd; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.model.Location; import com.l2jmobius.gameserver.model.itemcontainer.Inventory; import com.l2jmobius.gameserver.model.zone.L2ZoneForm; @@ -138,7 +138,7 @@ public class ZoneNPoly extends L2ZoneForm y = Rnd.get(_minY, _maxY); } - return new Location(x, y, GeoData.getInstance().getHeight(x, y, _z1)); + return new Location(x, y, GeoEngine.getInstance().getHeight(x, y, _z1)); } public int[] getX() diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/util/GeoUtils.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/util/GeoUtils.java index 21540f2215..dba01759ef 100644 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/util/GeoUtils.java +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/util/GeoUtils.java @@ -18,8 +18,8 @@ package com.l2jmobius.gameserver.util; import java.awt.Color; -import com.l2jmobius.gameserver.geodata.GeoData; -import com.l2jmobius.gameserver.geodata.geodriver.Cell; +import com.l2jmobius.gameserver.geoengine.GeoEngine; +import com.l2jmobius.gameserver.geoengine.geodata.GeoStructure; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.network.serverpackets.ExServerPrimitive; @@ -30,21 +30,21 @@ public final class GeoUtils { public static void debug2DLine(L2PcInstance player, int x, int y, int tx, int ty, int z) { - final int gx = GeoData.getInstance().getGeoX(x); - final int gy = GeoData.getInstance().getGeoY(y); + final int gx = GeoEngine.getInstance().getGeoX(x); + final int gy = GeoEngine.getInstance().getGeoY(y); - final int tgx = GeoData.getInstance().getGeoX(tx); - final int tgy = GeoData.getInstance().getGeoY(ty); + final int tgx = GeoEngine.getInstance().getGeoX(tx); + final int tgy = GeoEngine.getInstance().getGeoY(ty); final ExServerPrimitive prim = new ExServerPrimitive("Debug2DLine", x, y, z); - prim.addLine(Color.BLUE, GeoData.getInstance().getWorldX(gx), GeoData.getInstance().getWorldY(gy), z, GeoData.getInstance().getWorldX(tgx), GeoData.getInstance().getWorldY(tgy), z); + prim.addLine(Color.BLUE, GeoEngine.getInstance().getWorldX(gx), GeoEngine.getInstance().getWorldY(gy), z, GeoEngine.getInstance().getWorldX(tgx), GeoEngine.getInstance().getWorldY(tgy), z); final LinePointIterator iter = new LinePointIterator(gx, gy, tgx, tgy); while (iter.next()) { - final int wx = GeoData.getInstance().getWorldX(iter.x()); - final int wy = GeoData.getInstance().getWorldY(iter.y()); + final int wx = GeoEngine.getInstance().getWorldX(iter.x()); + final int wy = GeoEngine.getInstance().getWorldY(iter.y()); prim.addPoint(Color.RED, wx, wy, z); } @@ -53,21 +53,21 @@ public final class GeoUtils public static void debug3DLine(L2PcInstance player, int x, int y, int z, int tx, int ty, int tz) { - final int gx = GeoData.getInstance().getGeoX(x); - final int gy = GeoData.getInstance().getGeoY(y); + final int gx = GeoEngine.getInstance().getGeoX(x); + final int gy = GeoEngine.getInstance().getGeoY(y); - final int tgx = GeoData.getInstance().getGeoX(tx); - final int tgy = GeoData.getInstance().getGeoY(ty); + final int tgx = GeoEngine.getInstance().getGeoX(tx); + final int tgy = GeoEngine.getInstance().getGeoY(ty); final ExServerPrimitive prim = new ExServerPrimitive("Debug3DLine", x, y, z); - prim.addLine(Color.BLUE, GeoData.getInstance().getWorldX(gx), GeoData.getInstance().getWorldY(gy), z, GeoData.getInstance().getWorldX(tgx), GeoData.getInstance().getWorldY(tgy), tz); + prim.addLine(Color.BLUE, GeoEngine.getInstance().getWorldX(gx), GeoEngine.getInstance().getWorldY(gy), z, GeoEngine.getInstance().getWorldX(tgx), GeoEngine.getInstance().getWorldY(tgy), tz); final LinePointIterator3D iter = new LinePointIterator3D(gx, gy, z, tgx, tgy, tz); iter.next(); int prevX = iter.x(); int prevY = iter.y(); - int wx = GeoData.getInstance().getWorldX(prevX); - int wy = GeoData.getInstance().getWorldY(prevY); + int wx = GeoEngine.getInstance().getWorldX(prevX); + int wy = GeoEngine.getInstance().getWorldY(prevY); int wz = iter.z(); prim.addPoint(Color.RED, wx, wy, wz); @@ -78,8 +78,8 @@ public final class GeoUtils if ((curX != prevX) || (curY != prevY)) { - wx = GeoData.getInstance().getWorldX(curX); - wy = GeoData.getInstance().getWorldY(curY); + wx = GeoEngine.getInstance().getWorldX(curX); + wy = GeoEngine.getInstance().getWorldY(curY); wz = iter.z(); prim.addPoint(Color.RED, wx, wy, wz); @@ -93,7 +93,7 @@ public final class GeoUtils private static Color getDirectionColor(int x, int y, int z, int nswe) { - if (GeoData.getInstance().checkNearestNswe(x, y, z, nswe)) + if ((GeoEngine.getInstance().getNsweNearest(x, y, z) & nswe) == nswe) { return Color.GREEN; } @@ -109,7 +109,7 @@ public final class GeoUtils int iPacket = 0; ExServerPrimitive exsp = null; - final GeoData gd = GeoData.getInstance(); + final GeoEngine gd = GeoEngine.getInstance(); final int playerGx = gd.getGeoX(player.getX()); final int playerGy = gd.getGeoY(player.getY()); for (int dx = -geoRadius; dx <= geoRadius; ++dx) @@ -137,30 +137,30 @@ public final class GeoUtils final int x = gd.getWorldX(gx); final int y = gd.getWorldY(gy); - final int z = gd.getNearestZ(gx, gy, player.getZ()); + final int z = gd.getHeightNearest(gx, gy, player.getZ()); // north arrow - Color col = getDirectionColor(gx, gy, z, Cell.NSWE_NORTH); + Color col = getDirectionColor(gx, gy, z, GeoStructure.CELL_FLAG_N); exsp.addLine(col, x - 1, y - 7, z, x + 1, y - 7, z); exsp.addLine(col, x - 2, y - 6, z, x + 2, y - 6, z); exsp.addLine(col, x - 3, y - 5, z, x + 3, y - 5, z); exsp.addLine(col, x - 4, y - 4, z, x + 4, y - 4, z); // east arrow - col = getDirectionColor(gx, gy, z, Cell.NSWE_EAST); + col = getDirectionColor(gx, gy, z, GeoStructure.CELL_FLAG_E); exsp.addLine(col, x + 7, y - 1, z, x + 7, y + 1, z); exsp.addLine(col, x + 6, y - 2, z, x + 6, y + 2, z); exsp.addLine(col, x + 5, y - 3, z, x + 5, y + 3, z); exsp.addLine(col, x + 4, y - 4, z, x + 4, y + 4, z); // south arrow - col = getDirectionColor(gx, gy, z, Cell.NSWE_SOUTH); + col = getDirectionColor(gx, gy, z, GeoStructure.CELL_FLAG_S); exsp.addLine(col, x - 1, y + 7, z, x + 1, y + 7, z); exsp.addLine(col, x - 2, y + 6, z, x + 2, y + 6, z); exsp.addLine(col, x - 3, y + 5, z, x + 3, y + 5, z); exsp.addLine(col, x - 4, y + 4, z, x + 4, y + 4, z); - col = getDirectionColor(gx, gy, z, Cell.NSWE_WEST); + col = getDirectionColor(gx, gy, z, GeoStructure.CELL_FLAG_W); exsp.addLine(col, x - 7, y - 1, z, x - 7, y + 1, z); exsp.addLine(col, x - 6, y - 2, z, x - 6, y + 2, z); exsp.addLine(col, x - 5, y - 3, z, x - 5, y + 3, z); @@ -188,30 +188,30 @@ public final class GeoUtils { if (y > lastY) { - return Cell.NSWE_SOUTH_EAST; // Direction.SOUTH_EAST; + return GeoStructure.CELL_FLAG_SE; // Direction.SOUTH_EAST; } else if (y < lastY) { - return Cell.NSWE_NORTH_EAST; // Direction.NORTH_EAST; + return GeoStructure.CELL_FLAG_NE; // Direction.NORTH_EAST; } else { - return Cell.NSWE_EAST; // Direction.EAST; + return GeoStructure.CELL_FLAG_E; // Direction.EAST; } } else if (x < lastX) // west { if (y > lastY) { - return Cell.NSWE_SOUTH_WEST; // Direction.SOUTH_WEST; + return GeoStructure.CELL_FLAG_SW; // Direction.SOUTH_WEST; } else if (y < lastY) { - return Cell.NSWE_NORTH_WEST; // Direction.NORTH_WEST; + return GeoStructure.CELL_FLAG_NW; // Direction.NORTH_WEST; } else { - return Cell.NSWE_WEST; // Direction.WEST; + return GeoStructure.CELL_FLAG_W; // Direction.WEST; } } else @@ -219,11 +219,11 @@ public final class GeoUtils { if (y > lastY) { - return Cell.NSWE_SOUTH; // Direction.SOUTH; + return GeoStructure.CELL_FLAG_S; // Direction.SOUTH; } else if (y < lastY) { - return Cell.NSWE_NORTH; // Direction.NORTH; + return GeoStructure.CELL_FLAG_N; // Direction.NORTH; } else { diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/tools/geodataconverter/GeoDataConverter.java b/L2J_Mobius_Ertheia/java/com/l2jmobius/tools/geodataconverter/GeoDataConverter.java new file mode 100644 index 0000000000..81621d8ee6 --- /dev/null +++ b/L2J_Mobius_Ertheia/java/com/l2jmobius/tools/geodataconverter/GeoDataConverter.java @@ -0,0 +1,375 @@ +/* + * 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 . + */ +package com.l2jmobius.tools.geodataconverter; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.RandomAccessFile; +import java.nio.ByteOrder; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.util.Scanner; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.PropertiesParser; +import com.l2jmobius.gameserver.geoengine.geodata.ABlock; +import com.l2jmobius.gameserver.geoengine.geodata.BlockComplex; +import com.l2jmobius.gameserver.geoengine.geodata.BlockFlat; +import com.l2jmobius.gameserver.geoengine.geodata.BlockMultilayer; +import com.l2jmobius.gameserver.geoengine.geodata.GeoFormat; +import com.l2jmobius.gameserver.geoengine.geodata.GeoStructure; +import com.l2jmobius.gameserver.model.L2World; + +/** + * @author Hasha + */ +public final class GeoDataConverter +{ + private static GeoFormat _format; + private static ABlock[][] _blocks; + + public static void main(String[] args) + { + // initialize config + loadGeoengineConfigs(); + + // get geodata format + String type = ""; + try (Scanner scn = new Scanner(System.in)) + { + while (!(type.equalsIgnoreCase("J") || type.equalsIgnoreCase("O") || type.equalsIgnoreCase("E"))) + { + System.out.println("GeoDataConverter: Select source geodata type:"); + System.out.println(" J: L2J (e.g. 23_22.l2j)"); + System.out.println(" O: L2OFF (e.g. 23_22_conv.dat)"); + System.out.println(" E: Exit"); + System.out.print("Choice: "); + type = scn.next(); + } + } + if (type.equalsIgnoreCase("E")) + { + System.exit(0); + } + + _format = type.equalsIgnoreCase("J") ? GeoFormat.L2J : GeoFormat.L2OFF; + + // start conversion + System.out.println("GeoDataConverter: Converting all " + _format.toString() + " files."); + + // initialize geodata container + _blocks = new ABlock[GeoStructure.REGION_BLOCKS_X][GeoStructure.REGION_BLOCKS_Y]; + + // initialize multilayer temporarily buffer + BlockMultilayer.initialize(); + + // load geo files + int converted = 0; + for (int rx = L2World.TILE_X_MIN; rx <= L2World.TILE_X_MAX; rx++) + { + for (int ry = L2World.TILE_Y_MIN; ry <= L2World.TILE_Y_MAX; ry++) + { + final String input = String.format(_format.getFilename(), rx, ry); + final String filepath = Config.GEODATA_PATH; + File f = new File(filepath + input); + if (f.exists() && !f.isDirectory()) + { + // load geodata + if (!loadGeoBlocks(input)) + { + System.out.println("GeoDataConverter: Unable to load " + input + " region file."); + continue; + } + + // recalculate nswe + if (!recalculateNswe()) + { + System.out.println("GeoDataConverter: Unable to convert " + input + " region file."); + continue; + } + + // save geodata + final String output = String.format(GeoFormat.L2D.getFilename(), rx, ry); + if (!saveGeoBlocks(output)) + { + System.out.println("GeoDataConverter: Unable to save " + output + " region file."); + continue; + } + + converted++; + System.out.println("GeoDataConverter: Created " + output + " region file."); + } + } + } + System.out.println("GeoDataConverter: Converted " + converted + " " + _format.toString() + " to L2D region file(s)."); + + // release multilayer block temporarily buffer + BlockMultilayer.release(); + } + + /** + * Loads geo blocks from buffer of the region file. + * @param filename : The name of the to load. + * @return boolean : True when successful. + */ + private static final boolean loadGeoBlocks(String filename) + { + // region file is load-able, try to load it + try (RandomAccessFile raf = new RandomAccessFile(Config.GEODATA_PATH + filename, "r"); + FileChannel fc = raf.getChannel()) + { + MappedByteBuffer buffer = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()).load(); + buffer.order(ByteOrder.LITTLE_ENDIAN); + + // load 18B header for L2off geodata (1st and 2nd byte...region X and Y) + if (_format == GeoFormat.L2OFF) + { + for (int i = 0; i < 18; i++) + { + buffer.get(); + } + } + + // loop over region blocks + for (int ix = 0; ix < GeoStructure.REGION_BLOCKS_X; ix++) + { + for (int iy = 0; iy < GeoStructure.REGION_BLOCKS_Y; iy++) + { + if (_format == GeoFormat.L2J) + { + // get block type + final byte type = buffer.get(); + + // load block according to block type + switch (type) + { + case GeoStructure.TYPE_FLAT_L2J_L2OFF: + _blocks[ix][iy] = new BlockFlat(buffer, _format); + break; + + case GeoStructure.TYPE_COMPLEX_L2J: + _blocks[ix][iy] = new BlockComplex(buffer, _format); + break; + + case GeoStructure.TYPE_MULTILAYER_L2J: + _blocks[ix][iy] = new BlockMultilayer(buffer, _format); + break; + + default: + throw new IllegalArgumentException("Unknown block type: " + type); + } + } + else + { + // get block type + final short type = buffer.getShort(); + + // load block according to block type + switch (type) + { + case GeoStructure.TYPE_FLAT_L2J_L2OFF: + _blocks[ix][iy] = new BlockFlat(buffer, _format); + break; + + case GeoStructure.TYPE_COMPLEX_L2OFF: + _blocks[ix][iy] = new BlockComplex(buffer, _format); + break; + + default: + _blocks[ix][iy] = new BlockMultilayer(buffer, _format); + break; + } + } + } + } + + if (buffer.remaining() > 0) + { + System.out.println("GeoDataConverter: Region file " + filename + " can be corrupted, remaining " + buffer.remaining() + " bytes to read."); + return false; + } + + return true; + } + catch (Exception e) + { + System.out.println("GeoDataConverter: Error while loading " + filename + " region file."); + return false; + } + } + + /** + * Recalculate diagonal flags for the region file. + * @return boolean : True when successful. + */ + private static final boolean recalculateNswe() + { + try + { + for (int x = 0; x < GeoStructure.REGION_CELLS_X; x++) + { + for (int y = 0; y < GeoStructure.REGION_CELLS_Y; y++) + { + // get block + ABlock block = _blocks[x / GeoStructure.BLOCK_CELLS_X][y / GeoStructure.BLOCK_CELLS_Y]; + + // skip flat blocks + if (block instanceof BlockFlat) + { + continue; + } + + // for complex and multilayer blocks go though all layers + short height = Short.MAX_VALUE; + int index; + while ((index = block.getIndexBelow(x, y, height)) != -1) + { + // get height and nswe + height = block.getHeight(index); + byte nswe = block.getNswe(index); + + // update nswe with diagonal flags + nswe = updateNsweBelow(x, y, height, nswe); + + // set nswe of the cell + block.setNswe(index, nswe); + } + } + } + + return true; + } + catch (Exception e) + { + return false; + } + } + + /** + * Updates the NSWE flag with diagonal flags. + * @param x : Geodata X coordinate. + * @param y : Geodata Y coordinate. + * @param z : Geodata Z coordinate. + * @param nswe : NSWE flag to be updated. + * @return byte : Updated NSWE flag. + */ + private static final byte updateNsweBelow(int x, int y, short z, byte nswe) + { + // calculate virtual layer height + short height = (short) (z + GeoStructure.CELL_IGNORE_HEIGHT); + + // get NSWE of neighbor cells below virtual layer (NPC/PC can fall down of clif, but can not climb it -> NSWE of cell below) + byte nsweN = getNsweBelow(x, y - 1, height); + byte nsweS = getNsweBelow(x, y + 1, height); + byte nsweW = getNsweBelow(x - 1, y, height); + byte nsweE = getNsweBelow(x + 1, y, height); + + // north-west + if ((((nswe & GeoStructure.CELL_FLAG_N) != 0) && ((nsweN & GeoStructure.CELL_FLAG_W) != 0)) || (((nswe & GeoStructure.CELL_FLAG_W) != 0) && ((nsweW & GeoStructure.CELL_FLAG_N) != 0))) + { + nswe |= GeoStructure.CELL_FLAG_NW; + } + + // north-east + if ((((nswe & GeoStructure.CELL_FLAG_N) != 0) && ((nsweN & GeoStructure.CELL_FLAG_E) != 0)) || (((nswe & GeoStructure.CELL_FLAG_E) != 0) && ((nsweE & GeoStructure.CELL_FLAG_N) != 0))) + { + nswe |= GeoStructure.CELL_FLAG_NE; + } + + // south-west + if ((((nswe & GeoStructure.CELL_FLAG_S) != 0) && ((nsweS & GeoStructure.CELL_FLAG_W) != 0)) || (((nswe & GeoStructure.CELL_FLAG_W) != 0) && ((nsweW & GeoStructure.CELL_FLAG_S) != 0))) + { + nswe |= GeoStructure.CELL_FLAG_SW; + } + + // south-east + if ((((nswe & GeoStructure.CELL_FLAG_S) != 0) && ((nsweS & GeoStructure.CELL_FLAG_E) != 0)) || (((nswe & GeoStructure.CELL_FLAG_E) != 0) && ((nsweE & GeoStructure.CELL_FLAG_S) != 0))) + { + nswe |= GeoStructure.CELL_FLAG_SE; + } + + return nswe; + } + + private static final byte getNsweBelow(int geoX, int geoY, short worldZ) + { + // out of geo coordinates + if ((geoX < 0) || (geoX >= GeoStructure.REGION_CELLS_X)) + { + return 0; + } + + // out of geo coordinates + if ((geoY < 0) || (geoY >= GeoStructure.REGION_CELLS_Y)) + { + return 0; + } + + // get block + final ABlock block = _blocks[geoX / GeoStructure.BLOCK_CELLS_X][geoY / GeoStructure.BLOCK_CELLS_Y]; + + // get index, when valid, return nswe + final int index = block.getIndexBelow(geoX, geoY, worldZ); + return index == -1 ? 0 : block.getNswe(index); + } + + /** + * Save region file to file. + * @param filename : The name of file to save. + * @return boolean : True when successful. + */ + private static final boolean saveGeoBlocks(String filename) + { + try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(Config.GEODATA_PATH + filename), GeoStructure.REGION_BLOCKS * GeoStructure.BLOCK_CELLS * 3)) + { + // loop over region blocks and save each block + for (int ix = 0; ix < GeoStructure.REGION_BLOCKS_X; ix++) + { + for (int iy = 0; iy < GeoStructure.REGION_BLOCKS_Y; iy++) + { + _blocks[ix][iy].saveBlock(bos); + } + } + + // flush data to file + bos.flush(); + + return true; + } + catch (Exception e) + { + return false; + } + } + + private static final void loadGeoengineConfigs() + { + final PropertiesParser geoData = new PropertiesParser(Config.GEODATA_FILE); + Config.GEODATA_PATH = geoData.getString("GeoDataPath", "./data/geodata/"); + Config.COORD_SYNCHRONIZE = geoData.getInt("CoordSynchronize", -1); + Config.PART_OF_CHARACTER_HEIGHT = geoData.getInt("PartOfCharacterHeight", 75); + Config.MAX_OBSTACLE_HEIGHT = geoData.getInt("MaxObstacleHeight", 32); + Config.PATHFINDING = geoData.getBoolean("PathFinding", true); + Config.PATHFIND_BUFFERS = geoData.getString("PathFindBuffers", "100x6;128x6;192x6;256x4;320x4;384x4;500x2"); + Config.BASE_WEIGHT = geoData.getInt("BaseWeight", 10); + Config.DIAGONAL_WEIGHT = geoData.getInt("DiagonalWeight", 14); + Config.OBSTACLE_MULTIPLIER = geoData.getInt("ObstacleMultiplier", 10); + Config.HEURISTIC_WEIGHT = geoData.getInt("HeuristicWeight", 20); + Config.MAX_ITERATIONS = geoData.getInt("MaxIterations", 3500); + } +} \ No newline at end of file diff --git a/L2J_Mobius_Ertheia/readme.txt b/L2J_Mobius_Ertheia/readme.txt index 8787f9cbf8..f6a9bfe6ad 100644 --- a/L2J_Mobius_Ertheia/readme.txt +++ b/L2J_Mobius_Ertheia/readme.txt @@ -3,7 +3,7 @@ L2J-Mobius Ertheia Client: https://mega.nz/#F!BxkyzLBA!CIuE1GQOO1JMel7S7UxPfQ Use mega downloader to download https://megadownloader.en.softonic.com/ -Geodata: http://www.mediafire.com/file/rxdm9b97kbue8dy/Mobius_Ertheia_Geodata.zip +Geodata: http://www.mediafire.com/file/jbnro1jm6q56bal/mobius_geodata_ertheia_l2d.zip What is done -Ertheia packet compatibility diff --git a/L2J_Mobius_Helios/build.xml b/L2J_Mobius_Helios/build.xml index 5351f046e2..31ca932872 100644 --- a/L2J_Mobius_Helios/build.xml +++ b/L2J_Mobius_Helios/build.xml @@ -74,6 +74,7 @@ + diff --git a/L2J_Mobius_Helios/dist/game/GeoDataConverter.bat b/L2J_Mobius_Helios/dist/game/GeoDataConverter.bat new file mode 100644 index 0000000000..1f199613e9 --- /dev/null +++ b/L2J_Mobius_Helios/dist/game/GeoDataConverter.bat @@ -0,0 +1,6 @@ +@echo off +title L2D geodata converter + +java -Xmx512m -cp ./../libs/*;GameServer.jar com.l2jmobius.tools.geodataconverter.GeoDataConverter + +pause diff --git a/L2J_Mobius_Helios/dist/game/GeoDataConverter.sh b/L2J_Mobius_Helios/dist/game/GeoDataConverter.sh new file mode 100644 index 0000000000..b039beec34 --- /dev/null +++ b/L2J_Mobius_Helios/dist/game/GeoDataConverter.sh @@ -0,0 +1,4 @@ +#! /bin/sh + +java -Xmx512m -cp ./../libs/*;GameServer.jar com.l2jmobius.tools.geodataconverter.GeoDataConverter > log/stdout.log 2>&1 + diff --git a/L2J_Mobius_Helios/dist/game/config/AdminCommands.xml b/L2J_Mobius_Helios/dist/game/config/AdminCommands.xml index d2ff6c880f..1cca083da9 100644 --- a/L2J_Mobius_Helios/dist/game/config/AdminCommands.xml +++ b/L2J_Mobius_Helios/dist/game/config/AdminCommands.xml @@ -413,11 +413,7 @@ - - - - - + diff --git a/L2J_Mobius_Helios/dist/game/config/GeoData.ini b/L2J_Mobius_Helios/dist/game/config/GeoData.ini deleted file mode 100644 index 52ef701461..0000000000 --- a/L2J_Mobius_Helios/dist/game/config/GeoData.ini +++ /dev/null @@ -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 diff --git a/L2J_Mobius_Helios/dist/game/config/GeoEngine.ini b/L2J_Mobius_Helios/dist/game/config/GeoEngine.ini new file mode 100644 index 0000000000..94a0b1ac44 --- /dev/null +++ b/L2J_Mobius_Helios/dist/game/config/GeoEngine.ini @@ -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 diff --git a/L2J_Mobius_Helios/dist/game/data/geodata/Readme.txt b/L2J_Mobius_Helios/dist/game/data/geodata/Readme.txt index bf1f2071aa..8b18814e82 100644 --- a/L2J_Mobius_Helios/dist/game/data/geodata/Readme.txt +++ b/L2J_Mobius_Helios/dist/game/data/geodata/Readme.txt @@ -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 # -# # -##################################################### \ No newline at end of file +############################################## +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. diff --git a/L2J_Mobius_Helios/dist/game/data/pathnode/Readme.txt b/L2J_Mobius_Helios/dist/game/data/pathnode/Readme.txt deleted file mode 100644 index 2dfdaa8aab..0000000000 --- a/L2J_Mobius_Helios/dist/game/data/pathnode/Readme.txt +++ /dev/null @@ -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 # -# # -##################################################### \ No newline at end of file diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/ImperialTomb/FourSepulchers/FourSepulchers.java b/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/ImperialTomb/FourSepulchers/FourSepulchers.java index d53bc8c351..954afd0819 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/ImperialTomb/FourSepulchers/FourSepulchers.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/ImperialTomb/FourSepulchers/FourSepulchers.java @@ -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); diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/KartiasLabyrinth/KartiaHelperAdolph.java b/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/KartiasLabyrinth/KartiaHelperAdolph.java index 2a3e8902fa..1e7527c930 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/KartiasLabyrinth/KartiaHelperAdolph.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/KartiasLabyrinth/KartiaHelperAdolph.java @@ -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)) { diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/KartiasLabyrinth/KartiaSupportTroop.java b/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/KartiasLabyrinth/KartiaSupportTroop.java index 4359ebca01..0b6462a39e 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/KartiasLabyrinth/KartiaSupportTroop.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/KartiasLabyrinth/KartiaSupportTroop.java @@ -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); } diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/PlainsOfDion/PlainsOfDion.java b/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/PlainsOfDion/PlainsOfDion.java index d6334e36c2..c1387a6527 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/PlainsOfDion/PlainsOfDion.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/PlainsOfDion/PlainsOfDion.java @@ -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)]); diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/PrimevalIsle/PrimevalIsle.java b/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/PrimevalIsle/PrimevalIsle.java index d02786fc20..1ccd0b2a99 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/PrimevalIsle/PrimevalIsle.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/PrimevalIsle/PrimevalIsle.java @@ -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) diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/BoyAndGirl.java b/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/BoyAndGirl.java index 64c6501bd8..594ba85809 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/BoyAndGirl.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/BoyAndGirl.java @@ -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); } diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/Devno.java b/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/Devno.java index 3dd3b671cb..5b67a2a2e7 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/Devno.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/Devno.java @@ -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); } diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/Eleve.java b/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/Eleve.java index 7900817585..2258392af4 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/Eleve.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/Eleve.java @@ -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); } diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/Handermonkey.java b/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/Handermonkey.java index cb173a5030..e66acd12da 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/Handermonkey.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/Handermonkey.java @@ -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 diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/Karonf.java b/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/Karonf.java index 7297eeca95..0cd3444fd8 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/Karonf.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/Karonf.java @@ -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); } diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/Marsha.java b/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/Marsha.java index dbbba8d5f0..bae9a9253a 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/Marsha.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/Marsha.java @@ -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); } diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/Morgan.java b/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/Morgan.java index f976d88263..fc7164bd5f 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/Morgan.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/Morgan.java @@ -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); } diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/Rubentis.java b/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/Rubentis.java index 19b9fd7893..e50e2bc306 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/Rubentis.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/ai/areas/TalkingIsland/Rubentis.java @@ -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); } diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/ai/bosses/Frintezza/ScarletVanHalisha.java b/L2J_Mobius_Helios/dist/game/data/scripts/ai/bosses/Frintezza/ScarletVanHalisha.java index 175973cc3d..139154e05a 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/ai/bosses/Frintezza/ScarletVanHalisha.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/ai/bosses/Frintezza/ScarletVanHalisha.java @@ -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; } diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/ai/bosses/Tiat/Stage1.java b/L2J_Mobius_Helios/dist/game/data/scripts/ai/bosses/Tiat/Stage1.java index 6eb16f838e..a852734cb4 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/ai/bosses/Tiat/Stage1.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/ai/bosses/Tiat/Stage1.java @@ -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); } } } diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/ai/bosses/Valakas/Valakas.java b/L2J_Mobius_Helios/dist/game/data/scripts/ai/bosses/Valakas/Valakas.java index 9f5375d349..4275a803e2 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/ai/bosses/Valakas/Valakas.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/ai/bosses/Valakas/Valakas.java @@ -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)); } diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/ai/others/FleeMonsters.java b/L2J_Mobius_Helios/dist/game/data/scripts/ai/others/FleeMonsters.java index b377af5c37..632e19d481 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/ai/others/FleeMonsters.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/ai/others/FleeMonsters.java @@ -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); } diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/actionhandlers/L2PcInstanceAction.java b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/actionhandlers/L2PcInstanceAction.java index eb06ec5594..13902652f4 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/actionhandlers/L2PcInstanceAction.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/actionhandlers/L2PcInstanceAction.java @@ -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); } diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/actionhandlers/L2PetInstanceAction.java b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/actionhandlers/L2PetInstanceAction.java index c21b0e6ca1..5c2fe5e762 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/actionhandlers/L2PetInstanceAction.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/actionhandlers/L2PetInstanceAction.java @@ -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(); diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/actionhandlers/L2SummonAction.java b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/actionhandlers/L2SummonAction.java index b6af1a7ca4..11b1192023 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/actionhandlers/L2SummonAction.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/actionhandlers/L2SummonAction.java @@ -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); } diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminGeodata.java b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminGeodata.java index bfa36a76d5..551e52bbb0 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminGeodata.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminGeodata.java @@ -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."); } diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminPathNode.java b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminPathNode.java index 03b3ca8902..9cb85c282f 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminPathNode.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminPathNode.java @@ -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 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 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; } diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminServerInfo.java b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminServerInfo.java index 6796381333..867836c680 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminServerInfo.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminServerInfo.java @@ -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")); diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminTeleport.java b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminTeleport.java index 1b738a0264..fbf049aae5 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminTeleport.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminTeleport.java @@ -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); } diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminZones.java b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminZones.java index d6949af214..d5baa52a73 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminZones.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminZones.java @@ -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); } diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/effecthandlers/Blink.java b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/effecthandlers/Blink.java index 0e1c1d1aca..db1463c04d 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/effecthandlers/Blink.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/effecthandlers/Blink.java @@ -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)); diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/effecthandlers/Fear.java b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/effecthandlers/Fear.java index 7525c0f5ec..78fc694005 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/effecthandlers/Fear.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/effecthandlers/Fear.java @@ -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); } } diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/effecthandlers/FlyAway.java b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/effecthandlers/FlyAway.java index 1da9965557..a4d5e7f74b 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/effecthandlers/FlyAway.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/effecthandlers/FlyAway.java @@ -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); diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/effecthandlers/KnockBack.java b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/effecthandlers/KnockBack.java index ad73aef663..e2ddb48286 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/effecthandlers/KnockBack.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/effecthandlers/KnockBack.java @@ -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)); diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/effecthandlers/PullBack.java b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/effecthandlers/PullBack.java index 7850b26d5d..07b43c83d3 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/effecthandlers/PullBack.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/effecthandlers/PullBack.java @@ -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); diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/effecthandlers/TeleportToSummon.java b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/effecthandlers/TeleportToSummon.java index 8144305363..bffc2aecce 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/effecthandlers/TeleportToSummon.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/effecthandlers/TeleportToSummon.java @@ -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)); diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/effecthandlers/TeleportToTarget.java b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/effecthandlers/TeleportToTarget.java index 93ffb3174d..81504f196e 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/effecthandlers/TeleportToTarget.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/effecthandlers/TeleportToTarget.java @@ -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)); diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/skillconditionhandlers/OpBlinkSkillCondition.java b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/skillconditionhandlers/OpBlinkSkillCondition.java index 4b33ad31b2..bea71eb6e5 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/skillconditionhandlers/OpBlinkSkillCondition.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/skillconditionhandlers/OpBlinkSkillCondition.java @@ -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()); } } diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/Enemy.java b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/Enemy.java index b16408fba4..91fc781e3f 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/Enemy.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/Enemy.java @@ -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) { diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/EnemyNot.java b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/EnemyNot.java index 005d4e0ee1..00d3d4d8e2 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/EnemyNot.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/EnemyNot.java @@ -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) { diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/EnemyOnly.java b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/EnemyOnly.java index 2f5a79d6f5..5815598285 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/EnemyOnly.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/EnemyOnly.java @@ -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) { diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/Ground.java b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/Ground.java index f3b38dcf71..280f19d239 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/Ground.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/Ground.java @@ -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) { diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/NpcBody.java b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/NpcBody.java index 699fa269c7..7f46507e5b 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/NpcBody.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/NpcBody.java @@ -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) { diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/PcBody.java b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/PcBody.java index 77a9c9edd3..0ef234b8ac 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/PcBody.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/PcBody.java @@ -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) { diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/Target.java b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/Target.java index b388976172..f8456ed9f9 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/Target.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/Target.java @@ -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) { diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/affectscope/Fan.java b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/affectscope/Fan.java index 2487c40d5e..59b2d086d5 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/affectscope/Fan.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/affectscope/Fan.java @@ -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; } diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/affectscope/FanPB.java b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/affectscope/FanPB.java index ec987c91eb..d6783cff58 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/affectscope/FanPB.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/affectscope/FanPB.java @@ -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; } diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/affectscope/PointBlank.java b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/affectscope/PointBlank.java index d6c63186a2..2f7568dd13 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/affectscope/PointBlank.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/affectscope/PointBlank.java @@ -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; } diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/affectscope/Range.java b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/affectscope/Range.java index 90abebd98f..1d8ccd51e8 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/affectscope/Range.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/affectscope/Range.java @@ -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; } diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/affectscope/RingRange.java b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/affectscope/RingRange.java index 6cbe61fe1c..24c89e82d5 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/affectscope/RingRange.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/affectscope/RingRange.java @@ -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; } diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/affectscope/Square.java b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/affectscope/Square.java index 3225de6245..c39a270d2c 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/affectscope/Square.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/affectscope/Square.java @@ -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; } diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/affectscope/SquarePB.java b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/affectscope/SquarePB.java index 7ffad78a8f..1f695cc99d 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/affectscope/SquarePB.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/handlers/targethandlers/affectscope/SquarePB.java @@ -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; } diff --git a/L2J_Mobius_Helios/dist/game/data/scripts/quests/Q10753_WindsOfFateChoices/Q10753_WindsOfFateChoices.java b/L2J_Mobius_Helios/dist/game/data/scripts/quests/Q10753_WindsOfFateChoices/Q10753_WindsOfFateChoices.java index d7432591e5..65f0d20c26 100644 --- a/L2J_Mobius_Helios/dist/game/data/scripts/quests/Q10753_WindsOfFateChoices/Q10753_WindsOfFateChoices.java +++ b/L2J_Mobius_Helios/dist/game/data/scripts/quests/Q10753_WindsOfFateChoices/Q10753_WindsOfFateChoices.java @@ -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(); } diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/Config.java b/L2J_Mobius_Helios/java/com/l2jmobius/Config.java index 1dd46d6351..6ec607c7b0 100644 --- a/L2J_Mobius_Helios/java/com/l2jmobius/Config.java +++ b/L2J_Mobius_Helios/java/com/l2jmobius/Config.java @@ -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 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); diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/commons/util/MathUtil.java b/L2J_Mobius_Helios/java/com/l2jmobius/commons/util/MathUtil.java index 91dfcc4171..b0867bb70f 100644 --- a/L2J_Mobius_Helios/java/com/l2jmobius/commons/util/MathUtil.java +++ b/L2J_Mobius_Helios/java/com/l2jmobius/commons/util/MathUtil.java @@ -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); + } } diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/GameServer.java index 7762af0331..42b4933b82 100644 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/GameServer.java @@ -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; diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/ai/FriendlyNpcAI.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/ai/FriendlyNpcAI.java index 3eebee88ea..60fa4b1c8a 100644 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/ai/FriendlyNpcAI.java +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/ai/FriendlyNpcAI.java @@ -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()) { diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java index c363c397b5..46287d4e8e 100644 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java @@ -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) diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/ai/L2CharacterAI.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/ai/L2CharacterAI.java index 0d66c4a387..b046658f42 100644 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/ai/L2CharacterAI.java +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/ai/L2CharacterAI.java @@ -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; diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/ai/L2FortSiegeGuardAI.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/ai/L2FortSiegeGuardAI.java index 79f39cb51d..426228ee50 100644 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/ai/L2FortSiegeGuardAI.java +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/ai/L2FortSiegeGuardAI.java @@ -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 diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/ai/L2SiegeGuardAI.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/ai/L2SiegeGuardAI.java index caf5f39544..7cd4bb5dc1 100644 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/ai/L2SiegeGuardAI.java +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/ai/L2SiegeGuardAI.java @@ -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 diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/ai/L2SummonAI.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/ai/L2SummonAI.java index 00c00b8ff9..e29df8102b 100644 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/ai/L2SummonAI.java +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/ai/L2SummonAI.java @@ -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()); } diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/data/xml/impl/DoorData.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/data/xml/impl/DoorData.java index 973c82b4a8..592f3af578 100644 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/data/xml/impl/DoorData.java +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/data/xml/impl/DoorData.java @@ -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); } diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/GeoData.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/GeoData.java deleted file mode 100644 index a44ba3b703..0000000000 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/GeoData.java +++ /dev/null @@ -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 . - */ -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(); - } -} diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/Cell.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/Cell.java deleted file mode 100644 index 4914b1d72e..0000000000 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/Cell.java +++ /dev/null @@ -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 . - */ -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() - { - } -} diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/GeoDriver.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/GeoDriver.java deleted file mode 100644 index 2dc266df46..0000000000 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/GeoDriver.java +++ /dev/null @@ -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 . - */ -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 _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; - } -} diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/IBlock.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/IBlock.java deleted file mode 100644 index 21df97c40d..0000000000 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/IBlock.java +++ /dev/null @@ -1,42 +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 . - */ -package com.l2jmobius.gameserver.geodata.geodriver; - -/** - * @author HorridoJoho - */ -public interface IBlock -{ - int TYPE_FLAT = 0; - int TYPE_COMPLEX = 1; - int TYPE_MULTILAYER = 2; - - /** Cells in a block on the x axis */ - int BLOCK_CELLS_X = 8; - /** Cells in a block on the y axis */ - int BLOCK_CELLS_Y = 8; - /** Cells in a block */ - int BLOCK_CELLS = BLOCK_CELLS_X * BLOCK_CELLS_Y; - - boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe); - - int getNearestZ(int geoX, int geoY, int worldZ); - - int getNextLowerZ(int geoX, int geoY, int worldZ); - - int getNextHigherZ(int geoX, int geoY, int worldZ); -} diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/IRegion.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/IRegion.java deleted file mode 100644 index 3eb23da03e..0000000000 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/IRegion.java +++ /dev/null @@ -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 . - */ -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(); -} diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/ComplexBlock.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/ComplexBlock.java deleted file mode 100644 index 4d6410672e..0000000000 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/ComplexBlock.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/FlatBlock.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/FlatBlock.java deleted file mode 100644 index d5bcff094b..0000000000 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/FlatBlock.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/MultilayerBlock.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/MultilayerBlock.java deleted file mode 100644 index 313131bd5a..0000000000 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/MultilayerBlock.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/regions/NullRegion.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/regions/NullRegion.java deleted file mode 100644 index 60ecac873a..0000000000 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/regions/NullRegion.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/regions/Region.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/regions/Region.java deleted file mode 100644 index d2d02481ed..0000000000 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/geodriver/regions/Region.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNode.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNode.java deleted file mode 100644 index 83d0131910..0000000000 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNode.java +++ /dev/null @@ -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 . - */ -package com.l2jmobius.gameserver.geodata.pathfinding; - -public abstract class AbstractNode -{ - private T _loc; - private AbstractNode _parent; - - public AbstractNode(T loc) - { - _loc = loc; - } - - public void setParent(AbstractNode p) - { - _parent = p; - } - - public AbstractNode 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; - } -} \ No newline at end of file diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/PathFinding.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/PathFinding.java deleted file mode 100644 index e7b3093081..0000000000 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/PathFinding.java +++ /dev/null @@ -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 . - */ -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 findPath(int x, int y, int z, int tx, int ty, int tz, Instance instance, boolean playable); - - // @formatter:off - /* - public List 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 visited = new LinkedList(); - - // List of Nodes to Visit - LinkedList to_visit = new LinkedList(); - 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 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; - } -} diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNode.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNode.java deleted file mode 100644 index f903507286..0000000000 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNode.java +++ /dev/null @@ -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 . - */ -package com.l2jmobius.gameserver.geodata.pathfinding.cellnodes; - -import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNode; - -public class CellNode extends AbstractNode -{ - 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; - } -} \ No newline at end of file diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNodeBuffer.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNodeBuffer.java deleted file mode 100644 index 4eef566183..0000000000 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNodeBuffer.java +++ /dev/null @@ -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 . - */ -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 debugPath() - { - final List 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; - } -} \ No newline at end of file diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellPathFinding.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellPathFinding.java deleted file mode 100644 index 9eb6b0d04a..0000000000 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellPathFinding.java +++ /dev/null @@ -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 . - */ -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 _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 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 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 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 constructPath(AbstractNode node) - { - final LinkedList 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 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(); - } -} diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/NodeLoc.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/NodeLoc.java deleted file mode 100644 index 353dee1d7f..0000000000 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/NodeLoc.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNode.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNode.java deleted file mode 100644 index fb9d7fdd2e..0000000000 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNode.java +++ /dev/null @@ -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 . - */ -package com.l2jmobius.gameserver.geodata.pathfinding.geonodes; - -import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNode; - -/** - * @author -Nemesiss- - */ -public class GeoNode extends AbstractNode -{ - 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); - } - } -} diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNodeLoc.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNodeLoc.java deleted file mode 100644 index 9dabc50452..0000000000 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNodeLoc.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoPathFinding.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoPathFinding.java deleted file mode 100644 index f2d6c87e78..0000000000 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoPathFinding.java +++ /dev/null @@ -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 . - */ -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 _pathNodes = new ConcurrentHashMap<>(); - private static Map _pathNodesIndex = new ConcurrentHashMap<>(); - - public static GeoPathFinding getInstance() - { - return SingletonHolder._instance; - } - - @Override - public boolean pathNodesExist(short regionoffset) - { - return _pathNodesIndex.containsKey(regionoffset); - } - - @Override - public List 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 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 visited = new ArrayList<>(550); - - // List of Nodes to Visit - final LinkedList 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 constructPath2(AbstractNode node) - { - final LinkedList 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> 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(); - } -} diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/utils/BinaryNodeHeap.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/utils/BinaryNodeHeap.java deleted file mode 100644 index 665977f686..0000000000 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geodata/pathfinding/utils/BinaryNodeHeap.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java new file mode 100644 index 0000000000..587aab48e2 --- /dev/null +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java @@ -0,0 +1,1311 @@ +/* + * 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 . + */ +package com.l2jmobius.gameserver.geoengine; + +import java.io.File; +import java.io.RandomAccessFile; +import java.nio.ByteOrder; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.util.List; +import java.util.logging.Logger; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.MathUtil; +import com.l2jmobius.gameserver.data.xml.impl.DoorData; +import com.l2jmobius.gameserver.geoengine.geodata.ABlock; +import com.l2jmobius.gameserver.geoengine.geodata.BlockComplex; +import com.l2jmobius.gameserver.geoengine.geodata.BlockComplexDynamic; +import com.l2jmobius.gameserver.geoengine.geodata.BlockFlat; +import com.l2jmobius.gameserver.geoengine.geodata.BlockMultilayer; +import com.l2jmobius.gameserver.geoengine.geodata.BlockMultilayerDynamic; +import com.l2jmobius.gameserver.geoengine.geodata.BlockNull; +import com.l2jmobius.gameserver.geoengine.geodata.GeoFormat; +import com.l2jmobius.gameserver.geoengine.geodata.GeoLocation; +import com.l2jmobius.gameserver.geoengine.geodata.GeoStructure; +import com.l2jmobius.gameserver.geoengine.geodata.IBlockDynamic; +import com.l2jmobius.gameserver.geoengine.geodata.IGeoObject; +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.actor.L2Character; +import com.l2jmobius.gameserver.model.actor.instance.L2DoorInstance; +import com.l2jmobius.gameserver.model.instancezone.Instance; + +/** + * @author Hasha + */ +public class GeoEngine +{ + protected static final Logger _log = Logger.getLogger(GeoEngine.class.getName()); + + private final ABlock[][] _blocks; + private final BlockNull _nullBlock; + + /** + * Returns the instance of the {@link GeoEngine}. + * @return {@link GeoEngine} : The instance. + */ + public static final GeoEngine getInstance() + { + return SingletonHolder._instance; + } + + /** + * GeoEngine contructor. Loads all geodata files of chosen geodata format. + */ + public GeoEngine() + { + _log.info("GeoEngine: Initializing..."); + + // initialize block container + _blocks = new ABlock[GeoStructure.GEO_BLOCKS_X][GeoStructure.GEO_BLOCKS_Y]; + + // load null block + _nullBlock = new BlockNull(); + + // initialize multilayer temporarily buffer + BlockMultilayer.initialize(); + + // load geo files according to geoengine config setup + int loaded = 0; + int failed = 0; + for (int rx = L2World.TILE_X_MIN; rx <= L2World.TILE_X_MAX; rx++) + { + for (int ry = L2World.TILE_Y_MIN; ry <= L2World.TILE_Y_MAX; ry++) + { + final String filename = String.format(GeoFormat.L2D.getFilename(), rx, ry); + final String filepath = Config.GEODATA_PATH; + File f = new File(filepath + filename); + if (f.exists() && !f.isDirectory()) + { + // region file is load-able, try to load it + if (loadGeoBlocks(rx, ry)) + { + loaded++; + } + else + { + failed++; + } + } + else + { + // region file is not load-able, load null blocks + loadNullBlocks(rx, ry); + } + } + } + _log.info("GeoEngine: Loaded " + loaded + " L2D region files."); + + // Avoid wrong config when no files loaded + if ((loaded == 0) && (Config.COORD_SYNCHRONIZE == 2)) + { + Config.COORD_SYNCHRONIZE = -1; + _log.info("GeoEngine: Forcing CoordSynchronize setting to -1."); + } + + // release multilayer block temporarily buffer + BlockMultilayer.release(); + + if (failed > 0) + { + _log.info("GeoEngine: Failed to load " + failed + " L2D region files. Please consider to check your \"GeoEngine.ini\" settings and location of \"XX_YY.L2D\" geodata files."); + System.exit(1); + } + } + + /** + * Loads geodata from a file. When file does not exist, is corrupted or not consistent, loads none geodata. + * @param regionX : Geodata file region X coordinate. + * @param regionY : Geodata file region Y coordinate. + * @return boolean : True, when geodata file was loaded without problem. + */ + private final boolean loadGeoBlocks(int regionX, int regionY) + { + final String filename = String.format(GeoFormat.L2D.getFilename(), regionX, regionY); + final String filepath = Config.GEODATA_PATH + filename; + + // standard load + try (RandomAccessFile raf = new RandomAccessFile(filepath, "r"); + FileChannel fc = raf.getChannel()) + { + // initialize file buffer + MappedByteBuffer buffer = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()).load(); + buffer.order(ByteOrder.LITTLE_ENDIAN); + + // get block indexes + final int blockX = (regionX - L2World.TILE_X_MIN) * GeoStructure.REGION_BLOCKS_X; + final int blockY = (regionY - L2World.TILE_Y_MIN) * GeoStructure.REGION_BLOCKS_Y; + + // loop over region blocks + for (int ix = 0; ix < GeoStructure.REGION_BLOCKS_X; ix++) + { + for (int iy = 0; iy < GeoStructure.REGION_BLOCKS_Y; iy++) + { + // get block type + final byte type = buffer.get(); + + // load block according to block type + switch (type) + { + case GeoStructure.TYPE_FLAT_L2D: + _blocks[blockX + ix][blockY + iy] = new BlockFlat(buffer, GeoFormat.L2D); + break; + + case GeoStructure.TYPE_COMPLEX_L2D: + _blocks[blockX + ix][blockY + iy] = new BlockComplex(buffer, GeoFormat.L2D); + break; + + case GeoStructure.TYPE_MULTILAYER_L2D: + _blocks[blockX + ix][blockY + iy] = new BlockMultilayer(buffer, GeoFormat.L2D); + break; + + default: + throw new IllegalArgumentException("Unknown block type: " + type); + } + } + } + + // check data consistency + if (buffer.remaining() > 0) + { + _log.warning("GeoEngine: Region file " + filename + " can be corrupted, remaining " + buffer.remaining() + " bytes to read."); + } + + // loading was successful + return true; + } + catch (Exception e) + { + // an error occured while loading, load null blocks + _log.warning("GeoEngine: Error while loading " + filename + " region file."); + _log.warning(e.getMessage()); + e.printStackTrace(); + + // replace whole region file with null blocks + loadNullBlocks(regionX, regionY); + + // loading was not successful + return false; + } + } + + /** + * Loads null blocks. Used when no region file is detected or an error occurs during loading. + * @param regionX : Geodata file region X coordinate. + * @param regionY : Geodata file region Y coordinate. + */ + private final void loadNullBlocks(int regionX, int regionY) + { + // get block indexes + final int blockX = (regionX - L2World.TILE_X_MIN) * GeoStructure.REGION_BLOCKS_X; + final int blockY = (regionY - L2World.TILE_Y_MIN) * GeoStructure.REGION_BLOCKS_Y; + + // load all null blocks + for (int ix = 0; ix < GeoStructure.REGION_BLOCKS_X; ix++) + { + for (int iy = 0; iy < GeoStructure.REGION_BLOCKS_Y; iy++) + { + _blocks[blockX + ix][blockY + iy] = _nullBlock; + } + } + } + + // GEODATA - GENERAL + + /** + * Converts world X to geodata X. + * @param worldX + * @return int : Geo X + */ + public final int getGeoX(int worldX) + { + return (MathUtil.limit(worldX, L2World.MAP_MIN_X, L2World.MAP_MAX_X) - L2World.MAP_MIN_X) >> 4; + } + + /** + * Converts world Y to geodata Y. + * @param worldY + * @return int : Geo Y + */ + public final int getGeoY(int worldY) + { + return (MathUtil.limit(worldY, L2World.MAP_MIN_Y, L2World.MAP_MAX_Y) - L2World.MAP_MIN_Y) >> 4; + } + + /** + * Converts geodata X to world X. + * @param geoX + * @return int : World X + */ + public final int getWorldX(int geoX) + { + return (MathUtil.limit(geoX, 0, GeoStructure.GEO_CELLS_X) << 4) + L2World.MAP_MIN_X + 8; + } + + /** + * Converts geodata Y to world Y. + * @param geoY + * @return int : World Y + */ + public final int getWorldY(int geoY) + { + return (MathUtil.limit(geoY, 0, GeoStructure.GEO_CELLS_Y) << 4) + L2World.MAP_MIN_Y + 8; + } + + /** + * Returns block of geodata on given coordinates. + * @param geoX : Geodata X + * @param geoY : Geodata Y + * @return {@link ABlock} : Bloack of geodata. + */ + public final ABlock getBlock(int geoX, int geoY) + { + return _blocks[geoX / GeoStructure.BLOCK_CELLS_X][geoY / GeoStructure.BLOCK_CELLS_Y]; + } + + /** + * Check if geo coordinates has geo. + * @param geoX : Geodata X + * @param geoY : Geodata Y + * @return boolean : True, if given geo coordinates have geodata + */ + public final boolean hasGeoPos(int geoX, int geoY) + { + return getBlock(geoX, geoY).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, closest to given coordinates. + */ + public final short getHeightNearest(int geoX, int geoY, int worldZ) + { + return getBlock(geoX, geoY).getHeightNearest(geoX, geoY, worldZ); + } + + /** + * Returns the height of cell, which is closest to given coordinates.
+ * 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, closest to given coordinates. + */ + public final short getHeightNearestOriginal(int geoX, int geoY, int worldZ) + { + return getBlock(geoX, geoY).getHeightNearestOriginal(geoX, geoY, worldZ); + } + + /** + * Returns the NSWE flag byte of cell, which is closes 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 coordinate, closest to given coordinates. + */ + public final byte getNsweNearest(int geoX, int geoY, int worldZ) + { + return getBlock(geoX, geoY).getNsweNearest(geoX, geoY, worldZ); + } + + /** + * Returns the NSWE flag byte of cell, which is closes to given coordinates.
+ * 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 coordinate, closest to given coordinates. + */ + public final byte getNsweNearestOriginal(int geoX, int geoY, int worldZ) + { + return getBlock(geoX, geoY).getNsweNearestOriginal(geoX, geoY, worldZ); + } + + /** + * Check if world coordinates has geo. + * @param worldX : World X + * @param worldY : World Y + * @return boolean : True, if given world coordinates have geodata + */ + public final boolean hasGeo(int worldX, int worldY) + { + return hasGeoPos(getGeoX(worldX), getGeoY(worldY)); + } + + /** + * Returns closest Z coordinate according to geodata. + * @param worldX : world x + * @param worldY : world y + * @param worldZ : world z + * @return short : nearest Z coordinates according to geodata + */ + public final short getHeight(int worldX, int worldY, int worldZ) + { + return getHeightNearest(getGeoX(worldX), getGeoY(worldY), worldZ); + } + + // GEODATA - DYNAMIC + + /** + * Returns calculated NSWE flag byte as a description of {@link IGeoObject}.
+ * The {@link IGeoObject} is defined by boolean 2D array, saying if the object is present on given cell or not. + * @param inside : 2D description of {@link IGeoObject} + * @return byte[][] : Returns NSWE flags of {@link IGeoObject}. + */ + public static final byte[][] calculateGeoObject(boolean inside[][]) + { + // get dimensions + final int width = inside.length; + final int height = inside[0].length; + + // create object flags for geodata, according to the geo object 2D description + final byte[][] result = new byte[width][height]; + + // loop over each cell of the geo object + for (int ix = 0; ix < width; ix++) + { + for (int iy = 0; iy < height; iy++) + { + if (inside[ix][iy]) + { + // cell is inside geo object, block whole movement (nswe = 0) + result[ix][iy] = 0; + } + else + { + // cell is outside of geo object, block only movement leading inside geo object + + // set initial value -> no geodata change + byte nswe = (byte) 0xFF; + + // perform axial and diagonal checks + if (iy < (height - 1)) + { + if (inside[ix][iy + 1]) + { + nswe &= ~GeoStructure.CELL_FLAG_S; + } + } + if (iy > 0) + { + if (inside[ix][iy - 1]) + { + nswe &= ~GeoStructure.CELL_FLAG_N; + } + } + if (ix < (width - 1)) + { + if (inside[ix + 1][iy]) + { + nswe &= ~GeoStructure.CELL_FLAG_E; + } + } + if (ix > 0) + { + if (inside[ix - 1][iy]) + { + nswe &= ~GeoStructure.CELL_FLAG_W; + } + } + if ((ix < (width - 1)) && (iy < (height - 1))) + { + if (inside[ix + 1][iy + 1] || inside[ix][iy + 1] || inside[ix + 1][iy]) + { + nswe &= ~GeoStructure.CELL_FLAG_SE; + } + } + if ((ix < (width - 1)) && (iy > 0)) + { + if (inside[ix + 1][iy - 1] || inside[ix][iy - 1] || inside[ix + 1][iy]) + { + nswe &= ~GeoStructure.CELL_FLAG_NE; + } + } + if ((ix > 0) && (iy < (height - 1))) + { + if (inside[ix - 1][iy + 1] || inside[ix][iy + 1] || inside[ix - 1][iy]) + { + nswe &= ~GeoStructure.CELL_FLAG_SW; + } + } + if ((ix > 0) && (iy > 0)) + { + if (inside[ix - 1][iy - 1] || inside[ix][iy - 1] || inside[ix - 1][iy]) + { + nswe &= ~GeoStructure.CELL_FLAG_NW; + } + } + + result[ix][iy] = nswe; + } + } + } + + return result; + } + + /** + * Add {@link IGeoObject} to the geodata. + * @param object : An object using {@link IGeoObject} interface. + */ + public final void addGeoObject(IGeoObject object) + { + toggleGeoObject(object, true); + } + + /** + * Remove {@link IGeoObject} from the geodata. + * @param object : An object using {@link IGeoObject} interface. + */ + public final void removeGeoObject(IGeoObject object) + { + toggleGeoObject(object, false); + } + + /** + * Toggles an {@link IGeoObject} in the geodata. + * @param object : An object using {@link IGeoObject} interface. + * @param add : Add/remove object. + */ + private final void toggleGeoObject(IGeoObject object, boolean add) + { + // get object geo coordinates and data + final int minGX = object.getGeoX(); + final int minGY = object.getGeoY(); + final byte[][] geoData = object.getObjectGeoData(); + + // get min/max block coordinates + int minBX = minGX / GeoStructure.BLOCK_CELLS_X; + int maxBX = ((minGX + geoData.length) - 1) / GeoStructure.BLOCK_CELLS_X; + int minBY = minGY / GeoStructure.BLOCK_CELLS_Y; + int maxBY = ((minGY + geoData[0].length) - 1) / GeoStructure.BLOCK_CELLS_Y; + + // loop over affected blocks in X direction + for (int bx = minBX; bx <= maxBX; bx++) + { + // loop over affected blocks in Y direction + for (int by = minBY; by <= maxBY; by++) + { + ABlock block; + + // conversion to dynamic block must be synchronized to prevent 2 independent threads converting same block + synchronized (_blocks) + { + // get related block + block = _blocks[bx][by]; + + // check for dynamic block + if (!(block instanceof IBlockDynamic)) + { + // null block means no geodata (particular region file is not loaded), no geodata means no geobjects + if (block instanceof BlockNull) + { + continue; + } + + // not a dynamic block, convert it + if (block instanceof BlockFlat) + { + // convert flat block to the dynamic complex block + block = new BlockComplexDynamic(bx, by, (BlockFlat) block); + _blocks[bx][by] = block; + } + else if (block instanceof BlockComplex) + { + // convert complex block to the dynamic complex block + block = new BlockComplexDynamic(bx, by, (BlockComplex) block); + _blocks[bx][by] = block; + } + else if (block instanceof BlockMultilayer) + { + // convert multilayer block to the dynamic multilayer block + block = new BlockMultilayerDynamic(bx, by, (BlockMultilayer) block); + _blocks[bx][by] = block; + } + } + } + + // add/remove geo object to/from dynamic block + if (add) + { + ((IBlockDynamic) block).addGeoObject(object); + } + else + { + ((IBlockDynamic) block).removeGeoObject(object); + } + } + } + } + + // PATHFINDING + + /** + * Check line of sight from {@link L2Object} to {@link L2Object}. + * @param origin : The origin object. + * @param target : The target object. + * @return {@code boolean} : True if origin can see target + */ + public final boolean canSeeTarget(L2Object origin, L2Object target) + { + // get origin and target world coordinates + final int ox = origin.getX(); + final int oy = origin.getY(); + final int oz = origin.getZ(); + final int tx = target.getX(); + final int ty = target.getY(); + final int tz = target.getZ(); + + // get origin and check existing geo coordinates + final int gox = getGeoX(ox); + final int goy = getGeoY(oy); + if (!hasGeoPos(gox, goy)) + { + return true; + } + + final short goz = getHeightNearest(gox, goy, oz); + + // get target and check existing geo coordinates + final int gtx = getGeoX(tx); + final int gty = getGeoY(ty); + if (!hasGeoPos(gtx, gty)) + { + return true; + } + + final boolean door = target.isDoor(); + final short gtz = door ? getHeightNearestOriginal(gtx, gty, tz) : getHeightNearest(gtx, gty, tz); + + // origin and target coordinates are same + if ((gox == gtx) && (goy == gty)) + { + return goz == gtz; + } + + // get origin and target height, real height = collision height * 2 + double oheight = 0; + if (origin.isCharacter()) + { + oheight = ((L2Character) origin).getCollisionHeight() * 2; + } + + double theight = 0; + if (target.isCharacter()) + { + theight = ((L2Character) target).getCollisionHeight() * 2; + } + + // perform geodata check + return door ? checkSeeOriginal(gox, goy, goz, oheight, gtx, gty, gtz, theight) : checkSee(gox, goy, goz, oheight, gtx, gty, gtz, theight); + } + + /** + * Check line of sight from {@link L2Object} to {@link Location}. + * @param origin : The origin object. + * @param position : The target position. + * @return {@code boolean} : True if object can see position + */ + public final boolean canSeeTarget(L2Object origin, Location position) + { + // get origin and target world coordinates + final int ox = origin.getX(); + final int oy = origin.getY(); + final int oz = origin.getZ(); + final int tx = position.getX(); + final int ty = position.getY(); + final int tz = position.getZ(); + + // get origin and check existing geo coordinates + final int gox = getGeoX(ox); + final int goy = getGeoY(oy); + if (!hasGeoPos(gox, goy)) + { + return true; + } + + final short goz = getHeightNearest(gox, goy, oz); + + // get target and check existing geo coordinates + final int gtx = getGeoX(tx); + final int gty = getGeoY(ty); + if (!hasGeoPos(gtx, gty)) + { + return true; + } + + final short gtz = getHeightNearest(gtx, gty, tz); + + // origin and target coordinates are same + if ((gox == gtx) && (goy == gty)) + { + return goz == gtz; + } + + // get origin and target height, real height = collision height * 2 + double oheight = 0; + if (origin instanceof L2Character) + { + oheight = ((L2Character) origin).getTemplate().getCollisionHeight(); + } + + // perform geodata check + return checkSee(gox, goy, goz, oheight, gtx, gty, gtz, 0); + } + + /** + * Simple check for origin to target visibility. + * @param gox : origin X geodata coordinate + * @param goy : origin Y geodata coordinate + * @param goz : origin Z geodata coordinate + * @param oheight : origin height (if instance of {@link Character}) + * @param gtx : target X geodata coordinate + * @param gty : target Y geodata coordinate + * @param gtz : target Z geodata coordinate + * @param theight : target height (if instance of {@link Character}) + * @return {@code boolean} : True, when target can be seen. + */ + protected final boolean checkSee(int gox, int goy, int goz, double oheight, int gtx, int gty, int gtz, double theight) + { + // get line of sight Z coordinates + double losoz = goz + ((oheight * Config.PART_OF_CHARACTER_HEIGHT) / 100); + double lostz = gtz + ((theight * Config.PART_OF_CHARACTER_HEIGHT) / 100); + + // get X delta and signum + final int dx = Math.abs(gtx - gox); + final int sx = gox < gtx ? 1 : -1; + final byte dirox = sx > 0 ? GeoStructure.CELL_FLAG_E : GeoStructure.CELL_FLAG_W; + final byte dirtx = sx > 0 ? GeoStructure.CELL_FLAG_W : GeoStructure.CELL_FLAG_E; + + // get Y delta and signum + final int dy = Math.abs(gty - goy); + final int sy = goy < gty ? 1 : -1; + final byte diroy = sy > 0 ? GeoStructure.CELL_FLAG_S : GeoStructure.CELL_FLAG_N; + final byte dirty = sy > 0 ? GeoStructure.CELL_FLAG_N : GeoStructure.CELL_FLAG_S; + + // get Z delta + final int dm = Math.max(dx, dy); + final double dz = (lostz - losoz) / dm; + + // get direction flag for diagonal movement + final byte diroxy = getDirXY(dirox, diroy); + final byte dirtxy = getDirXY(dirtx, dirty); + + // delta, determines axis to move on (+..X axis, -..Y axis) + int d = dx - dy; + + // NSWE direction of movement + byte diro; + byte dirt; + + // clearDebugItems(); + // dropDebugItem(728, 0, new GeoLocation(gox, goy, goz)); // blue potion + // dropDebugItem(728, 0, new GeoLocation(gtx, gty, gtz)); // blue potion + + // initialize node values + int nox = gox; + int noy = goy; + int ntx = gtx; + int nty = gty; + byte nsweo = getNsweNearest(gox, goy, goz); + byte nswet = getNsweNearest(gtx, gty, gtz); + + // loop + ABlock block; + int index; + for (int i = 0; i < ((dm + 1) / 2); i++) + { + // dropDebugItem(57, 0, new GeoLocation(gox, goy, goz)); // antidote + // dropDebugItem(1831, 0, new GeoLocation(gtx, gty, gtz)); // adena + + // reset direction flag + diro = 0; + dirt = 0; + + // calculate next point coordinates + int e2 = 2 * d; + if ((e2 > -dy) && (e2 < dx)) + { + // calculate next point XY coordinates + d -= dy; + d += dx; + nox += sx; + ntx -= sx; + noy += sy; + nty -= sy; + diro |= diroxy; + dirt |= dirtxy; + } + else if (e2 > -dy) + { + // calculate next point X coordinate + d -= dy; + nox += sx; + ntx -= sx; + diro |= dirox; + dirt |= dirtx; + } + else if (e2 < dx) + { + // calculate next point Y coordinate + d += dx; + noy += sy; + nty -= sy; + diro |= diroy; + dirt |= dirty; + } + + { + // get block of the next cell + block = getBlock(nox, noy); + + // get index of particular layer, based on movement conditions + if ((nsweo & diro) == 0) + { + index = block.getIndexAbove(nox, noy, goz - GeoStructure.CELL_IGNORE_HEIGHT); + } + else + { + index = block.getIndexBelow(nox, noy, goz + GeoStructure.CELL_IGNORE_HEIGHT); + } + + // layer does not exist, return + if (index == -1) + { + return false; + } + + // get layer and next line of sight Z coordinate + goz = block.getHeight(index); + losoz += dz; + + // perform line of sight check, return when fails + if ((goz - losoz) > Config.MAX_OBSTACLE_HEIGHT) + { + return false; + } + + // get layer nswe + nsweo = block.getNswe(index); + } + { + // get block of the next cell + block = getBlock(ntx, nty); + + // get index of particular layer, based on movement conditions + if ((nswet & dirt) == 0) + { + index = block.getIndexAbove(ntx, nty, gtz - GeoStructure.CELL_IGNORE_HEIGHT); + } + else + { + index = block.getIndexBelow(ntx, nty, gtz + GeoStructure.CELL_IGNORE_HEIGHT); + } + + // layer does not exist, return + if (index == -1) + { + return false; + } + + // get layer and next line of sight Z coordinate + gtz = block.getHeight(index); + lostz -= dz; + + // perform line of sight check, return when fails + if ((gtz - lostz) > Config.MAX_OBSTACLE_HEIGHT) + { + return false; + } + + // get layer nswe + nswet = block.getNswe(index); + } + + // update coords + gox = nox; + goy = noy; + gtx = ntx; + gty = nty; + } + + // when iteration is completed, compare final Z coordinates + return Math.abs(goz - gtz) < (GeoStructure.CELL_HEIGHT * 4); + } + + /** + * Simple check for origin to target visibility.
+ * Geodata without {@link IGeoObject} are taken in consideration.
+ * NOTE: When two doors close between each other and the LoS check of one doors is performed through another door, result will not be accurate (the other door are skipped). + * @param gox : origin X geodata coordinate + * @param goy : origin Y geodata coordinate + * @param goz : origin Z geodata coordinate + * @param oheight : origin height (if instance of {@link Character}) + * @param gtx : target X geodata coordinate + * @param gty : target Y geodata coordinate + * @param gtz : target Z geodata coordinate + * @param theight : target height (if instance of {@link Character} or {@link L2DoorInstance}) + * @return {@code boolean} : True, when target can be seen. + */ + protected final boolean checkSeeOriginal(int gox, int goy, int goz, double oheight, int gtx, int gty, int gtz, double theight) + { + // get line of sight Z coordinates + double losoz = goz + ((oheight * Config.PART_OF_CHARACTER_HEIGHT) / 100); + double lostz = gtz + ((theight * Config.PART_OF_CHARACTER_HEIGHT) / 100); + + // get X delta and signum + final int dx = Math.abs(gtx - gox); + final int sx = gox < gtx ? 1 : -1; + final byte dirox = sx > 0 ? GeoStructure.CELL_FLAG_E : GeoStructure.CELL_FLAG_W; + final byte dirtx = sx > 0 ? GeoStructure.CELL_FLAG_W : GeoStructure.CELL_FLAG_E; + + // get Y delta and signum + final int dy = Math.abs(gty - goy); + final int sy = goy < gty ? 1 : -1; + final byte diroy = sy > 0 ? GeoStructure.CELL_FLAG_S : GeoStructure.CELL_FLAG_N; + final byte dirty = sy > 0 ? GeoStructure.CELL_FLAG_N : GeoStructure.CELL_FLAG_S; + + // get Z delta + final int dm = Math.max(dx, dy); + final double dz = (lostz - losoz) / dm; + + // get direction flag for diagonal movement + final byte diroxy = getDirXY(dirox, diroy); + final byte dirtxy = getDirXY(dirtx, dirty); + + // delta, determines axis to move on (+..X axis, -..Y axis) + int d = dx - dy; + + // NSWE direction of movement + byte diro; + byte dirt; + + // clearDebugItems(); + // dropDebugItem(728, 0, new GeoLocation(gox, goy, goz)); // blue potion + // dropDebugItem(728, 0, new GeoLocation(gtx, gty, gtz)); // blue potion + + // initialize node values + int nox = gox; + int noy = goy; + int ntx = gtx; + int nty = gty; + byte nsweo = getNsweNearestOriginal(gox, goy, goz); + byte nswet = getNsweNearestOriginal(gtx, gty, gtz); + + // loop + ABlock block; + int index; + for (int i = 0; i < ((dm + 1) / 2); i++) + { + // dropDebugItem(57, 0, new GeoLocation(gox, goy, goz)); // antidote + // dropDebugItem(1831, 0, new GeoLocation(gtx, gty, gtz)); // adena + + // reset direction flag + diro = 0; + dirt = 0; + + // calculate next point coordinates + int e2 = 2 * d; + if ((e2 > -dy) && (e2 < dx)) + { + // calculate next point XY coordinates + d -= dy; + d += dx; + nox += sx; + ntx -= sx; + noy += sy; + nty -= sy; + diro |= diroxy; + dirt |= dirtxy; + } + else if (e2 > -dy) + { + // calculate next point X coordinate + d -= dy; + nox += sx; + ntx -= sx; + diro |= dirox; + dirt |= dirtx; + } + else if (e2 < dx) + { + // calculate next point Y coordinate + d += dx; + noy += sy; + nty -= sy; + diro |= diroy; + dirt |= dirty; + } + + { + // get block of the next cell + block = getBlock(nox, noy); + + // get index of particular layer, based on movement conditions + if ((nsweo & diro) == 0) + { + index = block.getIndexAboveOriginal(nox, noy, goz - GeoStructure.CELL_IGNORE_HEIGHT); + } + else + { + index = block.getIndexBelowOriginal(nox, noy, goz + GeoStructure.CELL_IGNORE_HEIGHT); + } + + // layer does not exist, return + if (index == -1) + { + return false; + } + + // get layer and next line of sight Z coordinate + goz = block.getHeightOriginal(index); + losoz += dz; + + // perform line of sight check, return when fails + if ((goz - losoz) > Config.MAX_OBSTACLE_HEIGHT) + { + return false; + } + + // get layer nswe + nsweo = block.getNsweOriginal(index); + } + { + // get block of the next cell + block = getBlock(ntx, nty); + + // get index of particular layer, based on movement conditions + if ((nswet & dirt) == 0) + { + index = block.getIndexAboveOriginal(ntx, nty, gtz - GeoStructure.CELL_IGNORE_HEIGHT); + } + else + { + index = block.getIndexBelowOriginal(ntx, nty, gtz + GeoStructure.CELL_IGNORE_HEIGHT); + } + + // layer does not exist, return + if (index == -1) + { + return false; + } + + // get layer and next line of sight Z coordinate + gtz = block.getHeightOriginal(index); + lostz -= dz; + + // perform line of sight check, return when fails + if ((gtz - lostz) > Config.MAX_OBSTACLE_HEIGHT) + { + return false; + } + + // get layer nswe + nswet = block.getNsweOriginal(index); + } + + // update coords + gox = nox; + goy = noy; + gtx = ntx; + gty = nty; + } + + // when iteration is completed, compare final Z coordinates + return Math.abs(goz - gtz) < (GeoStructure.CELL_HEIGHT * 4); + } + + /** + * Check movement from coordinates to coordinates. + * @param ox : origin X coordinate + * @param oy : origin Y coordinate + * @param oz : origin Z coordinate + * @param tx : target X coordinate + * @param ty : target Y coordinate + * @param tz : target Z coordinate + * @param instance + * @return {code boolean} : True if target coordinates are reachable from origin coordinates + */ + public final boolean canMoveToTarget(int ox, int oy, int oz, int tx, int ty, int tz, Instance instance) + { + if (DoorData.getInstance().checkIfDoorsBetween(ox, oy, oz, tx, ty, tz, instance, false)) + { + return false; + } + + if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(ox, oy, oz), new Location(tx, ty, tz), instance)) + { + return false; + } + + // get origin and check existing geo coordinates + final int gox = getGeoX(ox); + final int goy = getGeoY(oy); + if (!hasGeoPos(gox, goy)) + { + return true; + } + + final short goz = getHeightNearest(gox, goy, oz); + + // get target and check existing geo coordinates + final int gtx = getGeoX(tx); + final int gty = getGeoY(ty); + if (!hasGeoPos(gtx, gty)) + { + return true; + } + + final short gtz = getHeightNearest(gtx, gty, tz); + + // target coordinates reached + if ((gox == gtx) && (goy == gty) && (goz == gtz)) + { + return true; + } + + // perform geodata check + GeoLocation loc = checkMove(gox, goy, goz, gtx, gty, gtz, instance); + return (loc.getGeoX() == gtx) && (loc.getGeoY() == gty); + } + + /** + * Check movement from origin to target. Returns last available point in the checked path. + * @param ox : origin X coordinate + * @param oy : origin Y coordinate + * @param oz : origin Z coordinate + * @param tx : target X coordinate + * @param ty : target Y coordinate + * @param tz : target Z coordinate + * @param instance + * @return {@link Location} : Last point where object can walk (just before wall) + */ + public final Location canMoveToTargetLoc(int ox, int oy, int oz, int tx, int ty, int tz, Instance instance) + { + if (DoorData.getInstance().checkIfDoorsBetween(ox, oy, oz, tx, ty, tz, instance, false)) + { + return new Location(ox, oy, getHeight(ox, oy, oz)); + } + + if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(ox, oy, oz), new Location(tx, ty, tz), instance)) + { + return new Location(ox, oy, getHeight(ox, oy, oz)); + } + + // get origin and check existing geo coordinates + final int gox = getGeoX(ox); + final int goy = getGeoY(oy); + if (!hasGeoPos(gox, goy)) + { + return new Location(tx, ty, tz); + } + + final short goz = getHeightNearest(gox, goy, oz); + + // get target and check existing geo coordinates + final int gtx = getGeoX(tx); + final int gty = getGeoY(ty); + if (!hasGeoPos(gtx, gty)) + { + return new Location(tx, ty, tz); + } + + final short gtz = getHeightNearest(gtx, gty, tz); + + // target coordinates reached + if ((gox == gtx) && (goy == gty) && (goz == gtz)) + { + return new Location(tx, ty, tz); + } + + // perform geodata check + return checkMove(gox, goy, goz, gtx, gty, gtz, instance); + } + + /** + * With this method you can check if a position is visible or can be reached by beeline movement.
+ * Target X and Y reachable and Z is on same floor: + *
    + *
  • Location of the target with corrected Z value from geodata.
  • + *
+ * Target X and Y reachable but Z is on another floor: + *
    + *
  • Location of the origin with corrected Z value from geodata.
  • + *
+ * Target X and Y not reachable: + *
    + *
  • Last accessible location in destination to target.
  • + *
+ * @param gox : origin X geodata coordinate + * @param goy : origin Y geodata coordinate + * @param goz : origin Z geodata coordinate + * @param gtx : target X geodata coordinate + * @param gty : target Y geodata coordinate + * @param gtz : target Z geodata coordinate + * @param instance + * @return {@link GeoLocation} : The last allowed point of movement. + */ + protected final GeoLocation checkMove(int gox, int goy, int goz, int gtx, int gty, int gtz, Instance instance) + { + if (DoorData.getInstance().checkIfDoorsBetween(gox, goy, goz, gtx, gty, gtz, instance, false)) + { + return new GeoLocation(gox, goy, goz); + } + + if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(gox, goy, goz), new Location(gtx, gty, gtz), instance)) + { + return new GeoLocation(gox, goy, goz); + } + + // get X delta, signum and direction flag + final int dx = Math.abs(gtx - gox); + final int sx = gox < gtx ? 1 : -1; + final byte dirX = sx > 0 ? GeoStructure.CELL_FLAG_E : GeoStructure.CELL_FLAG_W; + + // get Y delta, signum and direction flag + final int dy = Math.abs(gty - goy); + final int sy = goy < gty ? 1 : -1; + final byte dirY = sy > 0 ? GeoStructure.CELL_FLAG_S : GeoStructure.CELL_FLAG_N; + + // get direction flag for diagonal movement + final byte dirXY = getDirXY(dirX, dirY); + + // delta, determines axis to move on (+..X axis, -..Y axis) + int d = dx - dy; + + // NSWE direction of movement + byte direction; + + // load pointer coordinates + int gpx = gox; + int gpy = goy; + int gpz = goz; + + // load next pointer + int nx = gpx; + int ny = gpy; + + // loop + do + { + direction = 0; + + // calculate next point coordinates + int e2 = 2 * d; + if ((e2 > -dy) && (e2 < dx)) + { + d -= dy; + d += dx; + nx += sx; + ny += sy; + direction |= dirXY; + } + else if (e2 > -dy) + { + d -= dy; + nx += sx; + direction |= dirX; + } + else if (e2 < dx) + { + d += dx; + ny += sy; + direction |= dirY; + } + + // obstacle found, return + if ((getNsweNearest(gpx, gpy, gpz) & direction) == 0) + { + return new GeoLocation(gpx, gpy, gpz); + } + + // update pointer coordinates + gpx = nx; + gpy = ny; + gpz = getHeightNearest(nx, ny, gpz); + + // target coordinates reached + if ((gpx == gtx) && (gpy == gty)) + { + if (gpz == gtz) + { + // path found, Z coordinates are okay, return target point + return new GeoLocation(gtx, gty, gtz); + } + + // path found, Z coordinates are not okay, return origin point + return new GeoLocation(gox, goy, goz); + } + } + while (true); + } + + /** + * Returns diagonal NSWE flag format of combined two NSWE flags. + * @param dirX : X direction NSWE flag + * @param dirY : Y direction NSWE flag + * @return byte : NSWE flag of combined direction + */ + private static final byte getDirXY(byte dirX, byte dirY) + { + // check axis directions + if (dirY == GeoStructure.CELL_FLAG_N) + { + if (dirX == GeoStructure.CELL_FLAG_W) + { + return GeoStructure.CELL_FLAG_NW; + } + + return GeoStructure.CELL_FLAG_NE; + } + + if (dirX == GeoStructure.CELL_FLAG_W) + { + return GeoStructure.CELL_FLAG_SW; + } + + return GeoStructure.CELL_FLAG_SE; + } + + /** + * Returns the list of location objects as a result of complete path calculation. + * @param ox : origin x + * @param oy : origin y + * @param oz : origin z + * @param tx : target x + * @param ty : target y + * @param tz : target z + * @param instance + * @param playable : moving object is playable? + * @return {@code List} : complete path from nodes + */ + public List findPath(int ox, int oy, int oz, int tx, int ty, int tz, Instance instance, boolean playable) + { + return null; + } + + private static class SingletonHolder + { + protected static final GeoEngine _instance = Config.PATHFINDING ? new GeoEnginePathfinding() : new GeoEngine(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/GeoEnginePathfinding.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/GeoEnginePathfinding.java new file mode 100644 index 0000000000..b9def83228 --- /dev/null +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/GeoEnginePathfinding.java @@ -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 . + */ +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 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 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 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 : list of node location + */ + private static final List constructPath(Node target) + { + // create empty list + LinkedList 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 _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(); + } + } +} \ No newline at end of file diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/ABlock.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/ABlock.java new file mode 100644 index 0000000000..7fca5a9f52 --- /dev/null +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/ABlock.java @@ -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 . + */ +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.
+ * 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.
+ * 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.
+ * 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.
+ * 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.
+ * 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.
+ * 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; +} \ No newline at end of file diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplex.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplex.java new file mode 100644 index 0000000000..de0a7b8524 --- /dev/null +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplex.java @@ -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 . + */ +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); + } +} \ No newline at end of file diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplexDynamic.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplexDynamic.java new file mode 100644 index 0000000000..9f49e41899 --- /dev/null +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplexDynamic.java @@ -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 . + */ +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 _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; + } + } + } + } + } +} \ No newline at end of file diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/BlockFlat.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/BlockFlat.java new file mode 100644 index 0000000000..e1d82814eb --- /dev/null +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/BlockFlat.java @@ -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 . + */ +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)); + } +} \ No newline at end of file diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayer.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayer.java new file mode 100644 index 0000000000..56d4de75e1 --- /dev/null +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayer.java @@ -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 . + */ +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; + } + } +} \ No newline at end of file diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayerDynamic.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayerDynamic.java new file mode 100644 index 0000000000..2361135de5 --- /dev/null +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayerDynamic.java @@ -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 . + */ +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 _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; + } + } + } + } + } +} \ No newline at end of file diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/BlockNull.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/BlockNull.java new file mode 100644 index 0000000000..225bdef947 --- /dev/null +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/BlockNull.java @@ -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 . + */ +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) + { + } +} \ No newline at end of file diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNodeLoc.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/GeoFormat.java similarity index 67% rename from L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNodeLoc.java rename to L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/GeoFormat.java index 197cb70df9..57885fc734 100644 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNodeLoc.java +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/GeoFormat.java @@ -14,22 +14,26 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -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 void setZ(short z); - - public abstract int getNodeX(); - - public abstract int getNodeY(); -} + public String getFilename() + { + return _filename; + } +} \ No newline at end of file diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/GeoLocation.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/GeoLocation.java new file mode 100644 index 0000000000..850fcdbfcd --- /dev/null +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/GeoLocation.java @@ -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 . + */ +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; + } +} \ No newline at end of file diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/GeoStructure.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/GeoStructure.java new file mode 100644 index 0000000000..e1925e6e57 --- /dev/null +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/GeoStructure.java @@ -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 . + */ +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; +} \ No newline at end of file diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/IBlockDynamic.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/IBlockDynamic.java new file mode 100644 index 0000000000..e241e73b1c --- /dev/null +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/IBlockDynamic.java @@ -0,0 +1,35 @@ +/* + * 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 . + */ +package com.l2jmobius.gameserver.geoengine.geodata; + +/** + * @author Hasha + */ +public interface IBlockDynamic +{ + /** + * 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); + + /** + * 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); +} \ No newline at end of file diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/IGeoObject.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/IGeoObject.java new file mode 100644 index 0000000000..2726378e3a --- /dev/null +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/geodata/IGeoObject.java @@ -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 . + */ +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(); +} diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/pathfinding/Node.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/pathfinding/Node.java new file mode 100644 index 0000000000..27430a65cd --- /dev/null +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/pathfinding/Node.java @@ -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 . + */ +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; + } +} \ No newline at end of file diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/pathfinding/NodeBuffer.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/pathfinding/NodeBuffer.java new file mode 100644 index 0000000000..300fe31190 --- /dev/null +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/geoengine/pathfinding/NodeBuffer.java @@ -0,0 +1,351 @@ +/* + * 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 . + */ +package com.l2jmobius.gameserver.geoengine.pathfinding; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.locks.ReentrantLock; + +import com.l2jmobius.Config; +import com.l2jmobius.gameserver.geoengine.geodata.GeoStructure; + +/** + * @author DS, Hasha; Credits to Diamond + */ +public class NodeBuffer +{ + private final ReentrantLock _lock = new ReentrantLock(); + private final int _size; + private final Node[][] _buffer; + + // center coordinates + private int _cx = 0; + private int _cy = 0; + + // target coordinates + private int _gtx = 0; + private int _gty = 0; + private short _gtz = 0; + + // pathfinding statistics + private long _timeStamp = 0; + private long _lastElapsedTime = 0; + + private Node _current = null; + + /** + * Constructor of NodeBuffer. + * @param size : one dimension size of buffer + */ + public NodeBuffer(int size) + { + // set size + _size = size; + + // initialize buffer + _buffer = new Node[size][size]; + for (int x = 0; x < size; x++) + { + for (int y = 0; y < size; y++) + { + _buffer[x][y] = new Node(); + } + } + } + + /** + * Find path consisting of Nodes. Starts at origin coordinates, ends in target coordinates. + * @param gox : origin point x + * @param goy : origin point y + * @param goz : origin point z + * @param gtx : target point x + * @param gty : target point y + * @param gtz : target point z + * @return Node : first node of path + */ + public final Node findPath(int gox, int goy, short goz, int gtx, int gty, short gtz) + { + // load timestamp + _timeStamp = System.currentTimeMillis(); + + // set coordinates (middle of the line (gox,goy) - (gtx,gty), will be in the center of the buffer) + _cx = gox + ((gtx - gox - _size) / 2); + _cy = goy + ((gty - goy - _size) / 2); + + _gtx = gtx; + _gty = gty; + _gtz = gtz; + + _current = getNode(gox, goy, goz); + _current.setCost(getCostH(gox, goy, goz)); + + int count = 0; + do + { + // reached target? + if ((_current.getLoc().getGeoX() == _gtx) && (_current.getLoc().getGeoY() == _gty) && (Math.abs(_current.getLoc().getZ() - _gtz) < 8)) + { + return _current; + } + + // expand current node + expand(); + + // move pointer + _current = _current.getChild(); + } + while ((_current != null) && (++count < Config.MAX_ITERATIONS)); + + return null; + } + + /** + * Creates list of Nodes to show debug path. + * @return List : nodes + */ + public final List debugPath() + { + List result = new ArrayList<>(); + + for (Node n = _current; n.getParent() != null; n = n.getParent()) + { + result.add(n); + n.setCost(-n.getCost()); + } + + for (Node[] nodes : _buffer) + { + for (Node node : nodes) + { + if ((node.getLoc() == null) || (node.getCost() <= 0)) + { + continue; + } + + result.add(node); + } + } + + return result; + } + + public final boolean isLocked() + { + return _lock.tryLock(); + } + + public final void free() + { + _current = null; + + for (Node[] nodes : _buffer) + { + for (Node node : nodes) + { + if (node.getLoc() != null) + { + node.free(); + } + } + } + + _lock.unlock(); + _lastElapsedTime = System.currentTimeMillis() - _timeStamp; + } + + public final long getElapsedTime() + { + return _lastElapsedTime; + } + + /** + * Check _current Node and add its neighbors to the buffer. + */ + private final void expand() + { + // can't move anywhere, don't expand + byte nswe = _current.getLoc().getNSWE(); + if (nswe == 0) + { + return; + } + + // get geo coords of the node to be expanded + final int x = _current.getLoc().getGeoX(); + final int y = _current.getLoc().getGeoY(); + final short z = (short) _current.getLoc().getZ(); + + // can move north, expand + if ((nswe & GeoStructure.CELL_FLAG_N) != 0) + { + addNode(x, y - 1, z, Config.BASE_WEIGHT); + } + + // can move south, expand + if ((nswe & GeoStructure.CELL_FLAG_S) != 0) + { + addNode(x, y + 1, z, Config.BASE_WEIGHT); + } + + // can move west, expand + if ((nswe & GeoStructure.CELL_FLAG_W) != 0) + { + addNode(x - 1, y, z, Config.BASE_WEIGHT); + } + + // can move east, expand + if ((nswe & GeoStructure.CELL_FLAG_E) != 0) + { + addNode(x + 1, y, z, Config.BASE_WEIGHT); + } + + // can move north-west, expand + if ((nswe & GeoStructure.CELL_FLAG_NW) != 0) + { + addNode(x - 1, y - 1, z, Config.DIAGONAL_WEIGHT); + } + + // can move north-east, expand + if ((nswe & GeoStructure.CELL_FLAG_NE) != 0) + { + addNode(x + 1, y - 1, z, Config.DIAGONAL_WEIGHT); + } + + // can move south-west, expand + if ((nswe & GeoStructure.CELL_FLAG_SW) != 0) + { + addNode(x - 1, y + 1, z, Config.DIAGONAL_WEIGHT); + } + + // can move south-east, expand + if ((nswe & GeoStructure.CELL_FLAG_SE) != 0) + { + addNode(x + 1, y + 1, z, Config.DIAGONAL_WEIGHT); + } + } + + /** + * Returns node, if it exists in buffer. + * @param x : node X coord + * @param y : node Y coord + * @param z : node Z coord + * @return Node : node, if exits in buffer + */ + private final Node getNode(int x, int y, short z) + { + // check node X out of coordinates + final int ix = x - _cx; + if ((ix < 0) || (ix >= _size)) + { + return null; + } + + // check node Y out of coordinates + final int iy = y - _cy; + if ((iy < 0) || (iy >= _size)) + { + return null; + } + + // get node + Node result = _buffer[ix][iy]; + + // check and update + if (result.getLoc() == null) + { + result.setLoc(x, y, z); + } + + // return node + return result; + } + + /** + * Add node given by coordinates to the buffer. + * @param x : geo X coord + * @param y : geo Y coord + * @param z : geo Z coord + * @param weight : weight of movement to new node + */ + private final void addNode(int x, int y, short z, int weight) + { + // get node to be expanded + Node node = getNode(x, y, z); + if (node == null) + { + return; + } + + // Z distance between nearby cells is higher than cell size + if (node.getLoc().getZ() > (z + (2 * GeoStructure.CELL_HEIGHT))) + { + return; + } + + // node was already expanded, return + if (node.getCost() >= 0) + { + return; + } + + node.setParent(_current); + if (node.getLoc().getNSWE() != (byte) 0xFF) + { + node.setCost(getCostH(x, y, node.getLoc().getZ()) + (weight * Config.OBSTACLE_MULTIPLIER)); + } + else + { + node.setCost(getCostH(x, y, node.getLoc().getZ()) + weight); + } + + Node current = _current; + int count = 0; + while ((current.getChild() != null) && (count < (Config.MAX_ITERATIONS * 4))) + { + count++; + if (current.getChild().getCost() > node.getCost()) + { + node.setChild(current.getChild()); + break; + } + current = current.getChild(); + } + + if (count >= (Config.MAX_ITERATIONS * 4)) + { + System.err.println("Pathfinding: too long loop detected, cost:" + node.getCost()); + } + + current.setChild(node); + } + + /** + * @param x : node X coord + * @param y : node Y coord + * @param i : node Z coord + * @return double : node cost + */ + private final double getCostH(int x, int y, int i) + { + final int dX = x - _gtx; + final int dY = y - _gty; + final int dZ = (i - _gtz) / GeoStructure.CELL_HEIGHT; + + // return (Math.abs(dX) + Math.abs(dY) + Math.abs(dZ)) * Config.HEURISTIC_WEIGHT; // Manhattan distance + return Math.sqrt((dX * dX) + (dY * dY) + (dZ * dZ)) * Config.HEURISTIC_WEIGHT; // Direct distance + } +} \ No newline at end of file diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/instancemanager/WarpedSpaceManager.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/instancemanager/WarpedSpaceManager.java index 4f61421f83..cde24700ba 100644 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/instancemanager/WarpedSpaceManager.java +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/instancemanager/WarpedSpaceManager.java @@ -18,7 +18,6 @@ package com.l2jmobius.gameserver.instancemanager; import java.util.concurrent.ConcurrentHashMap; -import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNodeLoc; import com.l2jmobius.gameserver.model.Location; import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.holders.WarpedSpaceHolder; @@ -52,11 +51,6 @@ public class WarpedSpaceManager _warpedSpace.remove(creature); } - public boolean checkForWarpedSpace(AbstractNodeLoc start, AbstractNodeLoc end, Instance instance) - { - return checkForWarpedSpace(new Location(start.getX(), start.getY(), start.getZ()), new Location(end.getX(), end.getY(), end.getZ()), instance); - } - public boolean checkForWarpedSpace(Location origin, Location destination, Instance instance) { if (_warpedSpace != null) diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/Fishing.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/Fishing.java index e9cfd27a75..d0b69fa3e9 100644 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/Fishing.java +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/Fishing.java @@ -25,7 +25,7 @@ import com.l2jmobius.commons.util.Rnd; import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.data.xml.impl.FishingData; import com.l2jmobius.gameserver.enums.ShotType; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.instancemanager.ZoneManager; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.events.EventDispatcher; @@ -420,19 +420,19 @@ public class Fishing // always use water zone, fishing zone high z is high in the air... final int baitZ = waterZone.getWaterZ(); - // if (!GeoData.getInstance().canSeeTarget(player.getX(), player.getY(), player.getZ(), baitX, baitY, baitZ)) + // if (!GeoEngine.getInstance().canSeeTarget(player.getX(), player.getY(), player.getZ(), baitX, baitY, baitZ)) // // return Integer.MIN_VALUE; // } - if (GeoData.getInstance().hasGeo(baitX, baitY)) + if (GeoEngine.getInstance().hasGeo(baitX, baitY)) { - if (GeoData.getInstance().getHeight(baitX, baitY, baitZ) > baitZ) + if (GeoEngine.getInstance().getHeight(baitX, baitY, baitZ) > baitZ) { return Integer.MIN_VALUE; } - if (GeoData.getInstance().getHeight(baitX, baitY, player.getZ()) > baitZ) + if (GeoEngine.getInstance().getHeight(baitX, baitY, player.getZ()) > baitZ) { return Integer.MIN_VALUE; } diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/L2Spawn.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/L2Spawn.java index 3ddb0761ac..e9978f7863 100644 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/L2Spawn.java +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/L2Spawn.java @@ -26,7 +26,7 @@ import java.util.logging.Logger; import com.l2jmobius.commons.util.Rnd; import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.data.xml.impl.NpcData; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2NpcInstance; import com.l2jmobius.gameserver.model.actor.templates.L2NpcTemplate; @@ -544,7 +544,7 @@ public class L2Spawn implements IPositionable, IIdentifiable, INamable // don't correct z of flying npc's if (!npc.isFlying()) { - newlocz = GeoData.getInstance().getSpawnHeight(newlocx, newlocy, newlocz); + newlocz = GeoEngine.getInstance().getHeight(newlocx, newlocy, newlocz); } // Set is not random walk default value diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/Location.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/Location.java index dd88541a50..4b5e290517 100644 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/Location.java +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/Location.java @@ -26,9 +26,9 @@ import com.l2jmobius.gameserver.model.interfaces.IPositionable; */ public class Location implements IPositionable { - private int _x; - private int _y; - private int _z; + protected int _x; + protected int _y; + protected int _z; private int _heading; public Location(int x, int y, int z) diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/actor/L2Character.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/actor/L2Character.java index 8ab8348d64..8d4e253ccc 100644 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/actor/L2Character.java +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/actor/L2Character.java @@ -63,9 +63,7 @@ import com.l2jmobius.gameserver.enums.ShotType; import com.l2jmobius.gameserver.enums.StatusUpdateType; import com.l2jmobius.gameserver.enums.Team; import com.l2jmobius.gameserver.enums.UserInfoType; -import com.l2jmobius.gameserver.geodata.GeoData; -import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNodeLoc; -import com.l2jmobius.gameserver.geodata.pathfinding.PathFinding; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.idfactory.IdFactory; import com.l2jmobius.gameserver.instancemanager.MapRegionManager; import com.l2jmobius.gameserver.instancemanager.TimersManager; @@ -1053,7 +1051,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe stopEffectsOnAction(); // GeoData Los Check here (or dz > 1000) - if (!GeoData.getInstance().canSeeTarget(this, target)) + if (!GeoEngine.getInstance().canSeeTarget(this, target)) { sendPacket(SystemMessageId.CANNOT_SEE_TARGET); getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE); @@ -2851,7 +2849,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe public boolean disregardingGeodata; public int onGeodataPathIndex; - public List geoPath; + public List geoPath; public int geoPathAccurateTx; public int geoPathAccurateTy; public int geoPathGtx; @@ -3269,9 +3267,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe // Z coordinate will follow geodata or client values if ((Config.COORD_SYNCHRONIZE == 2) && !isFloating && !m.disregardingGeodata && ((GameTimeController.getInstance().getGameTicks() % 10) == 0 // once a second to reduce possible cpu load - ) && GeoData.getInstance().hasGeo(xPrev, yPrev)) + ) && GeoEngine.getInstance().hasGeo(xPrev, yPrev)) { - final int geoHeight = GeoData.getInstance().getSpawnHeight(xPrev, yPrev, zPrev); + final int geoHeight = GeoEngine.getInstance().getHeight(xPrev, yPrev, zPrev); dz = m._zDestination - geoHeight; // quite a big difference, compare to validatePosition packet if (isPlayer() && (Math.abs(getActingPlayer().getClientZ() - geoHeight) > 200) && (Math.abs(getActingPlayer().getClientZ() - geoHeight) < 1500)) @@ -3554,9 +3552,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe { // Notify the AI that the L2Character is arrived at destination getAI().notifyEvent(CtrlEvent.EVT_ARRIVED); - return; } + // Calculate movement angles needed sin = dy / distance; cos = dx / distance; @@ -3581,7 +3579,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe m.onGeodataPathIndex = -1; // Initialize not on geodata path m.disregardingGeodata = false; - if (!isFlying() && !isInsideZone(ZoneId.WATER)) + if (!isFlying() && !isInsideZone(ZoneId.WATER) && !isWalker()) { final boolean isInVehicle = isPlayer() && (getActingPlayer().getVehicle() != null); if (isInVehicle) @@ -3596,16 +3594,11 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe final int gtx = (originalX - L2World.MAP_MIN_X) >> 4; final int gty = (originalY - L2World.MAP_MIN_Y) >> 4; - final Location destiny = GeoData.getInstance().moveCheck(curX, curY, curZ, x, y, z, getInstanceWorld()); - - // location different if destination wasn't reached (or just z coord is different) - x = destiny.getX(); - y = destiny.getY(); - z = destiny.getZ(); - // Movement checks: - // when PATHFINDING > 0, for all characters except mobs returning home (could be changed later to teleport if pathfinding fails) - if (Config.PATHFINDING > 0) + // when geodata == 2, for all characters except mobs returning home (could be changed later to teleport if pathfinding fails) + // when geodata == 1, for l2playableinstance + // assuming intention_follow only when following owner + if ((Config.PATHFINDING && !(isAttackable() && ((L2Attackable) this).isReturningToSpawnPoint())) || (isPlayer() && !(isInVehicle && (distance > 1500))) || (isSummon() && !(getAI().getIntention() == CtrlIntention.AI_INTENTION_FOLLOW))) { if (isOnGeodataPath()) { @@ -3634,7 +3627,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe } else if (isSummon()) { - return; // preventation when summon get out of world coords, player will not loose him, unsummon handled from pcinstance + return; // prevention when summon get out of world coords, player will not loose him, unsummon handled from pcinstance } else { @@ -3643,6 +3636,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe return; } // location different if destination wasn't reached (or just z coord is different) + Location destiny = GeoEngine.getInstance().canMoveToTargetLoc(curX, curY, curZ, x, y, z, getInstanceWorld()); x = destiny.getX(); y = destiny.getY(); z = destiny.getZ(); @@ -3651,85 +3645,86 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe dz = z - curZ; distance = verticalMovementOnly ? Math.pow(dz, 2) : Math.hypot(dx, dy); } - // Pathfinding checks. Only when geodata setting is 2, the LoS check gives shorter result - // than the original movement was and the LoS gives a shorter distance than 2000 + // Pathfinding checks. Only when geodata setting is 2, the LoS check gives shorter result than the original movement was and the LoS gives a shorter distance than 2000 // This way of detecting need for pathfinding could be changed. - if ((Config.PATHFINDING > 0) && ((originalDistance - distance) > 30) && !isControlBlocked() && !isInVehicle) + if (Config.PATHFINDING && ((originalDistance - distance) > 30) && (distance < 2000) && !isControlBlocked() && !isInVehicle) { - m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayable()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + // Path calculation -- overrides previous movement check + if (isPlayable() || isMinion() || isInCombat()) { - // * Even though there's no path found (remember geonodes aren't perfect), - // the mob is attacking and right now we set it so that the mob will go - // after target anyway, is dz is small enough. - // * With cellpathfinding this approach could be changed but would require taking - // off the geonodes and some more checks. - // * Summons will follow their masters no matter what. - // * Currently minions also must move freely since L2AttackableAI commands - // them to move along with their leader - if (isPlayer() || (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) || (isSummon() && !((L2Summon) this).getFollowStatus())) + m.geoPath = GeoEngine.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayable()); + if ((m.geoPath == null) || (m.geoPath.size() < 2)) { - getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); - return; + // No path found + // Even though there's no path found (remember geonodes aren't perfect), the mob is attacking and right now we set it so that the mob will go after target anyway, is dz is small enough. + // With cellpathfinding this approach could be changed but would require taking off the geonodes and some more checks. + // Summons will follow their masters no matter what. + // Currently minions also must move freely since L2AttackableAI commands them to move along with their leader + if (isPlayer() || (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) || (isSummon() && !((L2Summon) this).getFollowStatus())) + { + getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); + return; + } + + m.disregardingGeodata = true; + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; } - - m.disregardingGeodata = true; - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; - } - else - { - m.onGeodataPathIndex = 0; // on first segment - m.geoPathGtx = gtx; - m.geoPathGty = gty; - m.geoPathAccurateTx = originalX; - m.geoPathAccurateTy = originalY; - - x = m.geoPath.get(m.onGeodataPathIndex).getX(); - y = m.geoPath.get(m.onGeodataPathIndex).getY(); - z = m.geoPath.get(m.onGeodataPathIndex).getZ(); - - // check for doors in the route - if (DoorData.getInstance().checkIfDoorsBetween(curX, curY, curZ, x, y, z, getInstanceWorld())) + else { - m.geoPath = null; - getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); - return; - } - if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(curX, curY, curZ), new Location(x, y, z), getInstanceWorld())) - { - m.geoPath = null; - getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); - return; - } - for (int i = 0; i < (m.geoPath.size() - 1); i++) - { - if (DoorData.getInstance().checkIfDoorsBetween(m.geoPath.get(i), m.geoPath.get(i + 1), getInstanceWorld())) + m.onGeodataPathIndex = 0; // on first segment + m.geoPathGtx = gtx; + m.geoPathGty = gty; + m.geoPathAccurateTx = originalX; + m.geoPathAccurateTy = originalY; + + x = m.geoPath.get(m.onGeodataPathIndex).getX(); + y = m.geoPath.get(m.onGeodataPathIndex).getY(); + z = m.geoPath.get(m.onGeodataPathIndex).getZ(); + + // check for doors in the route + if (DoorData.getInstance().checkIfDoorsBetween(curX, curY, curZ, x, y, z, getInstanceWorld())) { m.geoPath = null; getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); return; } - if (WarpedSpaceManager.getInstance().checkForWarpedSpace(m.geoPath.get(i), m.geoPath.get(i + 1), getInstanceWorld())) + if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(curX, curY, curZ), new Location(x, y, z), getInstanceWorld())) { m.geoPath = null; getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); return; } + for (int i = 0; i < (m.geoPath.size() - 1); i++) + { + if (DoorData.getInstance().checkIfDoorsBetween(m.geoPath.get(i), m.geoPath.get(i + 1), getInstanceWorld())) + { + m.geoPath = null; + getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); + return; + } + if (WarpedSpaceManager.getInstance().checkForWarpedSpace(m.geoPath.get(i), m.geoPath.get(i + 1), getInstanceWorld())) + { + m.geoPath = null; + getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); + return; + } + } + + dx = x - curX; + dy = y - curY; + dz = z - curZ; + distance = verticalMovementOnly ? Math.pow(dz, 2) : Math.hypot(dx, dy); + sin = dy / distance; + cos = dx / distance; } - - dx = x - curX; - dy = y - curY; - dz = z - curZ; - distance = verticalMovementOnly ? Math.pow(dz, 2) : Math.hypot(dx, dy); - sin = dy / distance; - cos = dx / distance; } } + // If no distance to go through, the movement is canceled - if ((distance < 1) && ((Config.PATHFINDING > 0) || isPlayable())) + if ((distance < 1) && (Config.PATHFINDING || isPlayable() || isControlBlocked())) { if (isSummon()) { @@ -3751,7 +3746,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe final int ticksToMove = 1 + (int) ((GameTimeController.TICKS_PER_SECOND * distance) / speed); m._xDestination = x; m._yDestination = y; - m._zDestination = z; // this is what was requested from client + m._zDestination = z; // Calculate and set the heading of the L2Character m._heading = 0; // initial value for coordinate sync @@ -4240,7 +4235,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe return; } // GeoData Los Check or dz > 1000 - if (!GeoData.getInstance().canSeeTarget(player, this)) + if (!GeoEngine.getInstance().canSeeTarget(player, this)) { player.sendPacket(SystemMessageId.CANNOT_SEE_TARGET); player.sendPacket(ActionFailed.STATIC_PACKET); diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/actor/L2Tower.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/actor/L2Tower.java index ac1d703e27..8390083019 100644 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/actor/L2Tower.java +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/actor/L2Tower.java @@ -17,7 +17,7 @@ package com.l2jmobius.gameserver.model.actor; import com.l2jmobius.gameserver.ai.CtrlIntention; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.actor.templates.L2NpcTemplate; import com.l2jmobius.gameserver.network.serverpackets.ActionFailed; @@ -63,7 +63,7 @@ public abstract class L2Tower extends L2Npc } else if (interact) { - if (isAutoAttackable(player) && (Math.abs(player.getZ() - getZ()) < 100) && GeoData.getInstance().canSeeTarget(player, this)) + if (isAutoAttackable(player) && (Math.abs(player.getZ() - getZ()) < 100) && GeoEngine.getInstance().canSeeTarget(player, this)) { // Notify the L2PcInstance AI with AI_INTENTION_INTERACT player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this); diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java index 28803d4bb9..fccf6a4983 100644 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java @@ -97,7 +97,7 @@ import com.l2jmobius.gameserver.enums.StatusUpdateType; import com.l2jmobius.gameserver.enums.SubclassInfoType; import com.l2jmobius.gameserver.enums.Team; import com.l2jmobius.gameserver.enums.UserInfoType; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.handler.AdminCommandHandler; import com.l2jmobius.gameserver.handler.IAdminCommandHandler; import com.l2jmobius.gameserver.handler.IItemHandler; @@ -12476,7 +12476,7 @@ public final class L2PcInstance extends L2Playable } // If there is no geodata loaded for the place we are client Z correction might cause falling damage. - if (!GeoData.getInstance().hasGeo(getX(), getY())) + if (!GeoEngine.getInstance().hasGeo(getX(), getY())) { return false; } diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java index af1054767c..2337da2419 100644 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java @@ -49,7 +49,7 @@ import com.l2jmobius.gameserver.enums.ItemLocation; import com.l2jmobius.gameserver.enums.ItemSkillType; import com.l2jmobius.gameserver.enums.ShotType; import com.l2jmobius.gameserver.enums.UserInfoType; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.idfactory.IdFactory; import com.l2jmobius.gameserver.instancemanager.CastleManager; import com.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager; @@ -1512,7 +1512,7 @@ public final class L2ItemInstance extends L2Object if (_dropper != null) { final Instance instance = _dropper.getInstanceWorld(); - final Location dropDest = GeoData.getInstance().moveCheck(_dropper.getX(), _dropper.getY(), _dropper.getZ(), _x, _y, _z, instance); + final Location dropDest = GeoEngine.getInstance().canMoveToTargetLoc(_dropper.getX(), _dropper.getY(), _dropper.getZ(), _x, _y, _z, instance); _x = dropDest.getX(); _y = dropDest.getY(); _z = dropDest.getZ(); diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java index 9780892efe..9c70018363 100644 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java @@ -37,7 +37,7 @@ import com.l2jmobius.gameserver.datatables.ItemTable; import com.l2jmobius.gameserver.enums.ItemSkillType; import com.l2jmobius.gameserver.enums.NextActionType; import com.l2jmobius.gameserver.enums.StatusUpdateType; -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; @@ -1009,7 +1009,7 @@ public class SkillCaster implements Runnable } } - final Location destination = GeoData.getInstance().moveCheck(creature.getX(), creature.getY(), creature.getZ(), x, y, z, creature.getInstanceWorld()); + final Location destination = GeoEngine.getInstance().canMoveToTargetLoc(creature.getX(), creature.getY(), creature.getZ(), x, y, z, creature.getInstanceWorld()); creature.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); creature.broadcastPacket(new FlyToLocation(creature, destination, flyType, 0, 0, 333)); diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/skills/SkillChannelizer.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/skills/SkillChannelizer.java index 3875eb6830..cc1667a637 100644 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/skills/SkillChannelizer.java +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/skills/SkillChannelizer.java @@ -25,7 +25,7 @@ import java.util.logging.Logger; import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.data.xml.impl.SkillData; import com.l2jmobius.gameserver.enums.ShotType; -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.instance.L2PcInstance; @@ -185,7 +185,7 @@ public class SkillChannelizer implements Runnable { continue; } - else if (!GeoData.getInstance().canSeeTarget(_channelizer, character)) + else if (!GeoEngine.getInstance().canSeeTarget(_channelizer, character)) { continue; } diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/zone/form/ZoneCuboid.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/zone/form/ZoneCuboid.java index 58d967f84d..4433e97b28 100644 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/zone/form/ZoneCuboid.java +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/zone/form/ZoneCuboid.java @@ -19,7 +19,7 @@ package com.l2jmobius.gameserver.model.zone.form; import java.awt.Rectangle; import com.l2jmobius.commons.util.Rnd; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.model.Location; import com.l2jmobius.gameserver.model.itemcontainer.Inventory; import com.l2jmobius.gameserver.model.zone.L2ZoneForm; @@ -131,6 +131,6 @@ public class ZoneCuboid extends L2ZoneForm final int x = Rnd.get(_r.x, _r.x + _r.width); final int y = Rnd.get(_r.y, _r.y + _r.height); - return new Location(x, y, GeoData.getInstance().getHeight(x, y, _z1)); + return new Location(x, y, GeoEngine.getInstance().getHeight(x, y, _z1)); } } diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/zone/form/ZoneCylinder.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/zone/form/ZoneCylinder.java index 969dd7d029..afdfd3fade 100644 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/zone/form/ZoneCylinder.java +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/zone/form/ZoneCylinder.java @@ -17,7 +17,7 @@ package com.l2jmobius.gameserver.model.zone.form; import com.l2jmobius.commons.util.Rnd; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.model.Location; import com.l2jmobius.gameserver.model.itemcontainer.Inventory; import com.l2jmobius.gameserver.model.zone.L2ZoneForm; @@ -146,6 +146,6 @@ public class ZoneCylinder extends L2ZoneForm x = (int) ((_rad * r * Math.cos(q)) + _x); y = (int) ((_rad * r * Math.sin(q)) + _y); - return new Location(x, y, GeoData.getInstance().getHeight(x, y, _z1)); + return new Location(x, y, GeoEngine.getInstance().getHeight(x, y, _z1)); } } diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/zone/form/ZoneNPoly.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/zone/form/ZoneNPoly.java index 6da33d788e..2340c1b218 100644 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/zone/form/ZoneNPoly.java +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/model/zone/form/ZoneNPoly.java @@ -19,7 +19,7 @@ package com.l2jmobius.gameserver.model.zone.form; import java.awt.Polygon; import com.l2jmobius.commons.util.Rnd; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.model.Location; import com.l2jmobius.gameserver.model.itemcontainer.Inventory; import com.l2jmobius.gameserver.model.zone.L2ZoneForm; @@ -138,7 +138,7 @@ public class ZoneNPoly extends L2ZoneForm y = Rnd.get(_minY, _maxY); } - return new Location(x, y, GeoData.getInstance().getHeight(x, y, _z1)); + return new Location(x, y, GeoEngine.getInstance().getHeight(x, y, _z1)); } public int[] getX() diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/util/GeoUtils.java b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/util/GeoUtils.java index 21540f2215..dba01759ef 100644 --- a/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/util/GeoUtils.java +++ b/L2J_Mobius_Helios/java/com/l2jmobius/gameserver/util/GeoUtils.java @@ -18,8 +18,8 @@ package com.l2jmobius.gameserver.util; import java.awt.Color; -import com.l2jmobius.gameserver.geodata.GeoData; -import com.l2jmobius.gameserver.geodata.geodriver.Cell; +import com.l2jmobius.gameserver.geoengine.GeoEngine; +import com.l2jmobius.gameserver.geoengine.geodata.GeoStructure; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.network.serverpackets.ExServerPrimitive; @@ -30,21 +30,21 @@ public final class GeoUtils { public static void debug2DLine(L2PcInstance player, int x, int y, int tx, int ty, int z) { - final int gx = GeoData.getInstance().getGeoX(x); - final int gy = GeoData.getInstance().getGeoY(y); + final int gx = GeoEngine.getInstance().getGeoX(x); + final int gy = GeoEngine.getInstance().getGeoY(y); - final int tgx = GeoData.getInstance().getGeoX(tx); - final int tgy = GeoData.getInstance().getGeoY(ty); + final int tgx = GeoEngine.getInstance().getGeoX(tx); + final int tgy = GeoEngine.getInstance().getGeoY(ty); final ExServerPrimitive prim = new ExServerPrimitive("Debug2DLine", x, y, z); - prim.addLine(Color.BLUE, GeoData.getInstance().getWorldX(gx), GeoData.getInstance().getWorldY(gy), z, GeoData.getInstance().getWorldX(tgx), GeoData.getInstance().getWorldY(tgy), z); + prim.addLine(Color.BLUE, GeoEngine.getInstance().getWorldX(gx), GeoEngine.getInstance().getWorldY(gy), z, GeoEngine.getInstance().getWorldX(tgx), GeoEngine.getInstance().getWorldY(tgy), z); final LinePointIterator iter = new LinePointIterator(gx, gy, tgx, tgy); while (iter.next()) { - final int wx = GeoData.getInstance().getWorldX(iter.x()); - final int wy = GeoData.getInstance().getWorldY(iter.y()); + final int wx = GeoEngine.getInstance().getWorldX(iter.x()); + final int wy = GeoEngine.getInstance().getWorldY(iter.y()); prim.addPoint(Color.RED, wx, wy, z); } @@ -53,21 +53,21 @@ public final class GeoUtils public static void debug3DLine(L2PcInstance player, int x, int y, int z, int tx, int ty, int tz) { - final int gx = GeoData.getInstance().getGeoX(x); - final int gy = GeoData.getInstance().getGeoY(y); + final int gx = GeoEngine.getInstance().getGeoX(x); + final int gy = GeoEngine.getInstance().getGeoY(y); - final int tgx = GeoData.getInstance().getGeoX(tx); - final int tgy = GeoData.getInstance().getGeoY(ty); + final int tgx = GeoEngine.getInstance().getGeoX(tx); + final int tgy = GeoEngine.getInstance().getGeoY(ty); final ExServerPrimitive prim = new ExServerPrimitive("Debug3DLine", x, y, z); - prim.addLine(Color.BLUE, GeoData.getInstance().getWorldX(gx), GeoData.getInstance().getWorldY(gy), z, GeoData.getInstance().getWorldX(tgx), GeoData.getInstance().getWorldY(tgy), tz); + prim.addLine(Color.BLUE, GeoEngine.getInstance().getWorldX(gx), GeoEngine.getInstance().getWorldY(gy), z, GeoEngine.getInstance().getWorldX(tgx), GeoEngine.getInstance().getWorldY(tgy), tz); final LinePointIterator3D iter = new LinePointIterator3D(gx, gy, z, tgx, tgy, tz); iter.next(); int prevX = iter.x(); int prevY = iter.y(); - int wx = GeoData.getInstance().getWorldX(prevX); - int wy = GeoData.getInstance().getWorldY(prevY); + int wx = GeoEngine.getInstance().getWorldX(prevX); + int wy = GeoEngine.getInstance().getWorldY(prevY); int wz = iter.z(); prim.addPoint(Color.RED, wx, wy, wz); @@ -78,8 +78,8 @@ public final class GeoUtils if ((curX != prevX) || (curY != prevY)) { - wx = GeoData.getInstance().getWorldX(curX); - wy = GeoData.getInstance().getWorldY(curY); + wx = GeoEngine.getInstance().getWorldX(curX); + wy = GeoEngine.getInstance().getWorldY(curY); wz = iter.z(); prim.addPoint(Color.RED, wx, wy, wz); @@ -93,7 +93,7 @@ public final class GeoUtils private static Color getDirectionColor(int x, int y, int z, int nswe) { - if (GeoData.getInstance().checkNearestNswe(x, y, z, nswe)) + if ((GeoEngine.getInstance().getNsweNearest(x, y, z) & nswe) == nswe) { return Color.GREEN; } @@ -109,7 +109,7 @@ public final class GeoUtils int iPacket = 0; ExServerPrimitive exsp = null; - final GeoData gd = GeoData.getInstance(); + final GeoEngine gd = GeoEngine.getInstance(); final int playerGx = gd.getGeoX(player.getX()); final int playerGy = gd.getGeoY(player.getY()); for (int dx = -geoRadius; dx <= geoRadius; ++dx) @@ -137,30 +137,30 @@ public final class GeoUtils final int x = gd.getWorldX(gx); final int y = gd.getWorldY(gy); - final int z = gd.getNearestZ(gx, gy, player.getZ()); + final int z = gd.getHeightNearest(gx, gy, player.getZ()); // north arrow - Color col = getDirectionColor(gx, gy, z, Cell.NSWE_NORTH); + Color col = getDirectionColor(gx, gy, z, GeoStructure.CELL_FLAG_N); exsp.addLine(col, x - 1, y - 7, z, x + 1, y - 7, z); exsp.addLine(col, x - 2, y - 6, z, x + 2, y - 6, z); exsp.addLine(col, x - 3, y - 5, z, x + 3, y - 5, z); exsp.addLine(col, x - 4, y - 4, z, x + 4, y - 4, z); // east arrow - col = getDirectionColor(gx, gy, z, Cell.NSWE_EAST); + col = getDirectionColor(gx, gy, z, GeoStructure.CELL_FLAG_E); exsp.addLine(col, x + 7, y - 1, z, x + 7, y + 1, z); exsp.addLine(col, x + 6, y - 2, z, x + 6, y + 2, z); exsp.addLine(col, x + 5, y - 3, z, x + 5, y + 3, z); exsp.addLine(col, x + 4, y - 4, z, x + 4, y + 4, z); // south arrow - col = getDirectionColor(gx, gy, z, Cell.NSWE_SOUTH); + col = getDirectionColor(gx, gy, z, GeoStructure.CELL_FLAG_S); exsp.addLine(col, x - 1, y + 7, z, x + 1, y + 7, z); exsp.addLine(col, x - 2, y + 6, z, x + 2, y + 6, z); exsp.addLine(col, x - 3, y + 5, z, x + 3, y + 5, z); exsp.addLine(col, x - 4, y + 4, z, x + 4, y + 4, z); - col = getDirectionColor(gx, gy, z, Cell.NSWE_WEST); + col = getDirectionColor(gx, gy, z, GeoStructure.CELL_FLAG_W); exsp.addLine(col, x - 7, y - 1, z, x - 7, y + 1, z); exsp.addLine(col, x - 6, y - 2, z, x - 6, y + 2, z); exsp.addLine(col, x - 5, y - 3, z, x - 5, y + 3, z); @@ -188,30 +188,30 @@ public final class GeoUtils { if (y > lastY) { - return Cell.NSWE_SOUTH_EAST; // Direction.SOUTH_EAST; + return GeoStructure.CELL_FLAG_SE; // Direction.SOUTH_EAST; } else if (y < lastY) { - return Cell.NSWE_NORTH_EAST; // Direction.NORTH_EAST; + return GeoStructure.CELL_FLAG_NE; // Direction.NORTH_EAST; } else { - return Cell.NSWE_EAST; // Direction.EAST; + return GeoStructure.CELL_FLAG_E; // Direction.EAST; } } else if (x < lastX) // west { if (y > lastY) { - return Cell.NSWE_SOUTH_WEST; // Direction.SOUTH_WEST; + return GeoStructure.CELL_FLAG_SW; // Direction.SOUTH_WEST; } else if (y < lastY) { - return Cell.NSWE_NORTH_WEST; // Direction.NORTH_WEST; + return GeoStructure.CELL_FLAG_NW; // Direction.NORTH_WEST; } else { - return Cell.NSWE_WEST; // Direction.WEST; + return GeoStructure.CELL_FLAG_W; // Direction.WEST; } } else @@ -219,11 +219,11 @@ public final class GeoUtils { if (y > lastY) { - return Cell.NSWE_SOUTH; // Direction.SOUTH; + return GeoStructure.CELL_FLAG_S; // Direction.SOUTH; } else if (y < lastY) { - return Cell.NSWE_NORTH; // Direction.NORTH; + return GeoStructure.CELL_FLAG_N; // Direction.NORTH; } else { diff --git a/L2J_Mobius_Helios/java/com/l2jmobius/tools/geodataconverter/GeoDataConverter.java b/L2J_Mobius_Helios/java/com/l2jmobius/tools/geodataconverter/GeoDataConverter.java new file mode 100644 index 0000000000..81621d8ee6 --- /dev/null +++ b/L2J_Mobius_Helios/java/com/l2jmobius/tools/geodataconverter/GeoDataConverter.java @@ -0,0 +1,375 @@ +/* + * 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 . + */ +package com.l2jmobius.tools.geodataconverter; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.RandomAccessFile; +import java.nio.ByteOrder; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.util.Scanner; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.PropertiesParser; +import com.l2jmobius.gameserver.geoengine.geodata.ABlock; +import com.l2jmobius.gameserver.geoengine.geodata.BlockComplex; +import com.l2jmobius.gameserver.geoengine.geodata.BlockFlat; +import com.l2jmobius.gameserver.geoengine.geodata.BlockMultilayer; +import com.l2jmobius.gameserver.geoengine.geodata.GeoFormat; +import com.l2jmobius.gameserver.geoengine.geodata.GeoStructure; +import com.l2jmobius.gameserver.model.L2World; + +/** + * @author Hasha + */ +public final class GeoDataConverter +{ + private static GeoFormat _format; + private static ABlock[][] _blocks; + + public static void main(String[] args) + { + // initialize config + loadGeoengineConfigs(); + + // get geodata format + String type = ""; + try (Scanner scn = new Scanner(System.in)) + { + while (!(type.equalsIgnoreCase("J") || type.equalsIgnoreCase("O") || type.equalsIgnoreCase("E"))) + { + System.out.println("GeoDataConverter: Select source geodata type:"); + System.out.println(" J: L2J (e.g. 23_22.l2j)"); + System.out.println(" O: L2OFF (e.g. 23_22_conv.dat)"); + System.out.println(" E: Exit"); + System.out.print("Choice: "); + type = scn.next(); + } + } + if (type.equalsIgnoreCase("E")) + { + System.exit(0); + } + + _format = type.equalsIgnoreCase("J") ? GeoFormat.L2J : GeoFormat.L2OFF; + + // start conversion + System.out.println("GeoDataConverter: Converting all " + _format.toString() + " files."); + + // initialize geodata container + _blocks = new ABlock[GeoStructure.REGION_BLOCKS_X][GeoStructure.REGION_BLOCKS_Y]; + + // initialize multilayer temporarily buffer + BlockMultilayer.initialize(); + + // load geo files + int converted = 0; + for (int rx = L2World.TILE_X_MIN; rx <= L2World.TILE_X_MAX; rx++) + { + for (int ry = L2World.TILE_Y_MIN; ry <= L2World.TILE_Y_MAX; ry++) + { + final String input = String.format(_format.getFilename(), rx, ry); + final String filepath = Config.GEODATA_PATH; + File f = new File(filepath + input); + if (f.exists() && !f.isDirectory()) + { + // load geodata + if (!loadGeoBlocks(input)) + { + System.out.println("GeoDataConverter: Unable to load " + input + " region file."); + continue; + } + + // recalculate nswe + if (!recalculateNswe()) + { + System.out.println("GeoDataConverter: Unable to convert " + input + " region file."); + continue; + } + + // save geodata + final String output = String.format(GeoFormat.L2D.getFilename(), rx, ry); + if (!saveGeoBlocks(output)) + { + System.out.println("GeoDataConverter: Unable to save " + output + " region file."); + continue; + } + + converted++; + System.out.println("GeoDataConverter: Created " + output + " region file."); + } + } + } + System.out.println("GeoDataConverter: Converted " + converted + " " + _format.toString() + " to L2D region file(s)."); + + // release multilayer block temporarily buffer + BlockMultilayer.release(); + } + + /** + * Loads geo blocks from buffer of the region file. + * @param filename : The name of the to load. + * @return boolean : True when successful. + */ + private static final boolean loadGeoBlocks(String filename) + { + // region file is load-able, try to load it + try (RandomAccessFile raf = new RandomAccessFile(Config.GEODATA_PATH + filename, "r"); + FileChannel fc = raf.getChannel()) + { + MappedByteBuffer buffer = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()).load(); + buffer.order(ByteOrder.LITTLE_ENDIAN); + + // load 18B header for L2off geodata (1st and 2nd byte...region X and Y) + if (_format == GeoFormat.L2OFF) + { + for (int i = 0; i < 18; i++) + { + buffer.get(); + } + } + + // loop over region blocks + for (int ix = 0; ix < GeoStructure.REGION_BLOCKS_X; ix++) + { + for (int iy = 0; iy < GeoStructure.REGION_BLOCKS_Y; iy++) + { + if (_format == GeoFormat.L2J) + { + // get block type + final byte type = buffer.get(); + + // load block according to block type + switch (type) + { + case GeoStructure.TYPE_FLAT_L2J_L2OFF: + _blocks[ix][iy] = new BlockFlat(buffer, _format); + break; + + case GeoStructure.TYPE_COMPLEX_L2J: + _blocks[ix][iy] = new BlockComplex(buffer, _format); + break; + + case GeoStructure.TYPE_MULTILAYER_L2J: + _blocks[ix][iy] = new BlockMultilayer(buffer, _format); + break; + + default: + throw new IllegalArgumentException("Unknown block type: " + type); + } + } + else + { + // get block type + final short type = buffer.getShort(); + + // load block according to block type + switch (type) + { + case GeoStructure.TYPE_FLAT_L2J_L2OFF: + _blocks[ix][iy] = new BlockFlat(buffer, _format); + break; + + case GeoStructure.TYPE_COMPLEX_L2OFF: + _blocks[ix][iy] = new BlockComplex(buffer, _format); + break; + + default: + _blocks[ix][iy] = new BlockMultilayer(buffer, _format); + break; + } + } + } + } + + if (buffer.remaining() > 0) + { + System.out.println("GeoDataConverter: Region file " + filename + " can be corrupted, remaining " + buffer.remaining() + " bytes to read."); + return false; + } + + return true; + } + catch (Exception e) + { + System.out.println("GeoDataConverter: Error while loading " + filename + " region file."); + return false; + } + } + + /** + * Recalculate diagonal flags for the region file. + * @return boolean : True when successful. + */ + private static final boolean recalculateNswe() + { + try + { + for (int x = 0; x < GeoStructure.REGION_CELLS_X; x++) + { + for (int y = 0; y < GeoStructure.REGION_CELLS_Y; y++) + { + // get block + ABlock block = _blocks[x / GeoStructure.BLOCK_CELLS_X][y / GeoStructure.BLOCK_CELLS_Y]; + + // skip flat blocks + if (block instanceof BlockFlat) + { + continue; + } + + // for complex and multilayer blocks go though all layers + short height = Short.MAX_VALUE; + int index; + while ((index = block.getIndexBelow(x, y, height)) != -1) + { + // get height and nswe + height = block.getHeight(index); + byte nswe = block.getNswe(index); + + // update nswe with diagonal flags + nswe = updateNsweBelow(x, y, height, nswe); + + // set nswe of the cell + block.setNswe(index, nswe); + } + } + } + + return true; + } + catch (Exception e) + { + return false; + } + } + + /** + * Updates the NSWE flag with diagonal flags. + * @param x : Geodata X coordinate. + * @param y : Geodata Y coordinate. + * @param z : Geodata Z coordinate. + * @param nswe : NSWE flag to be updated. + * @return byte : Updated NSWE flag. + */ + private static final byte updateNsweBelow(int x, int y, short z, byte nswe) + { + // calculate virtual layer height + short height = (short) (z + GeoStructure.CELL_IGNORE_HEIGHT); + + // get NSWE of neighbor cells below virtual layer (NPC/PC can fall down of clif, but can not climb it -> NSWE of cell below) + byte nsweN = getNsweBelow(x, y - 1, height); + byte nsweS = getNsweBelow(x, y + 1, height); + byte nsweW = getNsweBelow(x - 1, y, height); + byte nsweE = getNsweBelow(x + 1, y, height); + + // north-west + if ((((nswe & GeoStructure.CELL_FLAG_N) != 0) && ((nsweN & GeoStructure.CELL_FLAG_W) != 0)) || (((nswe & GeoStructure.CELL_FLAG_W) != 0) && ((nsweW & GeoStructure.CELL_FLAG_N) != 0))) + { + nswe |= GeoStructure.CELL_FLAG_NW; + } + + // north-east + if ((((nswe & GeoStructure.CELL_FLAG_N) != 0) && ((nsweN & GeoStructure.CELL_FLAG_E) != 0)) || (((nswe & GeoStructure.CELL_FLAG_E) != 0) && ((nsweE & GeoStructure.CELL_FLAG_N) != 0))) + { + nswe |= GeoStructure.CELL_FLAG_NE; + } + + // south-west + if ((((nswe & GeoStructure.CELL_FLAG_S) != 0) && ((nsweS & GeoStructure.CELL_FLAG_W) != 0)) || (((nswe & GeoStructure.CELL_FLAG_W) != 0) && ((nsweW & GeoStructure.CELL_FLAG_S) != 0))) + { + nswe |= GeoStructure.CELL_FLAG_SW; + } + + // south-east + if ((((nswe & GeoStructure.CELL_FLAG_S) != 0) && ((nsweS & GeoStructure.CELL_FLAG_E) != 0)) || (((nswe & GeoStructure.CELL_FLAG_E) != 0) && ((nsweE & GeoStructure.CELL_FLAG_S) != 0))) + { + nswe |= GeoStructure.CELL_FLAG_SE; + } + + return nswe; + } + + private static final byte getNsweBelow(int geoX, int geoY, short worldZ) + { + // out of geo coordinates + if ((geoX < 0) || (geoX >= GeoStructure.REGION_CELLS_X)) + { + return 0; + } + + // out of geo coordinates + if ((geoY < 0) || (geoY >= GeoStructure.REGION_CELLS_Y)) + { + return 0; + } + + // get block + final ABlock block = _blocks[geoX / GeoStructure.BLOCK_CELLS_X][geoY / GeoStructure.BLOCK_CELLS_Y]; + + // get index, when valid, return nswe + final int index = block.getIndexBelow(geoX, geoY, worldZ); + return index == -1 ? 0 : block.getNswe(index); + } + + /** + * Save region file to file. + * @param filename : The name of file to save. + * @return boolean : True when successful. + */ + private static final boolean saveGeoBlocks(String filename) + { + try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(Config.GEODATA_PATH + filename), GeoStructure.REGION_BLOCKS * GeoStructure.BLOCK_CELLS * 3)) + { + // loop over region blocks and save each block + for (int ix = 0; ix < GeoStructure.REGION_BLOCKS_X; ix++) + { + for (int iy = 0; iy < GeoStructure.REGION_BLOCKS_Y; iy++) + { + _blocks[ix][iy].saveBlock(bos); + } + } + + // flush data to file + bos.flush(); + + return true; + } + catch (Exception e) + { + return false; + } + } + + private static final void loadGeoengineConfigs() + { + final PropertiesParser geoData = new PropertiesParser(Config.GEODATA_FILE); + Config.GEODATA_PATH = geoData.getString("GeoDataPath", "./data/geodata/"); + Config.COORD_SYNCHRONIZE = geoData.getInt("CoordSynchronize", -1); + Config.PART_OF_CHARACTER_HEIGHT = geoData.getInt("PartOfCharacterHeight", 75); + Config.MAX_OBSTACLE_HEIGHT = geoData.getInt("MaxObstacleHeight", 32); + Config.PATHFINDING = geoData.getBoolean("PathFinding", true); + Config.PATHFIND_BUFFERS = geoData.getString("PathFindBuffers", "100x6;128x6;192x6;256x4;320x4;384x4;500x2"); + Config.BASE_WEIGHT = geoData.getInt("BaseWeight", 10); + Config.DIAGONAL_WEIGHT = geoData.getInt("DiagonalWeight", 14); + Config.OBSTACLE_MULTIPLIER = geoData.getInt("ObstacleMultiplier", 10); + Config.HEURISTIC_WEIGHT = geoData.getInt("HeuristicWeight", 20); + Config.MAX_ITERATIONS = geoData.getInt("MaxIterations", 3500); + } +} \ No newline at end of file diff --git a/L2J_Mobius_HighFive/build.xml b/L2J_Mobius_HighFive/build.xml index 5bcd95c967..d0647e5deb 100644 --- a/L2J_Mobius_HighFive/build.xml +++ b/L2J_Mobius_HighFive/build.xml @@ -74,6 +74,7 @@ + diff --git a/L2J_Mobius_HighFive/dist/game/GeoDataConverter.bat b/L2J_Mobius_HighFive/dist/game/GeoDataConverter.bat new file mode 100644 index 0000000000..1f199613e9 --- /dev/null +++ b/L2J_Mobius_HighFive/dist/game/GeoDataConverter.bat @@ -0,0 +1,6 @@ +@echo off +title L2D geodata converter + +java -Xmx512m -cp ./../libs/*;GameServer.jar com.l2jmobius.tools.geodataconverter.GeoDataConverter + +pause diff --git a/L2J_Mobius_HighFive/dist/game/GeoDataConverter.sh b/L2J_Mobius_HighFive/dist/game/GeoDataConverter.sh new file mode 100644 index 0000000000..b039beec34 --- /dev/null +++ b/L2J_Mobius_HighFive/dist/game/GeoDataConverter.sh @@ -0,0 +1,4 @@ +#! /bin/sh + +java -Xmx512m -cp ./../libs/*;GameServer.jar com.l2jmobius.tools.geodataconverter.GeoDataConverter > log/stdout.log 2>&1 + diff --git a/L2J_Mobius_HighFive/dist/game/config/AdminCommands.xml b/L2J_Mobius_HighFive/dist/game/config/AdminCommands.xml index a43e83986c..21610d47e5 100644 --- a/L2J_Mobius_HighFive/dist/game/config/AdminCommands.xml +++ b/L2J_Mobius_HighFive/dist/game/config/AdminCommands.xml @@ -395,11 +395,7 @@ - - - - - + diff --git a/L2J_Mobius_HighFive/dist/game/config/GeoData.ini b/L2J_Mobius_HighFive/dist/game/config/GeoData.ini deleted file mode 100644 index d07eb30e73..0000000000 --- a/L2J_Mobius_HighFive/dist/game/config/GeoData.ini +++ /dev/null @@ -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 file directory -# Default: pathnode -PathnodePath = 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 file directory -GeoDataPath = 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 diff --git a/L2J_Mobius_HighFive/dist/game/config/GeoEngine.ini b/L2J_Mobius_HighFive/dist/game/config/GeoEngine.ini new file mode 100644 index 0000000000..94a0b1ac44 --- /dev/null +++ b/L2J_Mobius_HighFive/dist/game/config/GeoEngine.ini @@ -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 diff --git a/L2J_Mobius_HighFive/dist/game/data/geodata/Readme.txt b/L2J_Mobius_HighFive/dist/game/data/geodata/Readme.txt index bf1f2071aa..8b18814e82 100644 --- a/L2J_Mobius_HighFive/dist/game/data/geodata/Readme.txt +++ b/L2J_Mobius_HighFive/dist/game/data/geodata/Readme.txt @@ -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 # -# # -##################################################### \ No newline at end of file +############################################## +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. diff --git a/L2J_Mobius_HighFive/dist/game/data/pathnode/Readme.txt b/L2J_Mobius_HighFive/dist/game/data/pathnode/Readme.txt deleted file mode 100644 index 2dfdaa8aab..0000000000 --- a/L2J_Mobius_HighFive/dist/game/data/pathnode/Readme.txt +++ /dev/null @@ -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 # -# # -##################################################### \ No newline at end of file diff --git a/L2J_Mobius_HighFive/dist/game/data/scripts/ai/group_template/AltarsOfSacrifice.java b/L2J_Mobius_HighFive/dist/game/data/scripts/ai/group_template/AltarsOfSacrifice.java index 230732a264..6f6613464d 100644 --- a/L2J_Mobius_HighFive/dist/game/data/scripts/ai/group_template/AltarsOfSacrifice.java +++ b/L2J_Mobius_HighFive/dist/game/data/scripts/ai/group_template/AltarsOfSacrifice.java @@ -18,7 +18,7 @@ package ai.group_template; import java.util.logging.Level; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.model.L2Spawn; import com.l2jmobius.gameserver.model.Location; import com.l2jmobius.gameserver.model.actor.L2Npc; @@ -62,7 +62,7 @@ public final class AltarsOfSacrifice extends AbstractNpcAI final int spawnX = (int) (radius * Math.cos(angleRadians)) + _middlePoint.getX(); final int spawnY = (int) (radius * Math.sin(angleRadians)) + _middlePoint.getY(); - spawn.setXYZ(spawnX, spawnY, GeoData.getInstance().getHeight(spawnX, spawnY, _middlePoint.getZ())); + spawn.setXYZ(spawnX, spawnY, GeoEngine.getInstance().getHeight(spawnX, spawnY, _middlePoint.getZ())); spawn.stopRespawn(); _spawnedBoss = spawn.spawnOne(false); } diff --git a/L2J_Mobius_HighFive/dist/game/data/scripts/ai/group_template/FleeMonsters.java b/L2J_Mobius_HighFive/dist/game/data/scripts/ai/group_template/FleeMonsters.java index c24c4792c3..e2cf6e6996 100644 --- a/L2J_Mobius_HighFive/dist/game/data/scripts/ai/group_template/FleeMonsters.java +++ b/L2J_Mobius_HighFive/dist/game/data/scripts/ai/group_template/FleeMonsters.java @@ -17,7 +17,7 @@ package ai.group_template; 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; @@ -71,7 +71,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.getInstanceId()); + final Location destination = GeoEngine.getInstance().canMoveToTargetLoc(npc.getX(), npc.getY(), npc.getZ(), posX, posY, posZ, attacker.getInstanceId()); npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, destination); return super.onAttack(npc, attacker, damage, isSummon); } diff --git a/L2J_Mobius_HighFive/dist/game/data/scripts/ai/group_template/PlainsOfDion.java b/L2J_Mobius_HighFive/dist/game/data/scripts/ai/group_template/PlainsOfDion.java index 3c46e92d28..91214518d1 100644 --- a/L2J_Mobius_HighFive/dist/game/data/scripts/ai/group_template/PlainsOfDion.java +++ b/L2J_Mobius_HighFive/dist/game/data/scripts/ai/group_template/PlainsOfDion.java @@ -17,7 +17,7 @@ package ai.group_template; import com.l2jmobius.gameserver.enums.ChatType; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; @@ -78,7 +78,7 @@ public final class PlainsOfDion extends AbstractNpcAI for (L2Character obj : npc.getKnownList().getKnownCharactersInRadius(npc.getTemplate().getClanHelpRange())) { - if (obj.isMonster() && Util.contains(DELU_LIZARDMEN, obj.getId()) && !obj.isAttackingNow() && !obj.isDead() && GeoData.getInstance().canSeeTarget(npc, obj)) + if (obj.isMonster() && Util.contains(DELU_LIZARDMEN, obj.getId()) && !obj.isAttackingNow() && !obj.isDead() && GeoEngine.getInstance().canSeeTarget(npc, obj)) { final L2Npc monster = (L2Npc) obj; addAttackDesire(monster, player); diff --git a/L2J_Mobius_HighFive/dist/game/data/scripts/ai/group_template/PrimevalIsle.java b/L2J_Mobius_HighFive/dist/game/data/scripts/ai/group_template/PrimevalIsle.java index 351e0d67c5..607082f858 100644 --- a/L2J_Mobius_HighFive/dist/game/data/scripts/ai/group_template/PrimevalIsle.java +++ b/L2J_Mobius_HighFive/dist/game/data/scripts/ai/group_template/PrimevalIsle.java @@ -18,7 +18,7 @@ package ai.group_template; 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.Location; @@ -269,7 +269,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.getInstanceId()); + final Location loc = GeoEngine.getInstance().canMoveToTargetLoc(npc.getX(), npc.getY(), npc.getZ(), newX, newY, npc.getZ(), npc.getInstanceId()); npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, loc, 0); } else if (ag_type == 1) diff --git a/L2J_Mobius_HighFive/dist/game/data/scripts/ai/individual/ScarletVanHalisha.java b/L2J_Mobius_HighFive/dist/game/data/scripts/ai/individual/ScarletVanHalisha.java index 264b5197fb..6520e73662 100644 --- a/L2J_Mobius_HighFive/dist/game/data/scripts/ai/individual/ScarletVanHalisha.java +++ b/L2J_Mobius_HighFive/dist/game/data/scripts/ai/individual/ScarletVanHalisha.java @@ -24,7 +24,7 @@ import java.util.ArrayList; import java.util.Collection; import com.l2jmobius.gameserver.datatables.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; @@ -222,7 +222,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; } diff --git a/L2J_Mobius_HighFive/dist/game/data/scripts/ai/individual/Valakas.java b/L2J_Mobius_HighFive/dist/game/data/scripts/ai/individual/Valakas.java index e70f998ab0..31a29294ed 100644 --- a/L2J_Mobius_HighFive/dist/game/data/scripts/ai/individual/Valakas.java +++ b/L2J_Mobius_HighFive/dist/game/data/scripts/ai/individual/Valakas.java @@ -23,7 +23,7 @@ import com.l2jmobius.Config; import com.l2jmobius.gameserver.ai.CtrlIntention; import com.l2jmobius.gameserver.datatables.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.model.Location; import com.l2jmobius.gameserver.model.StatsSet; @@ -477,7 +477,7 @@ public final class Valakas extends AbstractNpcAI final int posX = x + getRandom(-1400, 1400); final int posY = y + getRandom(-1400, 1400); - if (GeoData.getInstance().canMove(x, y, z, posX, posY, z, npc.getInstanceId())) + if (GeoEngine.getInstance().canMoveToTarget(x, y, z, posX, posY, z, npc.getInstanceId())) { npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(posX, posY, z, 0)); } diff --git a/L2J_Mobius_HighFive/dist/game/data/scripts/ai/npc/ForgeOfTheGods/TarBeetleSpawn.java b/L2J_Mobius_HighFive/dist/game/data/scripts/ai/npc/ForgeOfTheGods/TarBeetleSpawn.java index ccd86d1e70..9e52de84df 100644 --- a/L2J_Mobius_HighFive/dist/game/data/scripts/ai/npc/ForgeOfTheGods/TarBeetleSpawn.java +++ b/L2J_Mobius_HighFive/dist/game/data/scripts/ai/npc/ForgeOfTheGods/TarBeetleSpawn.java @@ -26,7 +26,7 @@ import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import com.l2jmobius.gameserver.ThreadPoolManager; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.model.L2Spawn; import com.l2jmobius.gameserver.model.L2Territory; import com.l2jmobius.gameserver.model.Location; @@ -228,7 +228,7 @@ public class TarBeetleSpawn implements IXmlReader spawn.setHeading(Rnd.get(65535)); spawn.setX(location.getX()); spawn.setY(location.getY()); - spawn.setZ(GeoData.getInstance().getSpawnHeight(location)); + spawn.setZ(GeoEngine.getInstance().getHeight(location.getX(), location.getY(), location.getZ())); final L2Npc npc = spawn.doSpawn(); npc.setIsNoRndWalk(true); diff --git a/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/actionhandlers/L2NpcAction.java b/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/actionhandlers/L2NpcAction.java index 8faf812826..6e2e09bbd8 100644 --- a/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/actionhandlers/L2NpcAction.java +++ b/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/actionhandlers/L2NpcAction.java @@ -19,7 +19,7 @@ package handlers.actionhandlers; import com.l2jmobius.Config; 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.Location; @@ -82,13 +82,13 @@ public class L2NpcAction implements IActionHandler // Check if the activeChar is attackable (without a forced attack) and isn't dead if (target.isAutoAttackable(activeChar) && !((L2Npc) target).isAlikeDead()) { - if (GeoData.getInstance().canSeeTarget(activeChar, target)) + if (GeoEngine.getInstance().canSeeTarget(activeChar, target)) { activeChar.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, target); } else { - final Location destination = GeoData.getInstance().moveCheck(activeChar, target); + final Location destination = GeoEngine.getInstance().canMoveToTargetLoc(activeChar.getX(), activeChar.getY(), activeChar.getZ(), target.getX(), target.getY(), target.getZ(), activeChar.getInstanceId()); activeChar.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, destination); } } diff --git a/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/actionhandlers/L2PcInstanceAction.java b/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/actionhandlers/L2PcInstanceAction.java index a71a760691..5ee9cd39a4 100644 --- a/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/actionhandlers/L2PcInstanceAction.java +++ b/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/actionhandlers/L2PcInstanceAction.java @@ -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.Location; @@ -102,13 +102,13 @@ public class L2PcInstanceAction implements IActionHandler } else { - if (GeoData.getInstance().canSeeTarget(activeChar, player)) + if (GeoEngine.getInstance().canSeeTarget(activeChar, player)) { activeChar.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, player); } else { - final Location destination = GeoData.getInstance().moveCheck(activeChar, player); + final Location destination = GeoEngine.getInstance().canMoveToTargetLoc(activeChar.getX(), activeChar.getY(), activeChar.getZ(), player.getX(), player.getY(), player.getZ(), activeChar.getInstanceId()); activeChar.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, destination); } activeChar.onActionRequest(); @@ -118,13 +118,13 @@ 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, player)) + if (GeoEngine.getInstance().canSeeTarget(activeChar, player)) { activeChar.getAI().setIntention(CtrlIntention.AI_INTENTION_FOLLOW, player); } else { - final Location destination = GeoData.getInstance().moveCheck(activeChar, player); + final Location destination = GeoEngine.getInstance().canMoveToTargetLoc(activeChar.getX(), activeChar.getY(), activeChar.getZ(), player.getX(), player.getY(), player.getZ(), activeChar.getInstanceId()); activeChar.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, destination); } } diff --git a/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/actionhandlers/L2PetInstanceAction.java b/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/actionhandlers/L2PetInstanceAction.java index dfbce6a9be..224f2eb903 100644 --- a/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/actionhandlers/L2PetInstanceAction.java +++ b/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/actionhandlers/L2PetInstanceAction.java @@ -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(); diff --git a/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/actionhandlers/L2SummonAction.java b/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/actionhandlers/L2SummonAction.java index 4764c1ffef..486ac079e7 100644 --- a/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/actionhandlers/L2SummonAction.java +++ b/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/actionhandlers/L2SummonAction.java @@ -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(); @@ -74,7 +74,7 @@ public class L2SummonAction implements IActionHandler } else { - if (GeoData.getInstance().canSeeTarget(activeChar, target)) + if (GeoEngine.getInstance().canSeeTarget(activeChar, target)) { activeChar.getAI().setIntention(CtrlIntention.AI_INTENTION_FOLLOW, target); } diff --git a/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminGeodata.java b/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminGeodata.java index 0e95e3a556..04b7fac173 100644 --- a/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminGeodata.java +++ b/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminGeodata.java @@ -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(geoX, geoY, 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."); } diff --git a/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminPathNode.java b/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminPathNode.java index a62074244b..795e401159 100644 --- a/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminPathNode.java +++ b/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminPathNode.java @@ -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 path = PathFinding.getInstance().findPath(activeChar.getX(), activeChar.getY(), (short) activeChar.getZ(), activeChar.getTarget().getX(), activeChar.getTarget().getY(), (short) activeChar.getTarget().getZ(), activeChar.getInstanceId(), true); + List path = GeoEngine.getInstance().findPath(activeChar.getX(), activeChar.getY(), (short) activeChar.getZ(), activeChar.getTarget().getX(), activeChar.getTarget().getY(), (short) activeChar.getTarget().getZ(), activeChar.getInstanceId(), 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; } diff --git a/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminServerInfo.java b/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminServerInfo.java index 6796381333..867836c680 100644 --- a/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminServerInfo.java +++ b/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminServerInfo.java @@ -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")); diff --git a/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminZones.java b/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminZones.java index f82aa59aaa..e2741e9b0a 100644 --- a/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminZones.java +++ b/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminZones.java @@ -31,7 +31,7 @@ import java.util.logging.Logger; import com.l2jmobius.Config; 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; @@ -262,7 +262,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); } diff --git a/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/effecthandlers/Blink.java b/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/effecthandlers/Blink.java index 2c7eccd4c1..e3524745f6 100644 --- a/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/effecthandlers/Blink.java +++ b/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/effecthandlers/Blink.java @@ -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 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.getInstanceId()); + final Location destination = GeoEngine.getInstance().canMoveToTargetLoc(effected.getX(), effected.getY(), effected.getZ(), x, y, z, effected.getInstanceId()); effected.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); effected.broadcastPacket(new FlyToLocation(effected, destination, FlyType.DUMMY)); diff --git a/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/effecthandlers/EnemyCharge.java b/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/effecthandlers/EnemyCharge.java index e65d1aa31e..fbe1912864 100644 --- a/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/effecthandlers/EnemyCharge.java +++ b/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/effecthandlers/EnemyCharge.java @@ -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.conditions.Condition; @@ -91,7 +91,7 @@ public final class EnemyCharge extends AbstractEffect final int y = curY + (int) ((distance - offset) * sin); final int z = info.getEffected().getZ(); - final Location destination = GeoData.getInstance().moveCheck(info.getEffector().getX(), info.getEffector().getY(), info.getEffector().getZ(), x, y, z, info.getEffector().getInstanceId()); + final Location destination = GeoEngine.getInstance().canMoveToTargetLoc(info.getEffector().getX(), info.getEffector().getY(), info.getEffector().getZ(), x, y, z, info.getEffector().getInstanceId()); info.getEffector().broadcastPacket(new FlyToLocation(info.getEffector(), destination, FlyType.CHARGE)); diff --git a/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/effecthandlers/Fishing.java b/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/effecthandlers/Fishing.java index cf93d6fef1..8aa3535904 100644 --- a/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/effecthandlers/Fishing.java +++ b/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/effecthandlers/Fishing.java @@ -17,8 +17,9 @@ package handlers.effecthandlers; import com.l2jmobius.Config; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.instancemanager.ZoneManager; +import com.l2jmobius.gameserver.model.Location; import com.l2jmobius.gameserver.model.PcCondOverride; import com.l2jmobius.gameserver.model.StatsSet; import com.l2jmobius.gameserver.model.actor.L2Character; @@ -237,19 +238,19 @@ public final class Fishing extends AbstractEffect // always use water zone, fishing zone high z is high in the air... final int baitZ = waterZone.getWaterZ(); - if (!GeoData.getInstance().canSeeTarget(player.getX(), player.getY(), player.getZ(), baitX, baitY, baitZ)) + if (!GeoEngine.getInstance().canSeeTarget(player, new Location(baitX, baitY, baitZ))) { return Integer.MIN_VALUE; } - if (GeoData.getInstance().hasGeo(baitX, baitY)) + if (GeoEngine.getInstance().hasGeo(baitX, baitY)) { - if (GeoData.getInstance().getHeight(baitX, baitY, baitZ) > baitZ) + if (GeoEngine.getInstance().getHeight(baitX, baitY, baitZ) > baitZ) { return Integer.MIN_VALUE; } - if (GeoData.getInstance().getHeight(baitX, baitY, player.getZ()) > baitZ) + if (GeoEngine.getInstance().getHeight(baitX, baitY, player.getZ()) > baitZ) { return Integer.MIN_VALUE; } diff --git a/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/effecthandlers/TeleportToTarget.java b/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/effecthandlers/TeleportToTarget.java index a716d8cdab..dd5fec07e1 100644 --- a/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/effecthandlers/TeleportToTarget.java +++ b/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/effecthandlers/TeleportToTarget.java @@ -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; @@ -78,7 +78,7 @@ public final class TeleportToTarget extends AbstractEffect final int y = (int) (py + (25 * Math.sin(ph))); final int z = target.getZ(); - final Location loc = GeoData.getInstance().moveCheck(activeChar.getX(), activeChar.getY(), activeChar.getZ(), x, y, z, activeChar.getInstanceId()); + final Location loc = GeoEngine.getInstance().canMoveToTargetLoc(activeChar.getX(), activeChar.getY(), activeChar.getZ(), x, y, z, activeChar.getInstanceId()); activeChar.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); activeChar.broadcastPacket(new FlyToLocation(activeChar, loc.getX(), loc.getY(), loc.getZ(), FlyType.DUMMY)); diff --git a/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/effecthandlers/ThrowUp.java b/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/effecthandlers/ThrowUp.java index fc8393bd3a..a286c194db 100644 --- a/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/effecthandlers/ThrowUp.java +++ b/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/effecthandlers/ThrowUp.java @@ -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.conditions.Condition; @@ -95,7 +95,7 @@ public final class ThrowUp extends AbstractEffect final int y = info.getEffector().getY() - (int) (offset * sin); final int z = info.getEffected().getZ(); - final Location destination = GeoData.getInstance().moveCheck(info.getEffected().getX(), info.getEffected().getY(), info.getEffected().getZ(), x, y, z, info.getEffected().getInstanceId()); + final Location destination = GeoEngine.getInstance().canMoveToTargetLoc(info.getEffected().getX(), info.getEffected().getY(), info.getEffected().getZ(), x, y, z, info.getEffected().getInstanceId()); info.getEffected().broadcastPacket(new FlyToLocation(info.getEffected(), destination, FlyType.THROW_UP)); // TODO: Review. diff --git a/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/targethandlers/AreaFriendly.java b/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/targethandlers/AreaFriendly.java index 3327195ed4..cb3753a536 100644 --- a/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/targethandlers/AreaFriendly.java +++ b/L2J_Mobius_HighFive/dist/game/data/scripts/handlers/targethandlers/AreaFriendly.java @@ -22,7 +22,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; -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; @@ -100,7 +100,7 @@ public class AreaFriendly implements ITargetTypeHandler private boolean checkTarget(L2PcInstance activeChar, L2Character target) { - if (!GeoData.getInstance().canSeeTarget(activeChar, target)) + if (!GeoEngine.getInstance().canSeeTarget(activeChar, target)) { return false; } diff --git a/L2J_Mobius_HighFive/dist/game/data/scripts/instances/CrystalCaverns/CrystalCaverns.java b/L2J_Mobius_HighFive/dist/game/data/scripts/instances/CrystalCaverns/CrystalCaverns.java index ca00def02b..b9d652a02e 100644 --- a/L2J_Mobius_HighFive/dist/game/data/scripts/instances/CrystalCaverns/CrystalCaverns.java +++ b/L2J_Mobius_HighFive/dist/game/data/scripts/instances/CrystalCaverns/CrystalCaverns.java @@ -27,7 +27,7 @@ import com.l2jmobius.gameserver.ai.CtrlIntention; import com.l2jmobius.gameserver.datatables.SkillData; import com.l2jmobius.gameserver.enums.ChatType; import com.l2jmobius.gameserver.enums.TrapAction; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.instancemanager.InstanceManager; import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2Party; @@ -682,7 +682,7 @@ public final class CrystalCaverns extends AbstractInstance final int _y = effector.getY() - (int) (offset * sin); final int _z = effected.getZ(); - final Location destination = GeoData.getInstance().moveCheck(effected.getX(), effected.getY(), effected.getZ(), _x, _y, _z, effected.getInstanceId()); + final Location destination = GeoEngine.getInstance().canMoveToTargetLoc(effected.getX(), effected.getY(), effected.getZ(), _x, _y, _z, effected.getInstanceId()); effected.broadcastPacket(new FlyToLocation(effected, destination, FlyType.THROW_UP)); diff --git a/L2J_Mobius_HighFive/dist/game/data/scripts/instances/FinalEmperialTomb/FinalEmperialTomb.java b/L2J_Mobius_HighFive/dist/game/data/scripts/instances/FinalEmperialTomb/FinalEmperialTomb.java index 95d902425f..cb852e75d3 100644 --- a/L2J_Mobius_HighFive/dist/game/data/scripts/instances/FinalEmperialTomb/FinalEmperialTomb.java +++ b/L2J_Mobius_HighFive/dist/game/data/scripts/instances/FinalEmperialTomb/FinalEmperialTomb.java @@ -33,7 +33,7 @@ import org.w3c.dom.Node; import com.l2jmobius.gameserver.ThreadPoolManager; 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.instancemanager.InstanceManager; import com.l2jmobius.gameserver.model.L2CommandChannel; import com.l2jmobius.gameserver.model.L2Object; @@ -569,7 +569,7 @@ public final class FinalEmperialTomb extends AbstractInstance implements IXmlRea final Location location = _spawnZoneList.get(spw.zone).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); } } else diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/Config.java b/L2J_Mobius_HighFive/java/com/l2jmobius/Config.java index 8c41843a45..4b51a01228 100644 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/Config.java +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/Config.java @@ -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.util.ArrayList; import java.util.Arrays; @@ -56,7 +55,6 @@ import org.w3c.dom.Node; import com.l2jmobius.gameserver.GameServer; import com.l2jmobius.gameserver.enums.ChatType; import com.l2jmobius.gameserver.enums.IllegalActionPunishmentType; -import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.holders.ItemHolder; import com.l2jmobius.gameserver.util.FloodProtectorConfig; import com.l2jmobius.gameserver.util.Util; @@ -102,7 +100,8 @@ 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"; + // -------------------------------------------------- // L2J Variable Definitions // -------------------------------------------------- @@ -1140,22 +1139,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 Path PATHNODE_PATH; - 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 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; /** * This class initializes all global variables for configuration.
@@ -2846,31 +2849,19 @@ public final class Config final PropertiesParser geoData = new PropertiesParser(GEODATA_FILE); - PATHNODE_PATH = Paths.get(Config.DATAPACK_ROOT.getPath() + "/data/" + geoData.getString("PathnodePath", "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(Config.DATAPACK_ROOT.getPath() + "/data/" + geoData.getString("GeoDataPath", "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++) - { - if (geoData.containskey(regionX + "_" + regionY)) - { - GEODATA_REGIONS.put(regionX + "_" + regionY, geoData.getBoolean(regionX + "_" + regionY, 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); } else if (Server.serverMode == Server.MODE_LOGINSERVER) { diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/GameServer.java index 55d38e823d..3fad7b0fac 100644 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/GameServer.java @@ -84,8 +84,7 @@ import com.l2jmobius.gameserver.datatables.ItemTable; import com.l2jmobius.gameserver.datatables.MerchantPriceConfigTable; import com.l2jmobius.gameserver.datatables.SkillData; import com.l2jmobius.gameserver.datatables.SpawnTable; -import com.l2jmobius.gameserver.geodata.GeoData; -import com.l2jmobius.gameserver.geodata.pathfinding.PathFinding; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.handler.EffectHandler; import com.l2jmobius.gameserver.idfactory.IdFactory; import com.l2jmobius.gameserver.instancemanager.AirShipManager; @@ -242,12 +241,8 @@ public final 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; diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java index 594deedc4f..80644f2f73 100644 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java @@ -32,7 +32,7 @@ import com.l2jmobius.gameserver.data.sql.impl.TerritoryTable; import com.l2jmobius.gameserver.datatables.SkillData; import com.l2jmobius.gameserver.enums.AISkillScope; import com.l2jmobius.gameserver.enums.AIType; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.instancemanager.DimensionalRiftManager; import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.Location; @@ -233,12 +233,12 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable // Check if the L2PcInstance target has karma (=PK) if ((player != null) && (player.getKarma() > 0)) { - return GeoData.getInstance().canSeeTarget(me, player); // Los Check + return GeoEngine.getInstance().canSeeTarget(me, player); // Los Check } // Check if the L2MonsterInstance target is aggressive if ((target instanceof L2MonsterInstance) && Config.GUARD_ATTACK_AGGRO_MOB) { - return (((L2MonsterInstance) target).isAggressive() && GeoData.getInstance().canSeeTarget(me, target)); + return (((L2MonsterInstance) target).isAggressive() && GeoEngine.getInstance().canSeeTarget(me, target)); } return false; @@ -254,7 +254,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable // Check if the L2PcInstance target has karma (=PK) if ((target instanceof L2PcInstance) && (((L2PcInstance) target).getKarma() > 0)) { - return GeoData.getInstance().canSeeTarget(me, target); // Los Check + return GeoEngine.getInstance().canSeeTarget(me, target); // Los Check } return false; } @@ -269,7 +269,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable if (me.isChaos() && me.isInsideRadius(target, me.getAggroRange(), false, false)) { - return !((L2Attackable) target).isInMyClan(me) && GeoData.getInstance().canSeeTarget(me, target); + return !((L2Attackable) target).isInMyClan(me) && GeoEngine.getInstance().canSeeTarget(me, target); } } @@ -291,7 +291,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable } // Check if the actor is Aggressive - return (me.isAggressive() && GeoData.getInstance().canSeeTarget(me, target)); + return (me.isAggressive() && GeoEngine.getInstance().canSeeTarget(me, target)); } } @@ -674,7 +674,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.getInstanceId()); + final Location moveLoc = GeoEngine.getInstance().canMoveToTargetLoc(npc.getX(), npc.getY(), npc.getZ(), x1, y1, z1, npc.getInstanceId()); moveTo(moveLoc.getX(), moveLoc.getY(), moveLoc.getZ()); } @@ -831,7 +831,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.getX(), npc.getY(), npc.getZ(), newX, newY, newZ, npc.getInstanceId())) + if (GeoEngine.getInstance().canMoveToTarget(npc.getX(), npc.getY(), npc.getZ(), newX, newY, newZ, npc.getInstanceId())) { moveTo(newX, newY, newZ); } @@ -848,7 +848,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable final int posZ = npc.getZ() + 30; posX = originalAttackTarget.getX() < posX ? posX + 300 : posX - 300; posY = originalAttackTarget.getY() < posY ? posY + 300 : posY - 300; - if (GeoData.getInstance().canMove(npc.getX(), npc.getY(), npc.getZ(), posX, posY, posZ, npc.getInstanceId())) + if (GeoEngine.getInstance().canMoveToTarget(npc.getX(), npc.getY(), npc.getZ(), posX, posY, posZ, npc.getInstanceId())) { setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(posX, posY, posZ, 0)); } @@ -924,7 +924,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable moveToPawn(leader, healSkill.getCastRange() + collision + leader.getTemplate().getCollisionRadius()); return; } - if (GeoData.getInstance().canSeeTarget(npc, leader)) + if (GeoEngine.getInstance().canSeeTarget(npc, leader)) { clientStopMoving(null); final L2Object target = npc.getTarget(); @@ -979,7 +979,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable } percentage = (targets.getCurrentHp() / targets.getMaxHp()) * 100; - if ((Rnd.get(100) < ((100 - percentage) / 10)) && GeoData.getInstance().canSeeTarget(npc, targets)) + if ((Rnd.get(100) < ((100 - percentage) / 10)) && GeoEngine.getInstance().canSeeTarget(npc, targets)) { clientStopMoving(null); final L2Object target = npc.getTarget(); @@ -1021,7 +1021,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable moveToPawn(leader, sk.getCastRange() + collision + leader.getTemplate().getCollisionRadius()); return; } - if (GeoData.getInstance().canSeeTarget(npc, leader)) + if (GeoEngine.getInstance().canSeeTarget(npc, leader)) { clientStopMoving(null); final L2Object target = npc.getTarget(); @@ -1054,7 +1054,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable { continue; } - if ((Rnd.get(100) < 10) && GeoData.getInstance().canSeeTarget(npc, targets)) + if ((Rnd.get(100) < 10) && GeoEngine.getInstance().canSeeTarget(npc, targets)) { clientStopMoving(null); final L2Object target = npc.getTarget(); @@ -1130,7 +1130,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable // -------------------------------------------------------------------------------- // Starts melee attack - if ((dist2 > range) || !GeoData.getInstance().canSeeTarget(npc, mostHate)) + if ((dist2 > range) || !GeoEngine.getInstance().canSeeTarget(npc, mostHate)) { if (npc.isMovementDisabled()) { @@ -1227,7 +1227,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable return true; } } - else if (GeoData.getInstance().canSeeTarget(caster, attackTarget) && !canAOE(sk) && !attackTarget.isDead() && (dist2 <= srange)) + else if (GeoEngine.getInstance().canSeeTarget(caster, attackTarget) && !canAOE(sk) && !attackTarget.isDead() && (dist2 <= srange)) { if (!attackTarget.isAffectedBySkill(sk.getId())) { @@ -1239,7 +1239,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable else if (canAOE(sk)) { if ((sk.getTargetType() == L2TargetType.AURA) || (sk.getTargetType() == L2TargetType.BEHIND_AURA) || (sk.getTargetType() == L2TargetType.FRONT_AURA) || (sk.getTargetType() == L2TargetType.AURA_CORPSE_MOB) // - || (((sk.getTargetType() == L2TargetType.AREA) || (sk.getTargetType() == L2TargetType.BEHIND_AREA) || (sk.getTargetType() == L2TargetType.FRONT_AREA)) && GeoData.getInstance().canSeeTarget(caster, attackTarget) && !attackTarget.isDead() && (dist2 <= srange))) + || (((sk.getTargetType() == L2TargetType.AREA) || (sk.getTargetType() == L2TargetType.BEHIND_AREA) || (sk.getTargetType() == L2TargetType.FRONT_AREA)) && GeoEngine.getInstance().canSeeTarget(caster, attackTarget) && !attackTarget.isDead() && (dist2 <= srange))) { clientStopMoving(null); caster.doCast(sk); @@ -1258,7 +1258,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable { if (sk.getTargetType() == L2TargetType.ONE) { - if ((attackTarget.getEffectList().getFirstEffect(L2EffectType.BUFF) != null) && GeoData.getInstance().canSeeTarget(caster, attackTarget) && !attackTarget.isDead() && (dist2 <= srange)) + if ((attackTarget.getEffectList().getFirstEffect(L2EffectType.BUFF) != null) && GeoEngine.getInstance().canSeeTarget(caster, attackTarget) && !attackTarget.isDead() && (dist2 <= srange)) { clientStopMoving(null); caster.doCast(sk); @@ -1275,8 +1275,8 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable } } else if (canAOE(sk) // - && ((((sk.getTargetType() == L2TargetType.AURA) || (sk.getTargetType() == L2TargetType.BEHIND_AURA) || (sk.getTargetType() == L2TargetType.FRONT_AURA)) && GeoData.getInstance().canSeeTarget(caster, attackTarget)) // - || (((sk.getTargetType() == L2TargetType.AREA) || (sk.getTargetType() == L2TargetType.BEHIND_AREA) || (sk.getTargetType() == L2TargetType.FRONT_AREA)) && GeoData.getInstance().canSeeTarget(caster, attackTarget) && !attackTarget.isDead() && (dist2 <= srange)))) + && ((((sk.getTargetType() == L2TargetType.AURA) || (sk.getTargetType() == L2TargetType.BEHIND_AURA) || (sk.getTargetType() == L2TargetType.FRONT_AURA)) && GeoEngine.getInstance().canSeeTarget(caster, attackTarget)) // + || (((sk.getTargetType() == L2TargetType.AREA) || (sk.getTargetType() == L2TargetType.BEHIND_AREA) || (sk.getTargetType() == L2TargetType.FRONT_AREA)) && GeoEngine.getInstance().canSeeTarget(caster, attackTarget) && !attackTarget.isDead() && (dist2 <= srange)))) { clientStopMoving(null); caster.doCast(sk); @@ -1296,7 +1296,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable { moveToPawn(leader, sk.getCastRange() + caster.getTemplate().getCollisionRadius() + leader.getTemplate().getCollisionRadius()); } - if (GeoData.getInstance().canSeeTarget(caster, leader)) + if (GeoEngine.getInstance().canSeeTarget(caster, leader)) { clientStopMoving(null); caster.setTarget(leader); @@ -1332,7 +1332,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable } percentage = (targets.getCurrentHp() / targets.getMaxHp()) * 100; - if ((Rnd.get(100) < ((100 - percentage) / 10)) && GeoData.getInstance().canSeeTarget(caster, targets)) + if ((Rnd.get(100) < ((100 - percentage) / 10)) && GeoEngine.getInstance().canSeeTarget(caster, targets)) { clientStopMoving(null); caster.setTarget(obj); @@ -1365,7 +1365,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable if (sk.hasEffectType(L2EffectType.PHYSICAL_ATTACK, L2EffectType.PHYSICAL_ATTACK_HP_LINK, L2EffectType.MAGICAL_ATTACK, L2EffectType.DEATH_LINK, L2EffectType.HP_DRAIN)) { - if (canAura(sk) || (GeoData.getInstance().canSeeTarget(caster, attackTarget) && !attackTarget.isDead() && (dist2 <= srange))) + if (canAura(sk) || (GeoEngine.getInstance().canSeeTarget(caster, attackTarget) && !attackTarget.isDead() && (dist2 <= srange))) { clientStopMoving(null); caster.doCast(sk); @@ -1396,7 +1396,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable } else if (canAOE(sk) && // ((sk.getTargetType() == L2TargetType.AURA) || (sk.getTargetType() == L2TargetType.BEHIND_AURA) || (sk.getTargetType() == L2TargetType.FRONT_AURA)// - || (((sk.getTargetType() == L2TargetType.AREA) || (sk.getTargetType() == L2TargetType.BEHIND_AREA) || (sk.getTargetType() == L2TargetType.FRONT_AREA)) && GeoData.getInstance().canSeeTarget(caster, attackTarget) && !attackTarget.isDead() && (dist2 <= srange)))) + || (((sk.getTargetType() == L2TargetType.AREA) || (sk.getTargetType() == L2TargetType.BEHIND_AREA) || (sk.getTargetType() == L2TargetType.FRONT_AREA)) && GeoEngine.getInstance().canSeeTarget(caster, attackTarget) && !attackTarget.isDead() && (dist2 <= srange)))) { clientStopMoving(null); caster.doCast(sk); @@ -1406,7 +1406,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable if (sk.hasEffectType(L2EffectType.STUN, L2EffectType.ROOT, L2EffectType.PARALYZE, L2EffectType.MUTE, L2EffectType.FEAR)) { - if (GeoData.getInstance().canSeeTarget(caster, attackTarget) && !canAOE(sk) && (dist2 <= srange)) + if (GeoEngine.getInstance().canSeeTarget(caster, attackTarget) && !canAOE(sk) && (dist2 <= srange)) { if (!attackTarget.isAffectedBySkill(sk.getId())) { @@ -1418,7 +1418,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable else if (canAOE(sk)) { if ((sk.getTargetType() == L2TargetType.AURA) || (sk.getTargetType() == L2TargetType.BEHIND_AURA) || (sk.getTargetType() == L2TargetType.FRONT_AURA)// - || (((sk.getTargetType() == L2TargetType.AREA) || (sk.getTargetType() == L2TargetType.BEHIND_AREA) || (sk.getTargetType() == L2TargetType.FRONT_AREA)) && GeoData.getInstance().canSeeTarget(caster, attackTarget) && !attackTarget.isDead() && (dist2 <= srange))) + || (((sk.getTargetType() == L2TargetType.AREA) || (sk.getTargetType() == L2TargetType.BEHIND_AREA) || (sk.getTargetType() == L2TargetType.FRONT_AREA)) && GeoEngine.getInstance().canSeeTarget(caster, attackTarget) && !attackTarget.isDead() && (dist2 <= srange))) { clientStopMoving(null); caster.doCast(sk); @@ -1435,7 +1435,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable if (sk.hasEffectType(L2EffectType.DMG_OVER_TIME, L2EffectType.DMG_OVER_TIME_PERCENT)) { - if (GeoData.getInstance().canSeeTarget(caster, attackTarget) && !canAOE(sk) && !attackTarget.isDead() && (dist2 <= srange)) + if (GeoEngine.getInstance().canSeeTarget(caster, attackTarget) && !canAOE(sk) && !attackTarget.isDead() && (dist2 <= srange)) { if (!attackTarget.isAffectedBySkill(sk.getId())) { @@ -1447,7 +1447,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable else if (canAOE(sk)) { if ((sk.getTargetType() == L2TargetType.AURA) || (sk.getTargetType() == L2TargetType.BEHIND_AURA) || (sk.getTargetType() == L2TargetType.FRONT_AURA) || (sk.getTargetType() == L2TargetType.AURA_CORPSE_MOB)// - || (((sk.getTargetType() == L2TargetType.AREA) || (sk.getTargetType() == L2TargetType.BEHIND_AREA) || (sk.getTargetType() == L2TargetType.FRONT_AREA)) && GeoData.getInstance().canSeeTarget(caster, attackTarget) && !attackTarget.isDead() && (dist2 <= srange))) + || (((sk.getTargetType() == L2TargetType.AREA) || (sk.getTargetType() == L2TargetType.BEHIND_AREA) || (sk.getTargetType() == L2TargetType.FRONT_AREA)) && GeoEngine.getInstance().canSeeTarget(caster, attackTarget) && !attackTarget.isDead() && (dist2 <= srange))) { clientStopMoving(null); caster.doCast(sk); @@ -1477,7 +1477,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable { moveToPawn(leader, sk.getCastRange() + caster.getTemplate().getCollisionRadius() + leader.getTemplate().getCollisionRadius()); } - if (GeoData.getInstance().canSeeTarget(caster, leader)) + if (GeoEngine.getInstance().canSeeTarget(caster, leader)) { clientStopMoving(null); caster.setTarget(leader); @@ -1501,7 +1501,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable continue; } - if ((Rnd.get(100) < 10) && GeoData.getInstance().canSeeTarget(caster, targets)) + if ((Rnd.get(100) < 10) && GeoEngine.getInstance().canSeeTarget(caster, targets)) { clientStopMoving(null); caster.setTarget(obj); @@ -1530,7 +1530,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable } } } - if (canAura(sk) || (GeoData.getInstance().canSeeTarget(caster, attackTarget) && !attackTarget.isDead() && (dist2 <= srange))) + if (canAura(sk) || (GeoEngine.getInstance().canSeeTarget(caster, attackTarget) && !attackTarget.isDead() && (dist2 <= srange))) { clientStopMoving(null); caster.doCast(sk); @@ -1591,7 +1591,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable { for (Skill sk : npc.getTemplate().getAISkills(AISkillScope.IMMOBILIZE)) { - if (!checkSkillCastConditions(npc, sk) || (((sk.getCastRange() + npc.getTemplate().getCollisionRadius() + getAttackTarget().getTemplate().getCollisionRadius()) <= dist2) && !canAura(sk)) || !GeoData.getInstance().canSeeTarget(npc, getAttackTarget())) + if (!checkSkillCastConditions(npc, sk) || (((sk.getCastRange() + npc.getTemplate().getCollisionRadius() + getAttackTarget().getTemplate().getCollisionRadius()) <= dist2) && !canAura(sk)) || !GeoEngine.getInstance().canSeeTarget(npc, getAttackTarget())) { continue; } @@ -1609,7 +1609,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable { for (Skill sk : npc.getTemplate().getAISkills(AISkillScope.COT)) { - if (!checkSkillCastConditions(npc, sk) || (((sk.getCastRange() + npc.getTemplate().getCollisionRadius() + getAttackTarget().getTemplate().getCollisionRadius()) <= dist2) && !canAura(sk)) || !GeoData.getInstance().canSeeTarget(npc, getAttackTarget())) + if (!checkSkillCastConditions(npc, sk) || (((sk.getCastRange() + npc.getTemplate().getCollisionRadius() + getAttackTarget().getTemplate().getCollisionRadius()) <= dist2) && !canAura(sk)) || !GeoEngine.getInstance().canSeeTarget(npc, getAttackTarget())) { continue; } @@ -1626,7 +1626,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable { for (Skill sk : npc.getTemplate().getAISkills(AISkillScope.DEBUFF)) { - if (!checkSkillCastConditions(npc, sk) || (((sk.getCastRange() + npc.getTemplate().getCollisionRadius() + getAttackTarget().getTemplate().getCollisionRadius()) <= dist2) && !canAura(sk)) || !GeoData.getInstance().canSeeTarget(npc, getAttackTarget())) + if (!checkSkillCastConditions(npc, sk) || (((sk.getCastRange() + npc.getTemplate().getCollisionRadius() + getAttackTarget().getTemplate().getCollisionRadius()) <= dist2) && !canAura(sk)) || !GeoEngine.getInstance().canSeeTarget(npc, getAttackTarget())) { continue; } @@ -1644,7 +1644,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable { for (Skill sk : npc.getTemplate().getAISkills(AISkillScope.NEGATIVE)) { - if (!checkSkillCastConditions(npc, sk) || (((sk.getCastRange() + npc.getTemplate().getCollisionRadius() + getAttackTarget().getTemplate().getCollisionRadius()) <= dist2) && !canAura(sk)) || !GeoData.getInstance().canSeeTarget(npc, getAttackTarget())) + if (!checkSkillCastConditions(npc, sk) || (((sk.getCastRange() + npc.getTemplate().getCollisionRadius() + getAttackTarget().getTemplate().getCollisionRadius()) <= dist2) && !canAura(sk)) || !GeoEngine.getInstance().canSeeTarget(npc, getAttackTarget())) { continue; } @@ -1662,7 +1662,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable { for (Skill sk : npc.getTemplate().getAISkills(AISkillScope.ATTACK)) { - if (!checkSkillCastConditions(npc, sk) || (((sk.getCastRange() + npc.getTemplate().getCollisionRadius() + getAttackTarget().getTemplate().getCollisionRadius()) <= dist2) && !canAura(sk)) || !GeoData.getInstance().canSeeTarget(npc, getAttackTarget())) + if (!checkSkillCastConditions(npc, sk) || (((sk.getCastRange() + npc.getTemplate().getCollisionRadius() + getAttackTarget().getTemplate().getCollisionRadius()) <= dist2) && !canAura(sk)) || !GeoEngine.getInstance().canSeeTarget(npc, getAttackTarget())) { continue; } @@ -1685,7 +1685,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable { continue; } - if(!GeoData.getInstance().canSeeTarget(_actor,getAttackTarget())) + if(!GeoEngine.getInstance().canSeeTarget(_actor,getAttackTarget())) continue; clientStopMoving(null); L2Object target = getAttackTarget(); @@ -1712,7 +1712,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable // return; // } - if ((dist > range) || !GeoData.getInstance().canSeeTarget(npc, getAttackTarget())) + if ((dist > range) || !GeoEngine.getInstance().canSeeTarget(npc, getAttackTarget())) { if (getAttackTarget().isMoving()) { @@ -1784,7 +1784,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable for (L2Character obj : actor.getAttackByList()) { - if ((obj == null) || obj.isDead() || !GeoData.getInstance().canSeeTarget(actor, obj) || (obj == getAttackTarget())) + if ((obj == null) || obj.isDead() || !GeoEngine.getInstance().canSeeTarget(actor, obj) || (obj == getAttackTarget())) { continue; } @@ -1813,7 +1813,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable // If there is nearby Target with aggro, start going on random target that is attackable for (L2Character obj : actor.getKnownList().getKnownCharactersInRadius(range)) { - if (obj.isDead() || !GeoData.getInstance().canSeeTarget(actor, obj)) + if (obj.isDead() || !GeoEngine.getInstance().canSeeTarget(actor, obj)) { continue; } @@ -1846,7 +1846,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable int range = 0; for (L2Character obj : actor.getKnownList().getKnownCharactersInRadius(range)) { - if (!(obj instanceof L2Attackable) || obj.isDead() || !GeoData.getInstance().canSeeTarget(actor, obj)) + if (!(obj instanceof L2Attackable) || obj.isDead() || !GeoEngine.getInstance().canSeeTarget(actor, obj)) { continue; } @@ -1886,7 +1886,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable int range = sk.getCastRange() + actor.getTemplate().getCollisionRadius() + getAttackTarget().getTemplate().getCollisionRadius(); for (L2Character obj : actor.getKnownList().getKnownCharactersInRadius(range)) { - if ((obj == null) || obj.isDead() || !GeoData.getInstance().canSeeTarget(actor, obj)) + if ((obj == null) || obj.isDead() || !GeoEngine.getInstance().canSeeTarget(actor, obj)) { continue; } @@ -1925,7 +1925,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable { for (L2Character obj : actor.getHateList()) { - if ((obj == null) || !GeoData.getInstance().canSeeTarget(actor, obj) || obj.isDead()) + if ((obj == null) || !GeoEngine.getInstance().canSeeTarget(actor, obj) || obj.isDead()) { continue; } @@ -1967,7 +1967,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable continue; } final L2Character obj = target instanceof L2Character ? (L2Character) target : null; - if ((obj == null) || !GeoData.getInstance().canSeeTarget(actor, obj) || (dist2 > range)) + if ((obj == null) || !GeoEngine.getInstance().canSeeTarget(actor, obj) || (dist2 > range)) { continue; } @@ -2003,7 +2003,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable { for (L2Character obj : actor.getHateList()) { - if ((obj == null) || !GeoData.getInstance().canSeeTarget(actor, obj) || obj.isDead() || (obj != MostHate) || (obj == actor)) + if ((obj == null) || !GeoEngine.getInstance().canSeeTarget(actor, obj) || obj.isDead() || (obj != MostHate) || (obj == actor)) { continue; } @@ -2036,7 +2036,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable for (L2Object target : actor.getKnownList().getKnownObjects().values()) { final L2Character obj = target instanceof L2Character ? (L2Character) target : null; - if ((obj == null) || !GeoData.getInstance().canSeeTarget(actor, obj) || obj.isDead() || (obj != MostHate) || (obj == actor) || (obj == getAttackTarget())) + if ((obj == null) || !GeoEngine.getInstance().canSeeTarget(actor, obj) || obj.isDead() || (obj != MostHate) || (obj == actor) || (obj == getAttackTarget())) { continue; } @@ -2085,7 +2085,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable continue; } - if ((obj == null) || !GeoData.getInstance().canSeeTarget(actor, obj) || obj.isDead() || (obj == getAttackTarget()) || (obj == actor)) + if ((obj == null) || !GeoEngine.getInstance().canSeeTarget(actor, obj) || obj.isDead() || (obj == getAttackTarget()) || (obj == actor)) { continue; } @@ -2115,7 +2115,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable continue; } obj = (L2Character) target; - if (!GeoData.getInstance().canSeeTarget(actor, obj) || obj.isDead() || (obj != MostHate) || (obj == actor)) + if (!GeoEngine.getInstance().canSeeTarget(actor, obj) || obj.isDead() || (obj != MostHate) || (obj == actor)) { continue; } diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/ai/L2CharacterAI.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/ai/L2CharacterAI.java index 3c0c7ef1e6..7e23606285 100644 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/ai/L2CharacterAI.java +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/ai/L2CharacterAI.java @@ -33,7 +33,7 @@ import com.l2jmobius.Config; import com.l2jmobius.gameserver.GameTimeController; 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; @@ -911,7 +911,7 @@ public class L2CharacterAI extends AbstractAI } // If pathfinding enabled the creature will go to the destination or it will go to the nearest obstacle. - setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, Config.PATHFINDING > 0 ? GeoData.getInstance().moveCheck(_actor.getX(), _actor.getY(), _actor.getZ(), posX, posY, posZ, _actor.getInstanceId()) : new Location(posX, posY, posZ)); + setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, Config.PATHFINDING ? GeoEngine.getInstance().canMoveToTarget(_actor.getX(), _actor.getY(), _actor.getZ(), posX, posY, posZ, _actor.getInstanceId()) : new Location(posX, posY, posZ)); } protected boolean maybeMoveToPosition(ILocational worldPosition, int offset) @@ -1155,7 +1155,7 @@ public class L2CharacterAI extends AbstractAI ((L2PcInstance) target).stopFakeDeath(true); return false; } - if ((target != null) && ((_actor == null) || (_skill == null) || !_skill.isBad() || (_skill.getAffectRange() <= 0) || GeoData.getInstance().canSeeTarget(_actor, target))) + if ((target != null) && ((_actor == null) || (_skill == null) || !_skill.isBad() || (_skill.getAffectRange() <= 0) || GeoEngine.getInstance().canSeeTarget(_actor, target))) { return false; } @@ -1449,7 +1449,7 @@ public class L2CharacterAI extends AbstractAI boolean cancast = true; for (L2Character target : _actor.getKnownList().getKnownCharactersInRadius(sk.getAffectRange())) { - if (!GeoData.getInstance().canSeeTarget(_actor, target) || ((target instanceof L2Attackable) && !((L2Npc) _actor).isChaos())) + if (!GeoEngine.getInstance().canSeeTarget(_actor, target) || ((target instanceof L2Attackable) && !((L2Npc) _actor).isChaos())) { continue; } @@ -1468,7 +1468,7 @@ public class L2CharacterAI extends AbstractAI boolean cancast = true; for (L2Character target : getAttackTarget().getKnownList().getKnownCharactersInRadius(sk.getAffectRange())) { - if (!GeoData.getInstance().canSeeTarget(_actor, target) || (target == null) || ((target instanceof L2Attackable) && !((L2Npc) _actor).isChaos())) + if (!GeoEngine.getInstance().canSeeTarget(_actor, target) || (target == null) || ((target instanceof L2Attackable) && !((L2Npc) _actor).isChaos())) { continue; } @@ -1488,7 +1488,7 @@ public class L2CharacterAI extends AbstractAI boolean cancast = false; for (L2Character target : _actor.getKnownList().getKnownCharactersInRadius(sk.getAffectRange())) { - if (!GeoData.getInstance().canSeeTarget(_actor, target) || ((target instanceof L2Attackable) && !((L2Npc) _actor).isChaos())) + if (!GeoEngine.getInstance().canSeeTarget(_actor, target) || ((target instanceof L2Attackable) && !((L2Npc) _actor).isChaos())) { continue; } @@ -1507,7 +1507,7 @@ public class L2CharacterAI extends AbstractAI boolean cancast = true; for (L2Character target : getAttackTarget().getKnownList().getKnownCharactersInRadius(sk.getAffectRange())) { - if (!GeoData.getInstance().canSeeTarget(_actor, target) || ((target instanceof L2Attackable) && !((L2Npc) _actor).isChaos())) + if (!GeoEngine.getInstance().canSeeTarget(_actor, target) || ((target instanceof L2Attackable) && !((L2Npc) _actor).isChaos())) { continue; } @@ -1532,7 +1532,7 @@ public class L2CharacterAI extends AbstractAI int ccount = 0; for (L2Character target : _actor.getKnownList().getKnownCharactersInRadius(sk.getAffectRange())) { - if (!(target instanceof L2Attackable) || !GeoData.getInstance().canSeeTarget(_actor, target)) + if (!(target instanceof L2Attackable) || !GeoEngine.getInstance().canSeeTarget(_actor, target)) { continue; } diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/ai/L2FortSiegeGuardAI.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/ai/L2FortSiegeGuardAI.java index c2c767f7cc..9784e3eac6 100644 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/ai/L2FortSiegeGuardAI.java +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/ai/L2FortSiegeGuardAI.java @@ -26,7 +26,7 @@ import java.util.concurrent.Future; import com.l2jmobius.Config; 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.actor.L2Attackable; import com.l2jmobius.gameserver.model.actor.L2Character; @@ -154,7 +154,7 @@ public class L2FortSiegeGuardAI extends L2CharacterAI implements Runnable target = owner; } } - return (!(target instanceof L2Playable) || !((L2Playable) target).isSilentMovingAffected() || _actor.isInsideRadius(target, 250, false, false)) && _actor.isAutoAttackable(target) && GeoData.getInstance().canSeeTarget(_actor, target); + return (!(target instanceof L2Playable) || !((L2Playable) target).isSilentMovingAffected() || _actor.isInsideRadius(target, 250, false, false)) && _actor.isAutoAttackable(target) && GeoEngine.getInstance().canSeeTarget(_actor, target); } /** @@ -379,7 +379,7 @@ public class L2FortSiegeGuardAI extends L2CharacterAI implements Runnable { continue; } - if (!GeoData.getInstance().canSeeTarget(_actor, cha)) + if (!GeoEngine.getInstance().canSeeTarget(_actor, cha)) { break; } @@ -403,7 +403,7 @@ public class L2FortSiegeGuardAI extends L2CharacterAI implements Runnable if (npc.getAI() != null) // TODO: possibly check not needed { - if (!npc.isDead() && (Math.abs(target.getZ() - npc.getZ()) < 600) && ((npc.getAI()._intention == CtrlIntention.AI_INTENTION_IDLE) || (npc.getAI()._intention == CtrlIntention.AI_INTENTION_ACTIVE)) && target.isInsideRadius(npc, 1500, true, false) && GeoData.getInstance().canSeeTarget(npc, target)) + if (!npc.isDead() && (Math.abs(target.getZ() - npc.getZ()) < 600) && ((npc.getAI()._intention == CtrlIntention.AI_INTENTION_IDLE) || (npc.getAI()._intention == CtrlIntention.AI_INTENTION_ACTIVE)) && target.isInsideRadius(npc, 1500, true, false) && GeoEngine.getInstance().canSeeTarget(npc, target)) { // Notify the L2Object AI with EVT_AGGRESSION npc.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, getAttackTarget(), 1); @@ -423,7 +423,7 @@ public class L2FortSiegeGuardAI extends L2CharacterAI implements Runnable { continue; } - if (!GeoData.getInstance().canSeeTarget(_actor, npc)) + if (!GeoEngine.getInstance().canSeeTarget(_actor, npc)) { break; } diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/ai/L2SiegeGuardAI.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/ai/L2SiegeGuardAI.java index c8814eae0d..4f9ad29d37 100644 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/ai/L2SiegeGuardAI.java +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/ai/L2SiegeGuardAI.java @@ -26,7 +26,7 @@ import java.util.concurrent.Future; import com.l2jmobius.Config; 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.actor.L2Attackable; import com.l2jmobius.gameserver.model.actor.L2Character; @@ -152,7 +152,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)); } /** @@ -377,7 +377,7 @@ public class L2SiegeGuardAI extends L2CharacterAI implements Runnable { continue; } - if (!GeoData.getInstance().canSeeTarget(_actor, cha)) + if (!GeoEngine.getInstance().canSeeTarget(_actor, cha)) { break; } @@ -401,7 +401,7 @@ public class L2SiegeGuardAI extends L2CharacterAI implements Runnable if (npc.getAI() != null) // TODO: possibly check not needed { - if (!npc.isDead() && (Math.abs(target.getZ() - npc.getZ()) < 600) && ((npc.getAI()._intention == CtrlIntention.AI_INTENTION_IDLE) || (npc.getAI()._intention == CtrlIntention.AI_INTENTION_ACTIVE)) && target.isInsideRadius(npc, 1500, true, false) && GeoData.getInstance().canSeeTarget(npc, target)) + if (!npc.isDead() && (Math.abs(target.getZ() - npc.getZ()) < 600) && ((npc.getAI()._intention == CtrlIntention.AI_INTENTION_IDLE) || (npc.getAI()._intention == CtrlIntention.AI_INTENTION_ACTIVE)) && target.isInsideRadius(npc, 1500, true, false) && GeoEngine.getInstance().canSeeTarget(npc, target)) { // Notify the L2Object AI with EVT_AGGRESSION npc.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, getAttackTarget(), 1); @@ -421,7 +421,7 @@ public class L2SiegeGuardAI extends L2CharacterAI implements Runnable { continue; } - if (!GeoData.getInstance().canSeeTarget(_actor, npc)) + if (!GeoEngine.getInstance().canSeeTarget(_actor, npc)) { break; } @@ -474,7 +474,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 diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/ai/L2SummonAI.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/ai/L2SummonAI.java index cb38164ec2..312f5ed33f 100644 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/ai/L2SummonAI.java +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/ai/L2SummonAI.java @@ -24,8 +24,7 @@ import java.util.concurrent.Future; import com.l2jmobius.Config; import com.l2jmobius.gameserver.ThreadPoolManager; -import com.l2jmobius.gameserver.geodata.GeoData; -import com.l2jmobius.gameserver.geodata.pathfinding.PathFinding; +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; @@ -51,7 +50,7 @@ public class L2SummonAI extends L2PlayableAI implements Runnable @Override protected void onIntentionAttack(L2Character target) { - if ((Config.PATHFINDING > 0) && (PathFinding.getInstance().findPath(_actor.getX(), _actor.getY(), _actor.getZ(), target.getX(), target.getY(), target.getZ(), _actor.getInstanceId(), true) == null)) + if (Config.PATHFINDING && (GeoEngine.getInstance().findPath(_actor.getX(), _actor.getY(), _actor.getZ(), target.getX(), target.getY(), target.getZ(), _actor.getInstanceId(), true) == null)) { return; } @@ -250,7 +249,7 @@ public class L2SummonAI extends L2PlayableAI implements Runnable final double angle = Math.toRadians(Rnd.get(-90, 90)) + Math.atan2(ownerY - _actor.getY(), ownerX - _actor.getX()); 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.getX(), _actor.getY(), _actor.getZ(), targetX, targetY, _actor.getZ(), _actor.getInstanceId())) + if (GeoEngine.getInstance().canMoveToTarget(_actor.getX(), _actor.getY(), _actor.getZ(), targetX, targetY, _actor.getZ(), _actor.getInstanceId())) { moveTo(targetX, targetY, _actor.getZ()); } diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/data/xml/impl/DoorData.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/data/xml/impl/DoorData.java index b4f36afc42..470301b151 100644 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/data/xml/impl/DoorData.java +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/data/xml/impl/DoorData.java @@ -28,9 +28,9 @@ import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; -import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNodeLoc; import com.l2jmobius.gameserver.instancemanager.InstanceManager; 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; @@ -165,7 +165,7 @@ public class DoorData implements IXmlReader return _doors.values(); } - public boolean checkIfDoorsBetween(AbstractNodeLoc start, AbstractNodeLoc end, int instanceId) + public boolean checkIfDoorsBetween(Location start, Location end, int instanceId) { return checkIfDoorsBetween(start.getX(), start.getY(), start.getZ(), end.getX(), end.getY(), end.getZ(), instanceId); } diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/GeoData.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/GeoData.java deleted file mode 100644 index cfea59c619..0000000000 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/GeoData.java +++ /dev/null @@ -1,578 +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 . - */ -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.model.L2Object; -import com.l2jmobius.gameserver.model.L2World; -import com.l2jmobius.gameserver.model.Location; -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; - -/** - * Geodata. - * @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 getWorldX(int geoX) - { - return _driver.getWorldX(geoX); - } - - public int getWorldY(int geoY) - { - return _driver.getWorldY(geoY); - } - - // /////////////////// - // L2J METHODS - /** - * Gets the height. - * @param x the x coordinate - * @param y the y coordinate - * @param z the z coordinate - * @return the height - */ - public int getHeight(int x, int y, int z) - { - return getNearestZ(getGeoX(x), getGeoY(y), z); - } - - /** - * Gets the spawn height. - * @param x the x coordinate - * @param y the y coordinate - * @param z the the z coordinate - * @return the spawn height - */ - public int getSpawnHeight(int x, int y, int z) - { - final int geoX = getGeoX(x); - final int geoY = getGeoY(y); - - if (!hasGeoPos(geoX, geoY)) - { - return z; - } - - final int nextLowerZ = getNextLowerZ(geoX, geoY, z + 20); - return Math.abs(nextLowerZ - z) <= SPAWN_Z_DELTA_LIMIT ? nextLowerZ : z; - } - - /** - * Gets the spawn height. - * @param location the location - * @return the spawn height - */ - public int getSpawnHeight(Location location) - { - return getSpawnHeight(location.getX(), location.getY(), location.getZ()); - } - - /** - * Can see target. Doors as target always return true. Checks doors between. - * @param cha the character - * @param target the target - * @return {@code true} if the character can see the target (LOS), {@code false} otherwise - */ - public boolean canSeeTarget(L2Object cha, L2Object target) - { - return (target != null) && (target.isDoor() || canSeeTarget(cha.getX(), cha.getY(), cha.getZ(), cha.getInstanceId(), target.getX(), target.getY(), target.getZ(), target.getInstanceId())); - } - - /** - * Can see target. Checks doors between. - * @param cha the character - * @param worldPosition the world position - * @return {@code true} if the character can see the target at the given world position, {@code false} otherwise - */ - public boolean canSeeTarget(L2Object cha, ILocational worldPosition) - { - return canSeeTarget(cha.getX(), cha.getY(), cha.getZ(), cha.getInstanceId(), worldPosition.getX(), worldPosition.getY(), worldPosition.getZ()); - } - - /** - * Can see target. Checks doors between. - * @param x the x coordinate - * @param y the y coordinate - * @param z the z coordinate - * @param instanceId - * @param tx the target's x coordinate - * @param ty the target's y coordinate - * @param tz the target's z coordinate - * @param tInstanceId the target's instanceId - * @return - */ - public boolean canSeeTarget(int x, int y, int z, int instanceId, int tx, int ty, int tz, int tInstanceId) - { - return (instanceId == tInstanceId) && canSeeTarget(x, y, z, instanceId, tx, ty, tz); - } - - /** - * Can see target. Checks doors between. - * @param x the x coordinate - * @param y the y coordinate - * @param z the z coordinate - * @param instanceId - * @param tx the target's x coordinate - * @param ty the target's y coordinate - * @param tz the target's z coordinate - * @return {@code true} if there is line of sight between the given coordinate sets, {@code false} otherwise - */ - public boolean canSeeTarget(int x, int y, int z, int instanceId, int tx, int ty, int tz) - { - return !DoorData.getInstance().checkIfDoorsBetween(x, y, z, tx, ty, tz, instanceId, true); - } - - 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!"); - } - return checkNearestNsweAntiCornerCut(prevX, prevY, prevGeoZ, nswe) ? getNearestZ(curX, curY, prevGeoZ) : 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)) - { - return !hasGeoPos(tGeoX, tGeoY) || (z == tz); - } - - 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 nswe = GeoUtils.computeNswe(prevX, prevY, curX, curY); - curGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, curX, curY, nswe); - final int maxHeight = ptIndex < ELEVATED_SEE_OVER_DISTANCE ? z + MAX_SEE_OVER_HEIGHT : beeCurZ + MAX_SEE_OVER_HEIGHT; - boolean canSeeThrough = false; - if (curGeoZ <= maxHeight) - { - 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; - } - - /** - * Verifies if the is a path between origin's location and destination, if not returns the closest location. - * @param origin the origin - * @param destination the destination - * @return the destination if there is a path or the closes location - */ - public Location moveCheck(ILocational origin, ILocational destination) - { - return moveCheck(origin.getX(), origin.getY(), origin.getZ(), destination.getX(), destination.getY(), destination.getZ(), origin.getInstanceId()); - } - - /** - * Move check. - * @param x the x coordinate - * @param y the y coordinate - * @param z the z coordinate - * @param tx the target's x coordinate - * @param ty the target's y coordinate - * @param tz the target's z coordinate - * @param instanceId the instance id - * @return the last Location (x,y,z) where player can walk - just before wall - */ - public Location moveCheck(int x, int y, int z, int tx, int ty, int tz, int instanceId) - { - 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, instanceId, false)) - { - 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) && !checkNearestNsweAntiCornerCut(prevX, prevY, prevZ, GeoUtils.computeNswe(prevX, prevY, curX, curY))) - { - // can't move, return previous location - return new Location(getWorldX(prevX), getWorldY(prevY), prevZ); - } - prevX = curX; - prevY = curY; - prevZ = curZ; - } - return hasGeoPos(prevX, prevY) && (prevZ != tz) ? new Location(x, y, z) : new Location(tx, ty, tz); - } - - /** - * Checks if its possible to move from one location to another. - * @param fromX the X coordinate to start checking from - * @param fromY the Y coordinate to start checking from - * @param fromZ the Z coordinate to start checking from - * @param toX the X coordinate to end checking at - * @param toY the Y coordinate to end checking at - * @param toZ the Z coordinate to end checking at - * @param instanceId the instance ID - * @return {@code true} if the character at start coordinates can move to end coordinates, {@code false} otherwise - */ - public boolean canMove(int fromX, int fromY, int fromZ, int toX, int toY, int toZ, int instanceId) - { - 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, instanceId, false)) - { - 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) && !checkNearestNsweAntiCornerCut(prevX, prevY, prevZ, GeoUtils.computeNswe(prevX, prevY, curX, curY))) - { - { - return false; - } - } - prevX = curX; - prevY = curY; - prevZ = curZ; - } - return !hasGeoPos(prevX, prevY) || (prevZ == toZ); - } - - public int traceTerrainZ(int x, int y, int z, int tx, int ty) - { - final int geoX = getGeoX(x); - final int geoY = getGeoY(y); - z = getNearestZ(geoX, geoY, z); - final int tGeoX = getGeoX(tx); - final int tGeoY = getGeoY(ty); - - final LinePointIterator pointIter = new LinePointIterator(geoX, geoY, tGeoX, tGeoY); - // first point is guaranteed to be available - pointIter.next(); - int prevZ = z; - - while (pointIter.next()) - { - prevZ = getNearestZ(pointIter.x(), pointIter.y(), prevZ); - } - - return prevZ; - } - - /** - * Checks if its possible to move from one location to another. - * @param from the {@code ILocational} to start checking from - * @param toX the X coordinate to end checking at - * @param toY the Y coordinate to end checking at - * @param toZ the Z coordinate to end checking at - * @return {@code true} if the character at start coordinates can move to end coordinates, {@code false} otherwise - */ - public boolean canMove(ILocational from, int toX, int toY, int toZ) - { - return canMove(from.getX(), from.getY(), from.getZ(), toX, toY, toZ, from.getInstanceId()); - } - - /** - * Checks if its possible to move from one location to another. - * @param from the {@code ILocational} to start checking from - * @param to the {@code ILocational} to end checking at - * @return {@code true} if the character at start coordinates can move to end coordinates, {@code false} otherwise - */ - public boolean canMove(ILocational from, ILocational to) - { - return canMove(from, to.getX(), to.getY(), to.getZ()); - } - - /** - * Checks the specified position for available geodata. - * @param x the X coordinate - * @param y the Y coordinate - * @return {@code true} if there is geodata for the given coordinates, {@code false} otherwise - */ - public boolean hasGeo(int x, int y) - { - return hasGeoPos(getGeoX(x), getGeoY(y)); - } - - public static GeoData getInstance() - { - return SingletonHolder._instance; - } - - private static class SingletonHolder - { - protected static final GeoData _instance = new GeoData(); - } -} diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/Cell.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/Cell.java deleted file mode 100644 index 4914b1d72e..0000000000 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/Cell.java +++ /dev/null @@ -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 . - */ -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() - { - } -} diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/GeoDriver.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/GeoDriver.java deleted file mode 100644 index 619358fd24..0000000000 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/GeoDriver.java +++ /dev/null @@ -1,162 +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 . - */ -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; - - /** 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; - - /** The regions array */ - private final AtomicReferenceArray _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 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()).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 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; - } -} diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/IBlock.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/IBlock.java deleted file mode 100644 index 21df97c40d..0000000000 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/IBlock.java +++ /dev/null @@ -1,42 +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 . - */ -package com.l2jmobius.gameserver.geodata.geodriver; - -/** - * @author HorridoJoho - */ -public interface IBlock -{ - int TYPE_FLAT = 0; - int TYPE_COMPLEX = 1; - int TYPE_MULTILAYER = 2; - - /** Cells in a block on the x axis */ - int BLOCK_CELLS_X = 8; - /** Cells in a block on the y axis */ - int BLOCK_CELLS_Y = 8; - /** Cells in a block */ - int BLOCK_CELLS = BLOCK_CELLS_X * BLOCK_CELLS_Y; - - boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe); - - int getNearestZ(int geoX, int geoY, int worldZ); - - int getNextLowerZ(int geoX, int geoY, int worldZ); - - int getNextHigherZ(int geoX, int geoY, int worldZ); -} diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/IRegion.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/IRegion.java deleted file mode 100644 index 3eb23da03e..0000000000 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/IRegion.java +++ /dev/null @@ -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 . - */ -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(); -} diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/ComplexBlock.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/ComplexBlock.java deleted file mode 100644 index 4d6410672e..0000000000 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/ComplexBlock.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/FlatBlock.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/FlatBlock.java deleted file mode 100644 index d5bcff094b..0000000000 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/FlatBlock.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/MultilayerBlock.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/MultilayerBlock.java deleted file mode 100644 index 313131bd5a..0000000000 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/MultilayerBlock.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/regions/NullRegion.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/regions/NullRegion.java deleted file mode 100644 index 60ecac873a..0000000000 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/regions/NullRegion.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/regions/Region.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/regions/Region.java deleted file mode 100644 index d2d02481ed..0000000000 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/geodriver/regions/Region.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNode.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNode.java deleted file mode 100644 index 40f58ccba0..0000000000 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNode.java +++ /dev/null @@ -1,84 +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 . - */ -package com.l2jmobius.gameserver.geodata.pathfinding; - -public abstract class AbstractNode -{ - private Loc _loc; - private AbstractNode _parent; - - public AbstractNode(Loc loc) - { - _loc = loc; - } - - public void setParent(AbstractNode p) - { - _parent = p; - } - - public AbstractNode getParent() - { - return _parent; - } - - public Loc getLoc() - { - return _loc; - } - - public void setLoc(Loc l) - { - _loc = l; - } - - @Override - public int hashCode() - { - return (31 * 1) + ((_loc == null) ? 0 : _loc.hashCode()); - } - - @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; - } -} \ No newline at end of file diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/PathFinding.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/PathFinding.java deleted file mode 100644 index a9f3a1169a..0000000000 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/PathFinding.java +++ /dev/null @@ -1,204 +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 . - */ -package com.l2jmobius.gameserver.geodata.pathfinding; - -import java.util.List; - -import com.l2jmobius.Config; -import com.l2jmobius.gameserver.geodata.pathfinding.cellnodes.CellPathFinding; -import com.l2jmobius.gameserver.geodata.pathfinding.geonodes.GeoPathFinding; -import com.l2jmobius.gameserver.model.L2World; - -/** - * @author -Nemesiss- - */ -public abstract class PathFinding -{ - public static PathFinding getInstance() - { - return Config.PATHFINDING == 1 ? GeoPathFinding.getInstance() : CellPathFinding.getInstance(); - } - - public abstract boolean pathNodesExist(short regionoffset); - - public abstract List findPath(int x, int y, int z, int tx, int ty, int tz, int instanceId, boolean playable); - - // @formatter:off - /* - public List 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 visited = new LinkedList(); - - // List of Nodes to Visit - LinkedList to_visit = new LinkedList(); - 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 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; - } -} diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNode.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNode.java deleted file mode 100644 index f903507286..0000000000 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNode.java +++ /dev/null @@ -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 . - */ -package com.l2jmobius.gameserver.geodata.pathfinding.cellnodes; - -import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNode; - -public class CellNode extends AbstractNode -{ - 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; - } -} \ No newline at end of file diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNodeBuffer.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNodeBuffer.java deleted file mode 100644 index c4b60ab8bb..0000000000 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNodeBuffer.java +++ /dev/null @@ -1,335 +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 . - */ -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 debugPath() - { - final List 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 final void getNeighbors() - { - if (_current.getLoc().canGoNone()) - { - 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) - { - return; - } - - // SouthEast - if ((nodeE != null) && (nodeS != null) && nodeE.getLoc().canGoSouth() && nodeS.getLoc().canGoEast()) - { - addNode(x + 1, y + 1, z, true); - } - - // SouthWest - if ((nodeS != null) && (nodeW != null) && nodeW.getLoc().canGoSouth() && nodeS.getLoc().canGoWest()) - { - addNode(x - 1, y + 1, z, true); - } - - // NorthEast - if ((nodeN != null) && (nodeE != null) && nodeE.getLoc().canGoNorth() && nodeN.getLoc().canGoEast()) - { - addNode(x + 1, y - 1, z, true); - } - - // NorthWest - if ((nodeN != null) && (nodeW != null) && nodeW.getLoc().canGoNorth() && nodeN.getLoc().canGoWest()) - { - addNode(x - 1, y - 1, z, true); - } - } - - private final 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 final 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 final boolean isHighWeight(int x, int y, int z) - { - final CellNode result = getNode(x, y, z); - return (result == null) || !result.getLoc().canGoAll() || (Math.abs(result.getLoc().getZ() - z) > 16); - } - - private final 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; - } -} \ No newline at end of file diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellPathFinding.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellPathFinding.java deleted file mode 100644 index 34aa54aeeb..0000000000 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellPathFinding.java +++ /dev/null @@ -1,429 +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 . - */ -package com.l2jmobius.gameserver.geodata.pathfinding.cellnodes; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -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.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 _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 findPath(int x, int y, int z, int tx, int ty, int tz, int instanceId, 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) - { - item.decayMe(); - } - - _debugItems.clear(); - } - } - - List 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++; - } - - boolean remove; - int pass = 0; - do - { - pass++; - _postFilterPasses++; - - remove = false; - final Iterator endPoint = path.iterator(); - endPoint.next(); - int currentX = x; - int currentY = y; - int currentZ = z; - - int midPoint = 0; - while (endPoint.hasNext()) - { - final AbstractNodeLoc locMiddle = path.get(midPoint); - final AbstractNodeLoc locEnd = endPoint.next(); - if (GeoData.getInstance().canMove(currentX, currentY, currentZ, locEnd.getX(), locEnd.getY(), locEnd.getZ(), instanceId)) - { - path.remove(midPoint); - remove = true; - if (debug) - { - dropDebugItem(735, 1, locMiddle); - } - } - else - { - currentX = locMiddle.getX(); - currentY = locMiddle.getY(); - currentZ = locMiddle.getZ(); - midPoint++; - } - } - } - // 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 constructPath(AbstractNode node) - { - final List path = new CopyOnWriteArrayList<>(); - 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.add(0, node.getLoc()); - node.setLoc(null); - } - - node = node.getParent(); - } - return path; - } - - private final 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 final 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; - List 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(); - } -} diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/NodeLoc.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/NodeLoc.java deleted file mode 100644 index 7fd25fbc18..0000000000 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/NodeLoc.java +++ /dev/null @@ -1,167 +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 . - */ -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 canGoNone() - { - return !canGoNorth() && !canGoEast() && !canGoSouth() && !canGoWest(); - } - - 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 void setZ(short 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; - - 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; - return (_x == other._x) && (_y == other._y) && (!_goNorth == !other._goNorth) && (!_goEast == !other._goEast) && (!_goSouth == !other._goSouth) && (!_goWest == !other._goWest) && (_geoHeight == other._geoHeight); - } -} diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNode.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNode.java deleted file mode 100644 index b6a75b0ad3..0000000000 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNode.java +++ /dev/null @@ -1,60 +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 . - */ -package com.l2jmobius.gameserver.geodata.pathfinding.geonodes; - -import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNode; - -/** - * @author -Nemesiss- - */ -public class GeoNode extends AbstractNode -{ - 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(GeoNode[] neighbors) - { - _neighbors = neighbors; - } - - public int getNeighborsIdx() - { - return _neighborsIdx; - } -} diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNodeLoc.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNodeLoc.java deleted file mode 100644 index 48b965379a..0000000000 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNodeLoc.java +++ /dev/null @@ -1,103 +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 . - */ -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 void setZ(short 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; - return (_x == other._x) && (_y == other._y) && (_z == other._z); - } -} diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoPathFinding.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoPathFinding.java deleted file mode 100644 index 762cadbb73..0000000000 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoPathFinding.java +++ /dev/null @@ -1,473 +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 . - */ -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.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -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.geodata.pathfinding.utils.FastNodeList; -import com.l2jmobius.gameserver.model.L2World; -import com.l2jmobius.gameserver.model.Location; -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 _pathNodes = new HashMap<>(); - private static Map _pathNodesIndex = new HashMap<>(); - - public static GeoPathFinding getInstance() - { - return SingletonHolder._instance; - } - - @Override - public boolean pathNodesExist(short regionoffset) - { - return _pathNodesIndex.containsKey(regionoffset); - } - - @Override - public List findPath(int x, int y, int z, int tx, int ty, int tz, int instanceId, 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(), instanceId); - 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(), instanceId); - 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 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 FastNodeList visited = new FastNodeList(550); - - // List of Nodes to Visit - final LinkedList 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(readNeighbors(node)); - final GeoNode[] neighbors = node.getNeighbors(); - if (neighbors == null) - { - continue; - } - for (GeoNode n : neighbors) - { - if (!visited.containsRev(n) && !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 constructPath2(AbstractNode node) - { - final LinkedList 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; - } - - private GeoNode[] readNeighbors(GeoNode n) - { - if (n.getLoc() == null) - { - return null; - } - - int idx = n.getNeighborsIdx(); - - 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> 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); - } - } - return neighbors.toArray(new GeoNode[neighbors.size()]); - } - - // 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(Config.PATHNODE_PATH.resolve("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; - } - - LoadPathNodeFile(Byte.parseByte(parts[0]), Byte.parseByte(parts[1])); - }); - //@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_PATH.toString(), 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(); - } -} diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/utils/BinaryNodeHeap.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/utils/BinaryNodeHeap.java deleted file mode 100644 index 665977f686..0000000000 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/utils/BinaryNodeHeap.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/utils/FastNodeList.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/utils/FastNodeList.java deleted file mode 100644 index 535678abbd..0000000000 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geodata/pathfinding/utils/FastNodeList.java +++ /dev/null @@ -1,49 +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 . - */ -package com.l2jmobius.gameserver.geodata.pathfinding.utils; - -import java.util.ArrayList; - -import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNode; - -/** - * @author -Nemesiss- - */ -public class FastNodeList -{ - private final ArrayList> _list; - - public FastNodeList(int size) - { - _list = new ArrayList<>(size); - } - - public void add(AbstractNode n) - { - _list.add(n); - } - - public boolean contains(AbstractNode n) - { - return _list.contains(n); - } - - public boolean containsRev(AbstractNode n) - { - return _list.lastIndexOf(n) != -1; - } -} diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java new file mode 100644 index 0000000000..da32a225aa --- /dev/null +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java @@ -0,0 +1,1294 @@ +/* + * 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 . + */ +package com.l2jmobius.gameserver.geoengine; + +import java.io.File; +import java.io.RandomAccessFile; +import java.nio.ByteOrder; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.util.List; +import java.util.logging.Logger; + +import com.l2jmobius.Config; +import com.l2jmobius.gameserver.data.xml.impl.DoorData; +import com.l2jmobius.gameserver.geoengine.geodata.ABlock; +import com.l2jmobius.gameserver.geoengine.geodata.BlockComplex; +import com.l2jmobius.gameserver.geoengine.geodata.BlockComplexDynamic; +import com.l2jmobius.gameserver.geoengine.geodata.BlockFlat; +import com.l2jmobius.gameserver.geoengine.geodata.BlockMultilayer; +import com.l2jmobius.gameserver.geoengine.geodata.BlockMultilayerDynamic; +import com.l2jmobius.gameserver.geoengine.geodata.BlockNull; +import com.l2jmobius.gameserver.geoengine.geodata.GeoFormat; +import com.l2jmobius.gameserver.geoengine.geodata.GeoLocation; +import com.l2jmobius.gameserver.geoengine.geodata.GeoStructure; +import com.l2jmobius.gameserver.geoengine.geodata.IBlockDynamic; +import com.l2jmobius.gameserver.geoengine.geodata.IGeoObject; +import com.l2jmobius.gameserver.model.L2Object; +import com.l2jmobius.gameserver.model.L2World; +import com.l2jmobius.gameserver.model.Location; +import com.l2jmobius.gameserver.model.actor.L2Character; +import com.l2jmobius.gameserver.model.actor.instance.L2DoorInstance; +import com.l2jmobius.gameserver.util.MathUtil; + +/** + * @author Hasha + */ +public class GeoEngine +{ + protected static final Logger _log = Logger.getLogger(GeoEngine.class.getName()); + + private final ABlock[][] _blocks; + private final BlockNull _nullBlock; + + /** + * Returns the instance of the {@link GeoEngine}. + * @return {@link GeoEngine} : The instance. + */ + public static final GeoEngine getInstance() + { + return SingletonHolder._instance; + } + + /** + * GeoEngine contructor. Loads all geodata files of chosen geodata format. + */ + public GeoEngine() + { + _log.info("GeoEngine: Initializing..."); + + // initialize block container + _blocks = new ABlock[GeoStructure.GEO_BLOCKS_X][GeoStructure.GEO_BLOCKS_Y]; + + // load null block + _nullBlock = new BlockNull(); + + // initialize multilayer temporarily buffer + BlockMultilayer.initialize(); + + // load geo files according to geoengine config setup + int loaded = 0; + int failed = 0; + for (int rx = L2World.TILE_X_MIN; rx <= L2World.TILE_X_MAX; rx++) + { + for (int ry = L2World.TILE_Y_MIN; ry <= L2World.TILE_Y_MAX; ry++) + { + final String filename = String.format(GeoFormat.L2D.getFilename(), rx, ry); + final String filepath = Config.GEODATA_PATH; + File f = new File(filepath + filename); + if (f.exists() && !f.isDirectory()) + { + // region file is load-able, try to load it + if (loadGeoBlocks(rx, ry)) + { + loaded++; + } + else + { + failed++; + } + } + else + { + // region file is not load-able, load null blocks + loadNullBlocks(rx, ry); + } + } + } + _log.info("GeoEngine: Loaded " + loaded + " L2D region files."); + + // Avoid wrong config when no files loaded + if ((loaded == 0) && (Config.COORD_SYNCHRONIZE == 2)) + { + Config.COORD_SYNCHRONIZE = -1; + _log.info("GeoEngine: Forcing CoordSynchronize setting to -1."); + } + + // release multilayer block temporarily buffer + BlockMultilayer.release(); + + if (failed > 0) + { + _log.info("GeoEngine: Failed to load " + failed + " L2D region files. Please consider to check your \"GeoEngine.ini\" settings and location of \"XX_YY.L2D\" geodata files."); + System.exit(1); + } + } + + /** + * Loads geodata from a file. When file does not exist, is corrupted or not consistent, loads none geodata. + * @param regionX : Geodata file region X coordinate. + * @param regionY : Geodata file region Y coordinate. + * @return boolean : True, when geodata file was loaded without problem. + */ + private final boolean loadGeoBlocks(int regionX, int regionY) + { + final String filename = String.format(GeoFormat.L2D.getFilename(), regionX, regionY); + final String filepath = Config.GEODATA_PATH + filename; + + // standard load + try (RandomAccessFile raf = new RandomAccessFile(filepath, "r"); + FileChannel fc = raf.getChannel()) + { + // initialize file buffer + MappedByteBuffer buffer = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()).load(); + buffer.order(ByteOrder.LITTLE_ENDIAN); + + // get block indexes + final int blockX = (regionX - L2World.TILE_X_MIN) * GeoStructure.REGION_BLOCKS_X; + final int blockY = (regionY - L2World.TILE_Y_MIN) * GeoStructure.REGION_BLOCKS_Y; + + // loop over region blocks + for (int ix = 0; ix < GeoStructure.REGION_BLOCKS_X; ix++) + { + for (int iy = 0; iy < GeoStructure.REGION_BLOCKS_Y; iy++) + { + // get block type + final byte type = buffer.get(); + + // load block according to block type + switch (type) + { + case GeoStructure.TYPE_FLAT_L2D: + _blocks[blockX + ix][blockY + iy] = new BlockFlat(buffer, GeoFormat.L2D); + break; + + case GeoStructure.TYPE_COMPLEX_L2D: + _blocks[blockX + ix][blockY + iy] = new BlockComplex(buffer, GeoFormat.L2D); + break; + + case GeoStructure.TYPE_MULTILAYER_L2D: + _blocks[blockX + ix][blockY + iy] = new BlockMultilayer(buffer, GeoFormat.L2D); + break; + + default: + throw new IllegalArgumentException("Unknown block type: " + type); + } + } + } + + // check data consistency + if (buffer.remaining() > 0) + { + _log.warning("GeoEngine: Region file " + filename + " can be corrupted, remaining " + buffer.remaining() + " bytes to read."); + } + + // loading was successful + return true; + } + catch (Exception e) + { + // an error occured while loading, load null blocks + _log.warning("GeoEngine: Error while loading " + filename + " region file."); + _log.warning(e.getMessage()); + e.printStackTrace(); + + // replace whole region file with null blocks + loadNullBlocks(regionX, regionY); + + // loading was not successful + return false; + } + } + + /** + * Loads null blocks. Used when no region file is detected or an error occurs during loading. + * @param regionX : Geodata file region X coordinate. + * @param regionY : Geodata file region Y coordinate. + */ + private final void loadNullBlocks(int regionX, int regionY) + { + // get block indexes + final int blockX = (regionX - L2World.TILE_X_MIN) * GeoStructure.REGION_BLOCKS_X; + final int blockY = (regionY - L2World.TILE_Y_MIN) * GeoStructure.REGION_BLOCKS_Y; + + // load all null blocks + for (int ix = 0; ix < GeoStructure.REGION_BLOCKS_X; ix++) + { + for (int iy = 0; iy < GeoStructure.REGION_BLOCKS_Y; iy++) + { + _blocks[blockX + ix][blockY + iy] = _nullBlock; + } + } + } + + // GEODATA - GENERAL + + /** + * Converts world X to geodata X. + * @param worldX + * @return int : Geo X + */ + public final int getGeoX(int worldX) + { + return (MathUtil.limit(worldX, L2World.MAP_MIN_X, L2World.MAP_MAX_X) - L2World.MAP_MIN_X) >> 4; + } + + /** + * Converts world Y to geodata Y. + * @param worldY + * @return int : Geo Y + */ + public final int getGeoY(int worldY) + { + return (MathUtil.limit(worldY, L2World.MAP_MIN_Y, L2World.MAP_MAX_Y) - L2World.MAP_MIN_Y) >> 4; + } + + /** + * Converts geodata X to world X. + * @param geoX + * @return int : World X + */ + public final int getWorldX(int geoX) + { + return (MathUtil.limit(geoX, 0, GeoStructure.GEO_CELLS_X) << 4) + L2World.MAP_MIN_X + 8; + } + + /** + * Converts geodata Y to world Y. + * @param geoY + * @return int : World Y + */ + public final int getWorldY(int geoY) + { + return (MathUtil.limit(geoY, 0, GeoStructure.GEO_CELLS_Y) << 4) + L2World.MAP_MIN_Y + 8; + } + + /** + * Returns block of geodata on given coordinates. + * @param geoX : Geodata X + * @param geoY : Geodata Y + * @return {@link ABlock} : Bloack of geodata. + */ + public final ABlock getBlock(int geoX, int geoY) + { + return _blocks[geoX / GeoStructure.BLOCK_CELLS_X][geoY / GeoStructure.BLOCK_CELLS_Y]; + } + + /** + * Check if geo coordinates has geo. + * @param geoX : Geodata X + * @param geoY : Geodata Y + * @return boolean : True, if given geo coordinates have geodata + */ + public final boolean hasGeoPos(int geoX, int geoY) + { + return getBlock(geoX, geoY).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, closest to given coordinates. + */ + public final short getHeightNearest(int geoX, int geoY, int worldZ) + { + return getBlock(geoX, geoY).getHeightNearest(geoX, geoY, worldZ); + } + + /** + * Returns the height of cell, which is closest to given coordinates.
+ * 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, closest to given coordinates. + */ + public final short getHeightNearestOriginal(int geoX, int geoY, int worldZ) + { + return getBlock(geoX, geoY).getHeightNearestOriginal(geoX, geoY, worldZ); + } + + /** + * Returns the NSWE flag byte of cell, which is closes 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 coordinate, closest to given coordinates. + */ + public final byte getNsweNearest(int geoX, int geoY, int worldZ) + { + return getBlock(geoX, geoY).getNsweNearest(geoX, geoY, worldZ); + } + + /** + * Returns the NSWE flag byte of cell, which is closes to given coordinates.
+ * 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 coordinate, closest to given coordinates. + */ + public final byte getNsweNearestOriginal(int geoX, int geoY, int worldZ) + { + return getBlock(geoX, geoY).getNsweNearestOriginal(geoX, geoY, worldZ); + } + + /** + * Check if world coordinates has geo. + * @param worldX : World X + * @param worldY : World Y + * @return boolean : True, if given world coordinates have geodata + */ + public final boolean hasGeo(int worldX, int worldY) + { + return hasGeoPos(getGeoX(worldX), getGeoY(worldY)); + } + + /** + * Returns closest Z coordinate according to geodata. + * @param worldX : world x + * @param worldY : world y + * @param worldZ : world z + * @return short : nearest Z coordinates according to geodata + */ + public final short getHeight(int worldX, int worldY, int worldZ) + { + return getHeightNearest(getGeoX(worldX), getGeoY(worldY), worldZ); + } + + // GEODATA - DYNAMIC + + /** + * Returns calculated NSWE flag byte as a description of {@link IGeoObject}.
+ * The {@link IGeoObject} is defined by boolean 2D array, saying if the object is present on given cell or not. + * @param inside : 2D description of {@link IGeoObject} + * @return byte[][] : Returns NSWE flags of {@link IGeoObject}. + */ + public static final byte[][] calculateGeoObject(boolean inside[][]) + { + // get dimensions + final int width = inside.length; + final int height = inside[0].length; + + // create object flags for geodata, according to the geo object 2D description + final byte[][] result = new byte[width][height]; + + // loop over each cell of the geo object + for (int ix = 0; ix < width; ix++) + { + for (int iy = 0; iy < height; iy++) + { + if (inside[ix][iy]) + { + // cell is inside geo object, block whole movement (nswe = 0) + result[ix][iy] = 0; + } + else + { + // cell is outside of geo object, block only movement leading inside geo object + + // set initial value -> no geodata change + byte nswe = (byte) 0xFF; + + // perform axial and diagonal checks + if (iy < (height - 1)) + { + if (inside[ix][iy + 1]) + { + nswe &= ~GeoStructure.CELL_FLAG_S; + } + } + if (iy > 0) + { + if (inside[ix][iy - 1]) + { + nswe &= ~GeoStructure.CELL_FLAG_N; + } + } + if (ix < (width - 1)) + { + if (inside[ix + 1][iy]) + { + nswe &= ~GeoStructure.CELL_FLAG_E; + } + } + if (ix > 0) + { + if (inside[ix - 1][iy]) + { + nswe &= ~GeoStructure.CELL_FLAG_W; + } + } + if ((ix < (width - 1)) && (iy < (height - 1))) + { + if (inside[ix + 1][iy + 1] || inside[ix][iy + 1] || inside[ix + 1][iy]) + { + nswe &= ~GeoStructure.CELL_FLAG_SE; + } + } + if ((ix < (width - 1)) && (iy > 0)) + { + if (inside[ix + 1][iy - 1] || inside[ix][iy - 1] || inside[ix + 1][iy]) + { + nswe &= ~GeoStructure.CELL_FLAG_NE; + } + } + if ((ix > 0) && (iy < (height - 1))) + { + if (inside[ix - 1][iy + 1] || inside[ix][iy + 1] || inside[ix - 1][iy]) + { + nswe &= ~GeoStructure.CELL_FLAG_SW; + } + } + if ((ix > 0) && (iy > 0)) + { + if (inside[ix - 1][iy - 1] || inside[ix][iy - 1] || inside[ix - 1][iy]) + { + nswe &= ~GeoStructure.CELL_FLAG_NW; + } + } + + result[ix][iy] = nswe; + } + } + } + + return result; + } + + /** + * Add {@link IGeoObject} to the geodata. + * @param object : An object using {@link IGeoObject} interface. + */ + public final void addGeoObject(IGeoObject object) + { + toggleGeoObject(object, true); + } + + /** + * Remove {@link IGeoObject} from the geodata. + * @param object : An object using {@link IGeoObject} interface. + */ + public final void removeGeoObject(IGeoObject object) + { + toggleGeoObject(object, false); + } + + /** + * Toggles an {@link IGeoObject} in the geodata. + * @param object : An object using {@link IGeoObject} interface. + * @param add : Add/remove object. + */ + private final void toggleGeoObject(IGeoObject object, boolean add) + { + // get object geo coordinates and data + final int minGX = object.getGeoX(); + final int minGY = object.getGeoY(); + final byte[][] geoData = object.getObjectGeoData(); + + // get min/max block coordinates + int minBX = minGX / GeoStructure.BLOCK_CELLS_X; + int maxBX = ((minGX + geoData.length) - 1) / GeoStructure.BLOCK_CELLS_X; + int minBY = minGY / GeoStructure.BLOCK_CELLS_Y; + int maxBY = ((minGY + geoData[0].length) - 1) / GeoStructure.BLOCK_CELLS_Y; + + // loop over affected blocks in X direction + for (int bx = minBX; bx <= maxBX; bx++) + { + // loop over affected blocks in Y direction + for (int by = minBY; by <= maxBY; by++) + { + ABlock block; + + // conversion to dynamic block must be synchronized to prevent 2 independent threads converting same block + synchronized (_blocks) + { + // get related block + block = _blocks[bx][by]; + + // check for dynamic block + if (!(block instanceof IBlockDynamic)) + { + // null block means no geodata (particular region file is not loaded), no geodata means no geobjects + if (block instanceof BlockNull) + { + continue; + } + + // not a dynamic block, convert it + if (block instanceof BlockFlat) + { + // convert flat block to the dynamic complex block + block = new BlockComplexDynamic(bx, by, (BlockFlat) block); + _blocks[bx][by] = block; + } + else if (block instanceof BlockComplex) + { + // convert complex block to the dynamic complex block + block = new BlockComplexDynamic(bx, by, (BlockComplex) block); + _blocks[bx][by] = block; + } + else if (block instanceof BlockMultilayer) + { + // convert multilayer block to the dynamic multilayer block + block = new BlockMultilayerDynamic(bx, by, (BlockMultilayer) block); + _blocks[bx][by] = block; + } + } + } + + // add/remove geo object to/from dynamic block + if (add) + { + ((IBlockDynamic) block).addGeoObject(object); + } + else + { + ((IBlockDynamic) block).removeGeoObject(object); + } + } + } + } + + // PATHFINDING + + /** + * Check line of sight from {@link L2Object} to {@link L2Object}. + * @param origin : The origin object. + * @param target : The target object. + * @return {@code boolean} : True if origin can see target + */ + public final boolean canSeeTarget(L2Object origin, L2Object target) + { + // get origin and target world coordinates + final int ox = origin.getX(); + final int oy = origin.getY(); + final int oz = origin.getZ(); + final int tx = target.getX(); + final int ty = target.getY(); + final int tz = target.getZ(); + + // get origin and check existing geo coordinates + final int gox = getGeoX(ox); + final int goy = getGeoY(oy); + if (!hasGeoPos(gox, goy)) + { + return true; + } + + final short goz = getHeightNearest(gox, goy, oz); + + // get target and check existing geo coordinates + final int gtx = getGeoX(tx); + final int gty = getGeoY(ty); + if (!hasGeoPos(gtx, gty)) + { + return true; + } + + final boolean door = target.isDoor(); + final short gtz = door ? getHeightNearestOriginal(gtx, gty, tz) : getHeightNearest(gtx, gty, tz); + + // origin and target coordinates are same + if ((gox == gtx) && (goy == gty)) + { + return goz == gtz; + } + + // get origin and target height, real height = collision height * 2 + double oheight = 0; + if (origin.isCharacter()) + { + oheight = ((L2Character) origin).getTemplate().getCollisionHeight() * 2; + } + + double theight = 0; + if (target.isCharacter()) + { + theight = ((L2Character) target).getTemplate().getCollisionHeight() * 2; + } + + // perform geodata check + return door ? checkSeeOriginal(gox, goy, goz, oheight, gtx, gty, gtz, theight) : checkSee(gox, goy, goz, oheight, gtx, gty, gtz, theight); + } + + /** + * Check line of sight from {@link L2Object} to {@link Location}. + * @param origin : The origin object. + * @param position : The target position. + * @return {@code boolean} : True if object can see position + */ + public final boolean canSeeTarget(L2Object origin, Location position) + { + // get origin and target world coordinates + final int ox = origin.getX(); + final int oy = origin.getY(); + final int oz = origin.getZ(); + final int tx = position.getX(); + final int ty = position.getY(); + final int tz = position.getZ(); + + // get origin and check existing geo coordinates + final int gox = getGeoX(ox); + final int goy = getGeoY(oy); + if (!hasGeoPos(gox, goy)) + { + return true; + } + + final short goz = getHeightNearest(gox, goy, oz); + + // get target and check existing geo coordinates + final int gtx = getGeoX(tx); + final int gty = getGeoY(ty); + if (!hasGeoPos(gtx, gty)) + { + return true; + } + + final short gtz = getHeightNearest(gtx, gty, tz); + + // origin and target coordinates are same + if ((gox == gtx) && (goy == gty)) + { + return goz == gtz; + } + + // get origin and target height, real height = collision height * 2 + double oheight = 0; + if (origin instanceof L2Character) + { + oheight = ((L2Character) origin).getTemplate().getCollisionHeight(); + } + + // perform geodata check + return checkSee(gox, goy, goz, oheight, gtx, gty, gtz, 0); + } + + /** + * Simple check for origin to target visibility. + * @param gox : origin X geodata coordinate + * @param goy : origin Y geodata coordinate + * @param goz : origin Z geodata coordinate + * @param oheight : origin height (if instance of {@link Character}) + * @param gtx : target X geodata coordinate + * @param gty : target Y geodata coordinate + * @param gtz : target Z geodata coordinate + * @param theight : target height (if instance of {@link Character}) + * @return {@code boolean} : True, when target can be seen. + */ + protected final boolean checkSee(int gox, int goy, int goz, double oheight, int gtx, int gty, int gtz, double theight) + { + // get line of sight Z coordinates + double losoz = goz + ((oheight * Config.PART_OF_CHARACTER_HEIGHT) / 100); + double lostz = gtz + ((theight * Config.PART_OF_CHARACTER_HEIGHT) / 100); + + // get X delta and signum + final int dx = Math.abs(gtx - gox); + final int sx = gox < gtx ? 1 : -1; + final byte dirox = sx > 0 ? GeoStructure.CELL_FLAG_E : GeoStructure.CELL_FLAG_W; + final byte dirtx = sx > 0 ? GeoStructure.CELL_FLAG_W : GeoStructure.CELL_FLAG_E; + + // get Y delta and signum + final int dy = Math.abs(gty - goy); + final int sy = goy < gty ? 1 : -1; + final byte diroy = sy > 0 ? GeoStructure.CELL_FLAG_S : GeoStructure.CELL_FLAG_N; + final byte dirty = sy > 0 ? GeoStructure.CELL_FLAG_N : GeoStructure.CELL_FLAG_S; + + // get Z delta + final int dm = Math.max(dx, dy); + final double dz = (lostz - losoz) / dm; + + // get direction flag for diagonal movement + final byte diroxy = getDirXY(dirox, diroy); + final byte dirtxy = getDirXY(dirtx, dirty); + + // delta, determines axis to move on (+..X axis, -..Y axis) + int d = dx - dy; + + // NSWE direction of movement + byte diro; + byte dirt; + + // clearDebugItems(); + // dropDebugItem(728, 0, new GeoLocation(gox, goy, goz)); // blue potion + // dropDebugItem(728, 0, new GeoLocation(gtx, gty, gtz)); // blue potion + + // initialize node values + int nox = gox; + int noy = goy; + int ntx = gtx; + int nty = gty; + byte nsweo = getNsweNearest(gox, goy, goz); + byte nswet = getNsweNearest(gtx, gty, gtz); + + // loop + ABlock block; + int index; + for (int i = 0; i < ((dm + 1) / 2); i++) + { + // dropDebugItem(57, 0, new GeoLocation(gox, goy, goz)); // antidote + // dropDebugItem(1831, 0, new GeoLocation(gtx, gty, gtz)); // adena + + // reset direction flag + diro = 0; + dirt = 0; + + // calculate next point coordinates + int e2 = 2 * d; + if ((e2 > -dy) && (e2 < dx)) + { + // calculate next point XY coordinates + d -= dy; + d += dx; + nox += sx; + ntx -= sx; + noy += sy; + nty -= sy; + diro |= diroxy; + dirt |= dirtxy; + } + else if (e2 > -dy) + { + // calculate next point X coordinate + d -= dy; + nox += sx; + ntx -= sx; + diro |= dirox; + dirt |= dirtx; + } + else if (e2 < dx) + { + // calculate next point Y coordinate + d += dx; + noy += sy; + nty -= sy; + diro |= diroy; + dirt |= dirty; + } + + { + // get block of the next cell + block = getBlock(nox, noy); + + // get index of particular layer, based on movement conditions + if ((nsweo & diro) == 0) + { + index = block.getIndexAbove(nox, noy, goz - GeoStructure.CELL_IGNORE_HEIGHT); + } + else + { + index = block.getIndexBelow(nox, noy, goz + GeoStructure.CELL_IGNORE_HEIGHT); + } + + // layer does not exist, return + if (index == -1) + { + return false; + } + + // get layer and next line of sight Z coordinate + goz = block.getHeight(index); + losoz += dz; + + // perform line of sight check, return when fails + if ((goz - losoz) > Config.MAX_OBSTACLE_HEIGHT) + { + return false; + } + + // get layer nswe + nsweo = block.getNswe(index); + } + { + // get block of the next cell + block = getBlock(ntx, nty); + + // get index of particular layer, based on movement conditions + if ((nswet & dirt) == 0) + { + index = block.getIndexAbove(ntx, nty, gtz - GeoStructure.CELL_IGNORE_HEIGHT); + } + else + { + index = block.getIndexBelow(ntx, nty, gtz + GeoStructure.CELL_IGNORE_HEIGHT); + } + + // layer does not exist, return + if (index == -1) + { + return false; + } + + // get layer and next line of sight Z coordinate + gtz = block.getHeight(index); + lostz -= dz; + + // perform line of sight check, return when fails + if ((gtz - lostz) > Config.MAX_OBSTACLE_HEIGHT) + { + return false; + } + + // get layer nswe + nswet = block.getNswe(index); + } + + // update coords + gox = nox; + goy = noy; + gtx = ntx; + gty = nty; + } + + // when iteration is completed, compare final Z coordinates + return Math.abs(goz - gtz) < (GeoStructure.CELL_HEIGHT * 4); + } + + /** + * Simple check for origin to target visibility.
+ * Geodata without {@link IGeoObject} are taken in consideration.
+ * NOTE: When two doors close between each other and the LoS check of one doors is performed through another door, result will not be accurate (the other door are skipped). + * @param gox : origin X geodata coordinate + * @param goy : origin Y geodata coordinate + * @param goz : origin Z geodata coordinate + * @param oheight : origin height (if instance of {@link Character}) + * @param gtx : target X geodata coordinate + * @param gty : target Y geodata coordinate + * @param gtz : target Z geodata coordinate + * @param theight : target height (if instance of {@link Character} or {@link L2DoorInstance}) + * @return {@code boolean} : True, when target can be seen. + */ + protected final boolean checkSeeOriginal(int gox, int goy, int goz, double oheight, int gtx, int gty, int gtz, double theight) + { + // get line of sight Z coordinates + double losoz = goz + ((oheight * Config.PART_OF_CHARACTER_HEIGHT) / 100); + double lostz = gtz + ((theight * Config.PART_OF_CHARACTER_HEIGHT) / 100); + + // get X delta and signum + final int dx = Math.abs(gtx - gox); + final int sx = gox < gtx ? 1 : -1; + final byte dirox = sx > 0 ? GeoStructure.CELL_FLAG_E : GeoStructure.CELL_FLAG_W; + final byte dirtx = sx > 0 ? GeoStructure.CELL_FLAG_W : GeoStructure.CELL_FLAG_E; + + // get Y delta and signum + final int dy = Math.abs(gty - goy); + final int sy = goy < gty ? 1 : -1; + final byte diroy = sy > 0 ? GeoStructure.CELL_FLAG_S : GeoStructure.CELL_FLAG_N; + final byte dirty = sy > 0 ? GeoStructure.CELL_FLAG_N : GeoStructure.CELL_FLAG_S; + + // get Z delta + final int dm = Math.max(dx, dy); + final double dz = (lostz - losoz) / dm; + + // get direction flag for diagonal movement + final byte diroxy = getDirXY(dirox, diroy); + final byte dirtxy = getDirXY(dirtx, dirty); + + // delta, determines axis to move on (+..X axis, -..Y axis) + int d = dx - dy; + + // NSWE direction of movement + byte diro; + byte dirt; + + // clearDebugItems(); + // dropDebugItem(728, 0, new GeoLocation(gox, goy, goz)); // blue potion + // dropDebugItem(728, 0, new GeoLocation(gtx, gty, gtz)); // blue potion + + // initialize node values + int nox = gox; + int noy = goy; + int ntx = gtx; + int nty = gty; + byte nsweo = getNsweNearestOriginal(gox, goy, goz); + byte nswet = getNsweNearestOriginal(gtx, gty, gtz); + + // loop + ABlock block; + int index; + for (int i = 0; i < ((dm + 1) / 2); i++) + { + // dropDebugItem(57, 0, new GeoLocation(gox, goy, goz)); // antidote + // dropDebugItem(1831, 0, new GeoLocation(gtx, gty, gtz)); // adena + + // reset direction flag + diro = 0; + dirt = 0; + + // calculate next point coordinates + int e2 = 2 * d; + if ((e2 > -dy) && (e2 < dx)) + { + // calculate next point XY coordinates + d -= dy; + d += dx; + nox += sx; + ntx -= sx; + noy += sy; + nty -= sy; + diro |= diroxy; + dirt |= dirtxy; + } + else if (e2 > -dy) + { + // calculate next point X coordinate + d -= dy; + nox += sx; + ntx -= sx; + diro |= dirox; + dirt |= dirtx; + } + else if (e2 < dx) + { + // calculate next point Y coordinate + d += dx; + noy += sy; + nty -= sy; + diro |= diroy; + dirt |= dirty; + } + + { + // get block of the next cell + block = getBlock(nox, noy); + + // get index of particular layer, based on movement conditions + if ((nsweo & diro) == 0) + { + index = block.getIndexAboveOriginal(nox, noy, goz - GeoStructure.CELL_IGNORE_HEIGHT); + } + else + { + index = block.getIndexBelowOriginal(nox, noy, goz + GeoStructure.CELL_IGNORE_HEIGHT); + } + + // layer does not exist, return + if (index == -1) + { + return false; + } + + // get layer and next line of sight Z coordinate + goz = block.getHeightOriginal(index); + losoz += dz; + + // perform line of sight check, return when fails + if ((goz - losoz) > Config.MAX_OBSTACLE_HEIGHT) + { + return false; + } + + // get layer nswe + nsweo = block.getNsweOriginal(index); + } + { + // get block of the next cell + block = getBlock(ntx, nty); + + // get index of particular layer, based on movement conditions + if ((nswet & dirt) == 0) + { + index = block.getIndexAboveOriginal(ntx, nty, gtz - GeoStructure.CELL_IGNORE_HEIGHT); + } + else + { + index = block.getIndexBelowOriginal(ntx, nty, gtz + GeoStructure.CELL_IGNORE_HEIGHT); + } + + // layer does not exist, return + if (index == -1) + { + return false; + } + + // get layer and next line of sight Z coordinate + gtz = block.getHeightOriginal(index); + lostz -= dz; + + // perform line of sight check, return when fails + if ((gtz - lostz) > Config.MAX_OBSTACLE_HEIGHT) + { + return false; + } + + // get layer nswe + nswet = block.getNsweOriginal(index); + } + + // update coords + gox = nox; + goy = noy; + gtx = ntx; + gty = nty; + } + + // when iteration is completed, compare final Z coordinates + return Math.abs(goz - gtz) < (GeoStructure.CELL_HEIGHT * 4); + } + + /** + * Check movement from coordinates to coordinates. + * @param ox : origin X coordinate + * @param oy : origin Y coordinate + * @param oz : origin Z coordinate + * @param tx : target X coordinate + * @param ty : target Y coordinate + * @param tz : target Z coordinate + * @param instanceId + * @return {code boolean} : True if target coordinates are reachable from origin coordinates + */ + public final boolean canMoveToTarget(int ox, int oy, int oz, int tx, int ty, int tz, int instanceId) + { + if (DoorData.getInstance().checkIfDoorsBetween(ox, oy, oz, tx, ty, tz, instanceId, false)) + { + return false; + } + + // get origin and check existing geo coordinates + final int gox = getGeoX(ox); + final int goy = getGeoY(oy); + if (!hasGeoPos(gox, goy)) + { + return true; + } + + final short goz = getHeightNearest(gox, goy, oz); + + // get target and check existing geo coordinates + final int gtx = getGeoX(tx); + final int gty = getGeoY(ty); + if (!hasGeoPos(gtx, gty)) + { + return true; + } + + final short gtz = getHeightNearest(gtx, gty, tz); + + // target coordinates reached + if ((gox == gtx) && (goy == gty) && (goz == gtz)) + { + return true; + } + + // perform geodata check + GeoLocation loc = checkMove(gox, goy, goz, gtx, gty, gtz, instanceId); + return (loc.getGeoX() == gtx) && (loc.getGeoY() == gty); + } + + /** + * Check movement from origin to target. Returns last available point in the checked path. + * @param ox : origin X coordinate + * @param oy : origin Y coordinate + * @param oz : origin Z coordinate + * @param tx : target X coordinate + * @param ty : target Y coordinate + * @param tz : target Z coordinate + * @param instanceId + * @return {@link Location} : Last point where object can walk (just before wall) + */ + public final Location canMoveToTargetLoc(int ox, int oy, int oz, int tx, int ty, int tz, int instanceId) + { + if (DoorData.getInstance().checkIfDoorsBetween(ox, oy, oz, tx, ty, tz, instanceId, false)) + { + return new Location(ox, oy, getHeight(ox, oy, oz)); + } + + // get origin and check existing geo coordinates + final int gox = getGeoX(ox); + final int goy = getGeoY(oy); + if (!hasGeoPos(gox, goy)) + { + return new Location(tx, ty, tz); + } + + final short goz = getHeightNearest(gox, goy, oz); + + // get target and check existing geo coordinates + final int gtx = getGeoX(tx); + final int gty = getGeoY(ty); + if (!hasGeoPos(gtx, gty)) + { + return new Location(tx, ty, tz); + } + + final short gtz = getHeightNearest(gtx, gty, tz); + + // target coordinates reached + if ((gox == gtx) && (goy == gty) && (goz == gtz)) + { + return new Location(tx, ty, tz); + } + + // perform geodata check + return checkMove(gox, goy, goz, gtx, gty, gtz, instanceId); + } + + /** + * With this method you can check if a position is visible or can be reached by beeline movement.
+ * Target X and Y reachable and Z is on same floor: + *
    + *
  • Location of the target with corrected Z value from geodata.
  • + *
+ * Target X and Y reachable but Z is on another floor: + *
    + *
  • Location of the origin with corrected Z value from geodata.
  • + *
+ * Target X and Y not reachable: + *
    + *
  • Last accessible location in destination to target.
  • + *
+ * @param gox : origin X geodata coordinate + * @param goy : origin Y geodata coordinate + * @param goz : origin Z geodata coordinate + * @param gtx : target X geodata coordinate + * @param gty : target Y geodata coordinate + * @param gtz : target Z geodata coordinate + * @param instanceId + * @return {@link GeoLocation} : The last allowed point of movement. + */ + protected final GeoLocation checkMove(int gox, int goy, int goz, int gtx, int gty, int gtz, int instanceId) + { + if (DoorData.getInstance().checkIfDoorsBetween(gox, goy, goz, gtx, gty, gtz, instanceId, false)) + { + return new GeoLocation(gox, goy, goz); + } + + // get X delta, signum and direction flag + final int dx = Math.abs(gtx - gox); + final int sx = gox < gtx ? 1 : -1; + final byte dirX = sx > 0 ? GeoStructure.CELL_FLAG_E : GeoStructure.CELL_FLAG_W; + + // get Y delta, signum and direction flag + final int dy = Math.abs(gty - goy); + final int sy = goy < gty ? 1 : -1; + final byte dirY = sy > 0 ? GeoStructure.CELL_FLAG_S : GeoStructure.CELL_FLAG_N; + + // get direction flag for diagonal movement + final byte dirXY = getDirXY(dirX, dirY); + + // delta, determines axis to move on (+..X axis, -..Y axis) + int d = dx - dy; + + // NSWE direction of movement + byte direction; + + // load pointer coordinates + int gpx = gox; + int gpy = goy; + int gpz = goz; + + // load next pointer + int nx = gpx; + int ny = gpy; + + // loop + do + { + direction = 0; + + // calculate next point coordinates + int e2 = 2 * d; + if ((e2 > -dy) && (e2 < dx)) + { + d -= dy; + d += dx; + nx += sx; + ny += sy; + direction |= dirXY; + } + else if (e2 > -dy) + { + d -= dy; + nx += sx; + direction |= dirX; + } + else if (e2 < dx) + { + d += dx; + ny += sy; + direction |= dirY; + } + + // obstacle found, return + if ((getNsweNearest(gpx, gpy, gpz) & direction) == 0) + { + return new GeoLocation(gpx, gpy, gpz); + } + + // update pointer coordinates + gpx = nx; + gpy = ny; + gpz = getHeightNearest(nx, ny, gpz); + + // target coordinates reached + if ((gpx == gtx) && (gpy == gty)) + { + if (gpz == gtz) + { + // path found, Z coordinates are okay, return target point + return new GeoLocation(gtx, gty, gtz); + } + + // path found, Z coordinates are not okay, return origin point + return new GeoLocation(gox, goy, goz); + } + } + while (true); + } + + /** + * Returns diagonal NSWE flag format of combined two NSWE flags. + * @param dirX : X direction NSWE flag + * @param dirY : Y direction NSWE flag + * @return byte : NSWE flag of combined direction + */ + private static final byte getDirXY(byte dirX, byte dirY) + { + // check axis directions + if (dirY == GeoStructure.CELL_FLAG_N) + { + if (dirX == GeoStructure.CELL_FLAG_W) + { + return GeoStructure.CELL_FLAG_NW; + } + + return GeoStructure.CELL_FLAG_NE; + } + + if (dirX == GeoStructure.CELL_FLAG_W) + { + return GeoStructure.CELL_FLAG_SW; + } + + return GeoStructure.CELL_FLAG_SE; + } + + /** + * Returns the list of location objects as a result of complete path calculation. + * @param ox : origin x + * @param oy : origin y + * @param oz : origin z + * @param tx : target x + * @param ty : target y + * @param tz : target z + * @param instanceId + * @param playable : moving object is playable? + * @return {@code List} : complete path from nodes + */ + public List findPath(int ox, int oy, int oz, int tx, int ty, int tz, int instanceId, boolean playable) + { + return null; + } + + private static class SingletonHolder + { + protected static final GeoEngine _instance = Config.PATHFINDING ? new GeoEnginePathfinding() : new GeoEngine(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/GeoEnginePathfinding.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/GeoEnginePathfinding.java new file mode 100644 index 0000000000..298401d71a --- /dev/null +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/GeoEnginePathfinding.java @@ -0,0 +1,307 @@ +/* + * 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 . + */ +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.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.util.StringUtil; + +/** + * @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 findPath(int ox, int oy, int oz, int tx, int ty, int tz, int 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 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 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 : list of node location + */ + private static final List constructPath(Node target) + { + // create empty list + LinkedList 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 _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(); + } + } +} \ No newline at end of file diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/ABlock.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/ABlock.java new file mode 100644 index 0000000000..7fca5a9f52 --- /dev/null +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/ABlock.java @@ -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 . + */ +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.
+ * 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.
+ * 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.
+ * 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.
+ * 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.
+ * 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.
+ * 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; +} \ No newline at end of file diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplex.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplex.java new file mode 100644 index 0000000000..de0a7b8524 --- /dev/null +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplex.java @@ -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 . + */ +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); + } +} \ No newline at end of file diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplexDynamic.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplexDynamic.java new file mode 100644 index 0000000000..9f49e41899 --- /dev/null +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplexDynamic.java @@ -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 . + */ +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 _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; + } + } + } + } + } +} \ No newline at end of file diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/BlockFlat.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/BlockFlat.java new file mode 100644 index 0000000000..e1d82814eb --- /dev/null +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/BlockFlat.java @@ -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 . + */ +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)); + } +} \ No newline at end of file diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayer.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayer.java new file mode 100644 index 0000000000..56d4de75e1 --- /dev/null +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayer.java @@ -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 . + */ +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; + } + } +} \ No newline at end of file diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayerDynamic.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayerDynamic.java new file mode 100644 index 0000000000..2361135de5 --- /dev/null +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayerDynamic.java @@ -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 . + */ +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 _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; + } + } + } + } + } +} \ No newline at end of file diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/BlockNull.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/BlockNull.java new file mode 100644 index 0000000000..225bdef947 --- /dev/null +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/BlockNull.java @@ -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 . + */ +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) + { + } +} \ No newline at end of file diff --git a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNodeLoc.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/GeoFormat.java similarity index 67% rename from L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNodeLoc.java rename to L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/GeoFormat.java index ec3bd23d44..57885fc734 100644 --- a/L2J_Mobius_Ertheia/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNodeLoc.java +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/GeoFormat.java @@ -1,33 +1,39 @@ -/* - * 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 . - */ -package com.l2jmobius.gameserver.geodata.pathfinding; - -/** - * @author -Nemesiss- - */ -public abstract class AbstractNodeLoc -{ - public abstract int getX(); - - public abstract int getY(); - - public abstract int getZ(); - - public abstract int getNodeX(); - - public abstract int getNodeY(); -} +/* + * 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 . + */ +package com.l2jmobius.gameserver.geoengine.geodata; + +/** + * @author Hasha + */ +public enum GeoFormat +{ + L2J("%d_%d.l2j"), + L2OFF("%d_%d_conv.dat"), + L2D("%d_%d.l2d"); + + private final String _filename; + + private GeoFormat(String filename) + { + _filename = filename; + } + + public String getFilename() + { + return _filename; + } +} \ No newline at end of file diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/GeoLocation.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/GeoLocation.java new file mode 100644 index 0000000000..850fcdbfcd --- /dev/null +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/GeoLocation.java @@ -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 . + */ +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; + } +} \ No newline at end of file diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/GeoStructure.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/GeoStructure.java new file mode 100644 index 0000000000..e1925e6e57 --- /dev/null +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/GeoStructure.java @@ -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 . + */ +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; +} \ No newline at end of file diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/IBlockDynamic.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/IBlockDynamic.java new file mode 100644 index 0000000000..e241e73b1c --- /dev/null +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/IBlockDynamic.java @@ -0,0 +1,35 @@ +/* + * 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 . + */ +package com.l2jmobius.gameserver.geoengine.geodata; + +/** + * @author Hasha + */ +public interface IBlockDynamic +{ + /** + * 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); + + /** + * 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); +} \ No newline at end of file diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/IGeoObject.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/IGeoObject.java new file mode 100644 index 0000000000..2726378e3a --- /dev/null +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/geodata/IGeoObject.java @@ -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 . + */ +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(); +} diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/pathfinding/Node.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/pathfinding/Node.java new file mode 100644 index 0000000000..27430a65cd --- /dev/null +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/pathfinding/Node.java @@ -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 . + */ +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; + } +} \ No newline at end of file diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/pathfinding/NodeBuffer.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/pathfinding/NodeBuffer.java new file mode 100644 index 0000000000..300fe31190 --- /dev/null +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/geoengine/pathfinding/NodeBuffer.java @@ -0,0 +1,351 @@ +/* + * 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 . + */ +package com.l2jmobius.gameserver.geoengine.pathfinding; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.locks.ReentrantLock; + +import com.l2jmobius.Config; +import com.l2jmobius.gameserver.geoengine.geodata.GeoStructure; + +/** + * @author DS, Hasha; Credits to Diamond + */ +public class NodeBuffer +{ + private final ReentrantLock _lock = new ReentrantLock(); + private final int _size; + private final Node[][] _buffer; + + // center coordinates + private int _cx = 0; + private int _cy = 0; + + // target coordinates + private int _gtx = 0; + private int _gty = 0; + private short _gtz = 0; + + // pathfinding statistics + private long _timeStamp = 0; + private long _lastElapsedTime = 0; + + private Node _current = null; + + /** + * Constructor of NodeBuffer. + * @param size : one dimension size of buffer + */ + public NodeBuffer(int size) + { + // set size + _size = size; + + // initialize buffer + _buffer = new Node[size][size]; + for (int x = 0; x < size; x++) + { + for (int y = 0; y < size; y++) + { + _buffer[x][y] = new Node(); + } + } + } + + /** + * Find path consisting of Nodes. Starts at origin coordinates, ends in target coordinates. + * @param gox : origin point x + * @param goy : origin point y + * @param goz : origin point z + * @param gtx : target point x + * @param gty : target point y + * @param gtz : target point z + * @return Node : first node of path + */ + public final Node findPath(int gox, int goy, short goz, int gtx, int gty, short gtz) + { + // load timestamp + _timeStamp = System.currentTimeMillis(); + + // set coordinates (middle of the line (gox,goy) - (gtx,gty), will be in the center of the buffer) + _cx = gox + ((gtx - gox - _size) / 2); + _cy = goy + ((gty - goy - _size) / 2); + + _gtx = gtx; + _gty = gty; + _gtz = gtz; + + _current = getNode(gox, goy, goz); + _current.setCost(getCostH(gox, goy, goz)); + + int count = 0; + do + { + // reached target? + if ((_current.getLoc().getGeoX() == _gtx) && (_current.getLoc().getGeoY() == _gty) && (Math.abs(_current.getLoc().getZ() - _gtz) < 8)) + { + return _current; + } + + // expand current node + expand(); + + // move pointer + _current = _current.getChild(); + } + while ((_current != null) && (++count < Config.MAX_ITERATIONS)); + + return null; + } + + /** + * Creates list of Nodes to show debug path. + * @return List : nodes + */ + public final List debugPath() + { + List result = new ArrayList<>(); + + for (Node n = _current; n.getParent() != null; n = n.getParent()) + { + result.add(n); + n.setCost(-n.getCost()); + } + + for (Node[] nodes : _buffer) + { + for (Node node : nodes) + { + if ((node.getLoc() == null) || (node.getCost() <= 0)) + { + continue; + } + + result.add(node); + } + } + + return result; + } + + public final boolean isLocked() + { + return _lock.tryLock(); + } + + public final void free() + { + _current = null; + + for (Node[] nodes : _buffer) + { + for (Node node : nodes) + { + if (node.getLoc() != null) + { + node.free(); + } + } + } + + _lock.unlock(); + _lastElapsedTime = System.currentTimeMillis() - _timeStamp; + } + + public final long getElapsedTime() + { + return _lastElapsedTime; + } + + /** + * Check _current Node and add its neighbors to the buffer. + */ + private final void expand() + { + // can't move anywhere, don't expand + byte nswe = _current.getLoc().getNSWE(); + if (nswe == 0) + { + return; + } + + // get geo coords of the node to be expanded + final int x = _current.getLoc().getGeoX(); + final int y = _current.getLoc().getGeoY(); + final short z = (short) _current.getLoc().getZ(); + + // can move north, expand + if ((nswe & GeoStructure.CELL_FLAG_N) != 0) + { + addNode(x, y - 1, z, Config.BASE_WEIGHT); + } + + // can move south, expand + if ((nswe & GeoStructure.CELL_FLAG_S) != 0) + { + addNode(x, y + 1, z, Config.BASE_WEIGHT); + } + + // can move west, expand + if ((nswe & GeoStructure.CELL_FLAG_W) != 0) + { + addNode(x - 1, y, z, Config.BASE_WEIGHT); + } + + // can move east, expand + if ((nswe & GeoStructure.CELL_FLAG_E) != 0) + { + addNode(x + 1, y, z, Config.BASE_WEIGHT); + } + + // can move north-west, expand + if ((nswe & GeoStructure.CELL_FLAG_NW) != 0) + { + addNode(x - 1, y - 1, z, Config.DIAGONAL_WEIGHT); + } + + // can move north-east, expand + if ((nswe & GeoStructure.CELL_FLAG_NE) != 0) + { + addNode(x + 1, y - 1, z, Config.DIAGONAL_WEIGHT); + } + + // can move south-west, expand + if ((nswe & GeoStructure.CELL_FLAG_SW) != 0) + { + addNode(x - 1, y + 1, z, Config.DIAGONAL_WEIGHT); + } + + // can move south-east, expand + if ((nswe & GeoStructure.CELL_FLAG_SE) != 0) + { + addNode(x + 1, y + 1, z, Config.DIAGONAL_WEIGHT); + } + } + + /** + * Returns node, if it exists in buffer. + * @param x : node X coord + * @param y : node Y coord + * @param z : node Z coord + * @return Node : node, if exits in buffer + */ + private final Node getNode(int x, int y, short z) + { + // check node X out of coordinates + final int ix = x - _cx; + if ((ix < 0) || (ix >= _size)) + { + return null; + } + + // check node Y out of coordinates + final int iy = y - _cy; + if ((iy < 0) || (iy >= _size)) + { + return null; + } + + // get node + Node result = _buffer[ix][iy]; + + // check and update + if (result.getLoc() == null) + { + result.setLoc(x, y, z); + } + + // return node + return result; + } + + /** + * Add node given by coordinates to the buffer. + * @param x : geo X coord + * @param y : geo Y coord + * @param z : geo Z coord + * @param weight : weight of movement to new node + */ + private final void addNode(int x, int y, short z, int weight) + { + // get node to be expanded + Node node = getNode(x, y, z); + if (node == null) + { + return; + } + + // Z distance between nearby cells is higher than cell size + if (node.getLoc().getZ() > (z + (2 * GeoStructure.CELL_HEIGHT))) + { + return; + } + + // node was already expanded, return + if (node.getCost() >= 0) + { + return; + } + + node.setParent(_current); + if (node.getLoc().getNSWE() != (byte) 0xFF) + { + node.setCost(getCostH(x, y, node.getLoc().getZ()) + (weight * Config.OBSTACLE_MULTIPLIER)); + } + else + { + node.setCost(getCostH(x, y, node.getLoc().getZ()) + weight); + } + + Node current = _current; + int count = 0; + while ((current.getChild() != null) && (count < (Config.MAX_ITERATIONS * 4))) + { + count++; + if (current.getChild().getCost() > node.getCost()) + { + node.setChild(current.getChild()); + break; + } + current = current.getChild(); + } + + if (count >= (Config.MAX_ITERATIONS * 4)) + { + System.err.println("Pathfinding: too long loop detected, cost:" + node.getCost()); + } + + current.setChild(node); + } + + /** + * @param x : node X coord + * @param y : node Y coord + * @param i : node Z coord + * @return double : node cost + */ + private final double getCostH(int x, int y, int i) + { + final int dX = x - _gtx; + final int dY = y - _gty; + final int dZ = (i - _gtz) / GeoStructure.CELL_HEIGHT; + + // return (Math.abs(dX) + Math.abs(dY) + Math.abs(dZ)) * Config.HEURISTIC_WEIGHT; // Manhattan distance + return Math.sqrt((dX * dX) + (dY * dY) + (dZ * dZ)) * Config.HEURISTIC_WEIGHT; // Direct distance + } +} \ No newline at end of file diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/L2Spawn.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/L2Spawn.java index 15dd3e259d..a2ffbc6483 100644 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/L2Spawn.java +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/L2Spawn.java @@ -31,7 +31,7 @@ import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.data.sql.impl.TerritoryTable; import com.l2jmobius.gameserver.data.xml.impl.NpcData; import com.l2jmobius.gameserver.datatables.NpcPersonalAIData; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.model.actor.L2Attackable; import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.templates.L2NpcTemplate; @@ -612,7 +612,7 @@ public class L2Spawn implements IPositionable, IIdentifiable, INamable final int randY = newlocy + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); final boolean isQuestMonster = (mob.getTitle() != null) && mob.getTitle().contains("Quest"); - if (mob.isMonster() && !isQuestMonster && !mob.isWalker() && !mob.isInsideZone(ZoneId.NO_BOOKMARK) && GeoData.getInstance().canSeeTarget(newlocx, newlocy, newlocz, randX, randY, newlocz) && (getInstanceId() == 0) && !getTemplate().isUndying() && !mob.isRaid() && !mob.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(mob.getId())) + if (mob.isMonster() && !isQuestMonster && !mob.isWalker() && !mob.isInsideZone(ZoneId.NO_BOOKMARK) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, getInstanceId()) && (getInstanceId() == 0) && !getTemplate().isUndying() && !mob.isRaid() && !mob.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(mob.getId())) { newlocx = randX; newlocy = randY; @@ -623,7 +623,7 @@ public class L2Spawn implements IPositionable, IIdentifiable, INamable // don't correct z of flying npc's if (!mob.isFlying()) { - newlocz = GeoData.getInstance().getSpawnHeight(newlocx, newlocy, newlocz); + newlocz = GeoEngine.getInstance().getHeight(newlocx, newlocy, newlocz); } mob.stopAllEffects(); diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/Location.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/Location.java index 83ee99dfa9..dc1266c27b 100644 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/Location.java +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/Location.java @@ -26,9 +26,9 @@ import com.l2jmobius.gameserver.model.interfaces.IPositionable; */ public class Location implements IPositionable { - private int _x; - private int _y; - private int _z; + protected int _x; + protected int _y; + protected int _z; private int _heading; private int _instanceId; diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Character.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Character.java index b566499caf..966ddb04a2 100644 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Character.java +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Character.java @@ -49,9 +49,7 @@ import com.l2jmobius.gameserver.enums.InstanceType; import com.l2jmobius.gameserver.enums.Race; import com.l2jmobius.gameserver.enums.ShotType; import com.l2jmobius.gameserver.enums.Team; -import com.l2jmobius.gameserver.geodata.GeoData; -import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNodeLoc; -import com.l2jmobius.gameserver.geodata.pathfinding.PathFinding; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.idfactory.IdFactory; import com.l2jmobius.gameserver.instancemanager.InstanceManager; import com.l2jmobius.gameserver.instancemanager.MapRegionManager; @@ -1006,7 +1004,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe stopEffectsOnAction(); // GeoData Los Check here (or dz > 1000) - if (!GeoData.getInstance().canSeeTarget(this, target)) + if (!GeoEngine.getInstance().canSeeTarget(this, target)) { sendPacket(SystemMessageId.CANNOT_SEE_TARGET); getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE); @@ -3433,7 +3431,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe public boolean disregardingGeodata; public int onGeodataPathIndex; - public List geoPath; + public List geoPath; public int geoPathAccurateTx; public int geoPathAccurateTy; public int geoPathGtx; @@ -4030,9 +4028,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe // Z coordinate will follow geodata or client values if ((Config.COORD_SYNCHRONIZE == 2) && !isFloating && !m.disregardingGeodata && ((GameTimeController.getInstance().getGameTicks() % 10) == 0 // once a second to reduce possible cpu load - ) && GeoData.getInstance().hasGeo(xPrev, yPrev)) + ) && GeoEngine.getInstance().hasGeo(xPrev, yPrev)) { - final int geoHeight = GeoData.getInstance().getSpawnHeight(xPrev, yPrev, zPrev); + final int geoHeight = GeoEngine.getInstance().getHeight(xPrev, yPrev, zPrev); dz = m._zDestination - geoHeight; // quite a big difference, compare to validatePosition packet if (isPlayer() && (Math.abs(getActingPlayer().getClientZ() - geoHeight) > 200) && (Math.abs(getActingPlayer().getClientZ() - geoHeight) < 1500)) @@ -4392,7 +4390,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe // Movement checks: // When pathfinding enabled, for all characters except monsters returning home (could be changed later to teleport if pathfinding fails) - if (((Config.PATHFINDING > 0) && (!(isAttackable() && ((L2Attackable) this).isReturningToSpawnPoint()))) // + if ((Config.PATHFINDING && (!(isAttackable() && ((L2Attackable) this).isReturningToSpawnPoint()))) // || (isPlayer() && !(isInVehicle && (distance > 1500))) // || (this instanceof L2RiftInvaderInstance)) { @@ -4423,7 +4421,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe } else if (isSummon()) { - return; // preventation when summon get out of world coords, player will not loose him, unsummon handled from pcinstance + return; // prevention when summon get out of world coords, player will not loose him, unsummon handled from pcinstance } else { @@ -4431,7 +4429,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe } return; } - final Location destiny = GeoData.getInstance().moveCheck(curX, curY, curZ, x, y, z, getInstanceId()); + final Location destiny = GeoEngine.getInstance().canMoveToTargetLoc(curX, curY, curZ, x, y, z, getInstanceId()); // location different if destination wasn't reached (or just z coord is different) x = destiny.getX(); y = destiny.getY(); @@ -4444,13 +4442,13 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe // Pathfinding checks. Only when geodata setting is 2, the LoS check gives shorter result // than the original movement was and the LoS gives a shorter distance than 2000 // This way of detecting need for pathfinding could be changed. - if ((Config.PATHFINDING > 0) && ((originalDistance - distance) > 30) && (distance < 2000)) + if (Config.PATHFINDING && ((originalDistance - distance) > 30) && (distance < 2000)) { // Path calculation // Overrides previous movement check if ((isPlayable() && !isInVehicle) || isMinion() || isInCombat()) { - m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceId(), isPlayable()); + m.geoPath = GeoEngine.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceId(), isPlayable()); if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found { // Even though there's no path found (remember geonodes aren't perfect), @@ -4511,7 +4509,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe } } // If no distance to go through, the movement is canceled - if ((distance < 1) && ((Config.PATHFINDING > 0) || isPlayable() || (this instanceof L2RiftInvaderInstance) || isAfraid())) + if ((distance < 1) && (Config.PATHFINDING || isPlayable() || (this instanceof L2RiftInvaderInstance) || isAfraid())) { if (isSummon()) { @@ -5064,7 +5062,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe return; } // GeoData Los Check or dz > 1000 - if (!GeoData.getInstance().canSeeTarget(player, this)) + if (!GeoEngine.getInstance().canSeeTarget(player, this)) { player.sendPacket(SystemMessageId.CANNOT_SEE_TARGET); player.sendPacket(ActionFailed.STATIC_PACKET); @@ -5400,7 +5398,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe // Healing party members should ignore LOS. if (((skill.getTargetType() != L2TargetType.PARTY) || !skill.hasEffectType(L2EffectType.HEAL)) // - && (mut.getSkillTime() > 550) && !GeoData.getInstance().canSeeTarget(this, target)) + && (mut.getSkillTime() > 550) && !GeoEngine.getInstance().canSeeTarget(this, target)) { skipLOS++; continue; diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Summon.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Summon.java index d51520e0c7..f84d6471ed 100644 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Summon.java +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Summon.java @@ -26,7 +26,7 @@ import com.l2jmobius.gameserver.enums.InstanceType; import com.l2jmobius.gameserver.enums.Race; import com.l2jmobius.gameserver.enums.ShotType; import com.l2jmobius.gameserver.enums.Team; -import com.l2jmobius.gameserver.geodata.pathfinding.PathFinding; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.handler.IItemHandler; import com.l2jmobius.gameserver.handler.ItemHandler; import com.l2jmobius.gameserver.instancemanager.TerritoryWarManager; @@ -660,7 +660,7 @@ public abstract class L2Summon extends L2Playable return false; } - if ((this != target) && skill.isPhysical() && (Config.PATHFINDING > 0) && (PathFinding.getInstance().findPath(getX(), getY(), getZ(), target.getX(), target.getY(), target.getZ(), getInstanceId(), true) == null)) + if ((this != target) && skill.isPhysical() && Config.PATHFINDING && (GeoEngine.getInstance().findPath(getX(), getY(), getZ(), target.getX(), target.getY(), target.getZ(), getInstanceId(), true) == null)) { sendPacket(SystemMessageId.CANNOT_SEE_TARGET); return false; diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Tower.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Tower.java index 04f94b079f..61e4d6a2de 100644 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Tower.java +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Tower.java @@ -17,7 +17,7 @@ package com.l2jmobius.gameserver.model.actor; import com.l2jmobius.gameserver.ai.CtrlIntention; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.actor.templates.L2NpcTemplate; import com.l2jmobius.gameserver.network.serverpackets.ActionFailed; @@ -65,7 +65,7 @@ public abstract class L2Tower extends L2Npc // Set the target of the L2PcInstance player player.setTarget(this); } - else if (interact && isAutoAttackable(player) && (Math.abs(player.getZ() - getZ()) < 100) && GeoData.getInstance().canSeeTarget(player, this)) + else if (interact && isAutoAttackable(player) && (Math.abs(player.getZ() - getZ()) < 100) && GeoEngine.getInstance().canSeeTarget(player, this)) { // Notify the L2PcInstance AI with AI_INTENTION_INTERACT player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this); diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java index 9d8ea61d74..790fdb159a 100644 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java @@ -90,7 +90,7 @@ import com.l2jmobius.gameserver.enums.Sex; import com.l2jmobius.gameserver.enums.ShortcutType; import com.l2jmobius.gameserver.enums.ShotType; import com.l2jmobius.gameserver.enums.Team; -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.idfactory.IdFactory; @@ -106,7 +106,6 @@ import com.l2jmobius.gameserver.instancemanager.GrandBossManager; import com.l2jmobius.gameserver.instancemanager.HandysBlockCheckerManager; import com.l2jmobius.gameserver.instancemanager.InstanceManager; import com.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager; -import com.l2jmobius.gameserver.instancemanager.PremiumManager; import com.l2jmobius.gameserver.instancemanager.PunishmentManager; import com.l2jmobius.gameserver.instancemanager.QuestManager; import com.l2jmobius.gameserver.instancemanager.SiegeManager; @@ -355,9 +354,6 @@ public final class L2PcInstance extends L2Playable private static final String UPDATE_CHARACTER = "UPDATE characters SET level=?,maxHp=?,curHp=?,maxCp=?,curCp=?,maxMp=?,curMp=?,face=?,hairStyle=?,hairColor=?,sex=?,heading=?,x=?,y=?,z=?,exp=?,expBeforeDeath=?,sp=?,karma=?,fame=?,pvpkills=?,pkkills=?,clanid=?,race=?,classid=?,deletetime=?,title=?,title_color=?,accesslevel=?,online=?,isin7sdungeon=?,clan_privs=?,wantspeace=?,base_class=?,onlinetime=?,newbie=?,nobless=?,power_grade=?,subpledge=?,lvl_joined_academy=?,apprentice=?,sponsor=?,clan_join_expiry_time=?,clan_create_expiry_time=?,char_name=?,death_penalty_level=?,bookmarkslot=?,vitality_points=?,language=? WHERE charId=?"; private static final String RESTORE_CHARACTER = "SELECT * FROM characters WHERE charId=?"; - // Character Premium System String Definitions: - private static final String RESTORE_PREMIUMSERVICE = "SELECT premium_service,enddate FROM account_premium WHERE account_name=?"; - // Character Teleport Bookmark: private static final String INSERT_TP_BOOKMARK = "INSERT INTO character_tpbookmark (charId,Id,x,y,z,icon,tag,name) values (?,?,?,?,?,?,?,?)"; private static final String UPDATE_TP_BOOKMARK = "UPDATE character_tpbookmark SET icon=?,tag=?,name=? where charId=? AND Id=?"; @@ -6727,7 +6723,6 @@ public final class L2PcInstance extends L2Playable player = new L2PcInstance(objectId, template, rset.getString("account_name"), app); player.setName(rset.getString("char_name")); - restorePremiumSystemData(player, rset.getString("account_name")); player._lastAccess = rset.getLong("lastAccess"); player.getStat().setExp(rset.getLong("exp")); @@ -8734,14 +8729,14 @@ public final class L2PcInstance extends L2Playable { if (sklTargetType == L2TargetType.GROUND) { - if (!GeoData.getInstance().canSeeTarget(this, worldPosition)) + if (!GeoEngine.getInstance().canSeeTarget(this, worldPosition)) { sendPacket(SystemMessageId.CANNOT_SEE_TARGET); sendPacket(ActionFailed.STATIC_PACKET); return false; } } - else if (!GeoData.getInstance().canSeeTarget(this, target)) + else if (!GeoEngine.getInstance().canSeeTarget(this, target)) { sendPacket(SystemMessageId.CANNOT_SEE_TARGET); sendPacket(ActionFailed.STATIC_PACKET); @@ -8749,7 +8744,7 @@ public final class L2PcInstance extends L2Playable } } - if ((skill.getFlyType() == FlyType.CHARGE) && !GeoData.getInstance().canMove(this, target)) + if ((skill.getFlyType() == FlyType.CHARGE) && !GeoEngine.getInstance().canMoveToTarget(getX(), getY(), getZ(), target.getX(), target.getY(), target.getZ(), getInstanceId())) { sendPacket(SystemMessageId.THE_TARGET_IS_LOCATED_WHERE_YOU_CANNOT_CHARGE); return false; @@ -13404,7 +13399,7 @@ public final class L2PcInstance extends L2Playable } // If there is no geodata loaded for the place we are client Z correction might cause falling damage. - if (!GeoData.getInstance().hasGeo(getX(), getY())) + if (!GeoEngine.getInstance().hasGeo(getX(), getY())) { return false; } @@ -13952,48 +13947,6 @@ public final class L2PcInstance extends L2Playable return Config.PREMIUM_SYSTEM_ENABLED && _premiumStatus; } - private static void restorePremiumSystemData(L2PcInstance player, String account) - { - boolean success = false; - try (Connection con = DatabaseFactory.getInstance().getConnection()) - { - final PreparedStatement ps = con.prepareStatement(RESTORE_PREMIUMSERVICE); - ps.setString(1, account); - final ResultSet rs = ps.executeQuery(); - while (rs.next()) - { - success = true; - if (Config.PREMIUM_SYSTEM_ENABLED) - { - if (rs.getLong("enddate") <= System.currentTimeMillis()) - { - PremiumManager.getInstance().removePremiumStatus(account); - player.setPremiumStatus(false); - } - else - { - player.setPremiumStatus(rs.getBoolean("premium_service")); - } - } - else - { - player.setPremiumStatus(false); - } - } - ps.close(); - } - catch (Exception e) - { - _log.warning("Premium System: Could not restore premium system data for " + account + "." + e); - e.printStackTrace(); - } - if (!success) - { - PremiumManager.getInstance().removePremiumStatus(player.getAccountName()); - player.setPremiumStatus(false); - } - } - public void setLastPetitionGmName(String gmName) { _lastPetitionGmName = gmName; diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java index 3ff8228e67..0c496184e0 100644 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java @@ -40,7 +40,7 @@ import com.l2jmobius.gameserver.datatables.ItemTable; import com.l2jmobius.gameserver.enums.InstanceType; import com.l2jmobius.gameserver.enums.ItemLocation; import com.l2jmobius.gameserver.enums.ShotType; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.idfactory.IdFactory; import com.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager; import com.l2jmobius.gameserver.instancemanager.MercTicketManager; @@ -1540,7 +1540,7 @@ public final class L2ItemInstance extends L2Object if (_dropper != null) { - final Location dropDest = GeoData.getInstance().moveCheck(_dropper.getX(), _dropper.getY(), _dropper.getZ(), _x, _y, _z, _dropper.getInstanceId()); + final Location dropDest = GeoEngine.getInstance().canMoveToTargetLoc(_dropper.getX(), _dropper.getY(), _dropper.getZ(), _x, _y, _z, _dropper.getInstanceId()); _x = dropDest.getX(); _y = dropDest.getY(); _z = dropDest.getZ(); diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/skills/Skill.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/skills/Skill.java index 2071ea1b43..a80f671d65 100644 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/skills/Skill.java +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/skills/Skill.java @@ -32,7 +32,7 @@ import com.l2jmobius.gameserver.data.xml.impl.SkillTreesData; import com.l2jmobius.gameserver.datatables.SkillData; import com.l2jmobius.gameserver.enums.MountType; import com.l2jmobius.gameserver.enums.ShotType; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.handler.ITargetTypeHandler; import com.l2jmobius.gameserver.handler.TargetHandler; import com.l2jmobius.gameserver.instancemanager.HandysBlockCheckerManager; @@ -1221,7 +1221,7 @@ public final class Skill implements IIdentifiable } } - if (!GeoData.getInstance().canSeeTarget(caster, target)) + if (!GeoEngine.getInstance().canSeeTarget(caster, target)) { return false; } diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/skills/SkillChannelizer.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/skills/SkillChannelizer.java index 737edab279..fbf7c85e3c 100644 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/skills/SkillChannelizer.java +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/skills/SkillChannelizer.java @@ -24,7 +24,7 @@ import java.util.logging.Logger; import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.datatables.SkillData; import com.l2jmobius.gameserver.enums.ShotType; -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.instance.L2PcInstance; @@ -178,7 +178,7 @@ public class SkillChannelizer implements Runnable { continue; } - else if (!GeoData.getInstance().canSeeTarget(_channelizer, character)) + else if (!GeoEngine.getInstance().canSeeTarget(_channelizer, character)) { continue; } diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/zone/form/ZoneCuboid.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/zone/form/ZoneCuboid.java index d7b94c10a2..dbd264d55f 100644 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/zone/form/ZoneCuboid.java +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/zone/form/ZoneCuboid.java @@ -18,7 +18,7 @@ package com.l2jmobius.gameserver.model.zone.form; import java.awt.Rectangle; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.model.itemcontainer.Inventory; import com.l2jmobius.gameserver.model.zone.L2ZoneForm; import com.l2jmobius.util.Rnd; @@ -134,7 +134,7 @@ public class ZoneCuboid extends L2ZoneForm { x, y, - GeoData.getInstance().getHeight(x, y, _z1) + GeoEngine.getInstance().getHeight(x, y, _z1) }; } } diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/zone/form/ZoneCylinder.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/zone/form/ZoneCylinder.java index ec8300ace4..e0bfbfff50 100644 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/zone/form/ZoneCylinder.java +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/zone/form/ZoneCylinder.java @@ -16,7 +16,7 @@ */ package com.l2jmobius.gameserver.model.zone.form; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.model.itemcontainer.Inventory; import com.l2jmobius.gameserver.model.zone.L2ZoneForm; import com.l2jmobius.util.Rnd; @@ -101,7 +101,7 @@ public class ZoneCylinder extends L2ZoneForm { (int) x, (int) y, - GeoData.getInstance().getHeight((int) x, (int) y, _z1) + GeoEngine.getInstance().getHeight((int) x, (int) y, _z1) }; } } diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/zone/form/ZoneNPoly.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/zone/form/ZoneNPoly.java index 9f58089cf3..8aee86a012 100644 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/zone/form/ZoneNPoly.java +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/model/zone/form/ZoneNPoly.java @@ -18,7 +18,7 @@ package com.l2jmobius.gameserver.model.zone.form; import java.awt.Polygon; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.model.itemcontainer.Inventory; import com.l2jmobius.gameserver.model.zone.L2ZoneForm; import com.l2jmobius.util.Rnd; @@ -131,7 +131,7 @@ public class ZoneNPoly extends L2ZoneForm { x, y, - GeoData.getInstance().getHeight(x, y, _z1) + GeoEngine.getInstance().getHeight(x, y, _z1) }; } diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/util/GeoUtils.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/util/GeoUtils.java index 9b7cc833f0..c81ee877ec 100644 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/util/GeoUtils.java +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/util/GeoUtils.java @@ -18,8 +18,8 @@ package com.l2jmobius.gameserver.util; import java.awt.Color; -import com.l2jmobius.gameserver.geodata.GeoData; -import com.l2jmobius.gameserver.geodata.geodriver.Cell; +import com.l2jmobius.gameserver.geoengine.GeoEngine; +import com.l2jmobius.gameserver.geoengine.geodata.GeoStructure; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.network.serverpackets.ExServerPrimitive; @@ -30,41 +30,44 @@ public final class GeoUtils { public static void debug2DLine(L2PcInstance player, int x, int y, int tx, int ty, int z) { - final int gx = GeoData.getInstance().getGeoX(x); - final int gy = GeoData.getInstance().getGeoY(y); + final int gx = GeoEngine.getInstance().getGeoX(x); + final int gy = GeoEngine.getInstance().getGeoY(y); - final int tgx = GeoData.getInstance().getGeoX(tx); - final int tgy = GeoData.getInstance().getGeoY(ty); + final int tgx = GeoEngine.getInstance().getGeoX(tx); + final int tgy = GeoEngine.getInstance().getGeoY(ty); final ExServerPrimitive prim = new ExServerPrimitive("Debug2DLine", x, y, z); - prim.addLine(Color.BLUE, GeoData.getInstance().getWorldX(gx), GeoData.getInstance().getWorldY(gy), z, GeoData.getInstance().getWorldX(tgx), GeoData.getInstance().getWorldY(tgy), z); + prim.addLine(Color.BLUE, GeoEngine.getInstance().getWorldX(gx), GeoEngine.getInstance().getWorldY(gy), z, GeoEngine.getInstance().getWorldX(tgx), GeoEngine.getInstance().getWorldY(tgy), z); final LinePointIterator iter = new LinePointIterator(gx, gy, tgx, tgy); while (iter.next()) { - prim.addPoint(Color.RED, GeoData.getInstance().getWorldX(iter.x()), GeoData.getInstance().getWorldY(iter.y()), z); + final int wx = GeoEngine.getInstance().getWorldX(iter.x()); + final int wy = GeoEngine.getInstance().getWorldY(iter.y()); + + prim.addPoint(Color.RED, wx, wy, z); } player.sendPacket(prim); } public static void debug3DLine(L2PcInstance player, int x, int y, int z, int tx, int ty, int tz) { - final int gx = GeoData.getInstance().getGeoX(x); - final int gy = GeoData.getInstance().getGeoY(y); + final int gx = GeoEngine.getInstance().getGeoX(x); + final int gy = GeoEngine.getInstance().getGeoY(y); - final int tgx = GeoData.getInstance().getGeoX(tx); - final int tgy = GeoData.getInstance().getGeoY(ty); + final int tgx = GeoEngine.getInstance().getGeoX(tx); + final int tgy = GeoEngine.getInstance().getGeoY(ty); final ExServerPrimitive prim = new ExServerPrimitive("Debug3DLine", x, y, z); - prim.addLine(Color.BLUE, GeoData.getInstance().getWorldX(gx), GeoData.getInstance().getWorldY(gy), z, GeoData.getInstance().getWorldX(tgx), GeoData.getInstance().getWorldY(tgy), tz); + prim.addLine(Color.BLUE, GeoEngine.getInstance().getWorldX(gx), GeoEngine.getInstance().getWorldY(gy), z, GeoEngine.getInstance().getWorldX(tgx), GeoEngine.getInstance().getWorldY(tgy), tz); final LinePointIterator3D iter = new LinePointIterator3D(gx, gy, z, tgx, tgy, tz); iter.next(); int prevX = iter.x(); int prevY = iter.y(); - int wx = GeoData.getInstance().getWorldX(prevX); - int wy = GeoData.getInstance().getWorldY(prevY); + int wx = GeoEngine.getInstance().getWorldX(prevX); + int wy = GeoEngine.getInstance().getWorldY(prevY); int wz = iter.z(); prim.addPoint(Color.RED, wx, wy, wz); @@ -75,8 +78,8 @@ public final class GeoUtils if ((curX != prevX) || (curY != prevY)) { - wx = GeoData.getInstance().getWorldX(curX); - wy = GeoData.getInstance().getWorldY(curY); + wx = GeoEngine.getInstance().getWorldX(curX); + wy = GeoEngine.getInstance().getWorldY(curY); wz = iter.z(); prim.addPoint(Color.RED, wx, wy, wz); @@ -90,18 +93,23 @@ public final class GeoUtils private static Color getDirectionColor(int x, int y, int z, int nswe) { - return GeoData.getInstance().checkNearestNswe(x, y, z, nswe) ? Color.GREEN : Color.RED; + if ((GeoEngine.getInstance().getNsweNearest(x, y, z) & nswe) == nswe) + { + return Color.GREEN; + } + return Color.RED; } public static void debugGrid(L2PcInstance player) { - final int geoRadius = 10; - final int blocksPerPacket = 49; + final int geoRadius = 20; + final int blocksPerPacket = 40; + int iBlock = blocksPerPacket; int iPacket = 0; ExServerPrimitive exsp = null; - final GeoData gd = GeoData.getInstance(); + final GeoEngine gd = GeoEngine.getInstance(); final int playerGx = gd.getGeoX(player.getX()); final int playerGy = gd.getGeoY(player.getY()); for (int dx = -geoRadius; dx <= geoRadius; ++dx) @@ -129,30 +137,30 @@ public final class GeoUtils final int x = gd.getWorldX(gx); final int y = gd.getWorldY(gy); - final int z = gd.getNearestZ(gx, gy, player.getZ()); + final int z = gd.getHeightNearest(gx, gy, player.getZ()); // north arrow - Color col = getDirectionColor(gx, gy, z, Cell.NSWE_NORTH); + Color col = getDirectionColor(gx, gy, z, GeoStructure.CELL_FLAG_N); exsp.addLine(col, x - 1, y - 7, z, x + 1, y - 7, z); exsp.addLine(col, x - 2, y - 6, z, x + 2, y - 6, z); exsp.addLine(col, x - 3, y - 5, z, x + 3, y - 5, z); exsp.addLine(col, x - 4, y - 4, z, x + 4, y - 4, z); // east arrow - col = getDirectionColor(gx, gy, z, Cell.NSWE_EAST); + col = getDirectionColor(gx, gy, z, GeoStructure.CELL_FLAG_E); exsp.addLine(col, x + 7, y - 1, z, x + 7, y + 1, z); exsp.addLine(col, x + 6, y - 2, z, x + 6, y + 2, z); exsp.addLine(col, x + 5, y - 3, z, x + 5, y + 3, z); exsp.addLine(col, x + 4, y - 4, z, x + 4, y + 4, z); // south arrow - col = getDirectionColor(gx, gy, z, Cell.NSWE_SOUTH); + col = getDirectionColor(gx, gy, z, GeoStructure.CELL_FLAG_S); exsp.addLine(col, x - 1, y + 7, z, x + 1, y + 7, z); exsp.addLine(col, x - 2, y + 6, z, x + 2, y + 6, z); exsp.addLine(col, x - 3, y + 5, z, x + 3, y + 5, z); exsp.addLine(col, x - 4, y + 4, z, x + 4, y + 4, z); - col = getDirectionColor(gx, gy, z, Cell.NSWE_WEST); + col = getDirectionColor(gx, gy, z, GeoStructure.CELL_FLAG_W); exsp.addLine(col, x - 7, y - 1, z, x - 7, y + 1, z); exsp.addLine(col, x - 6, y - 2, z, x - 6, y + 2, z); exsp.addLine(col, x - 5, y - 3, z, x - 5, y + 3, z); @@ -180,43 +188,47 @@ public final class GeoUtils { if (y > lastY) { - return Cell.NSWE_SOUTH_EAST; // Direction.SOUTH_EAST; + return GeoStructure.CELL_FLAG_SE; // Direction.SOUTH_EAST; } else if (y < lastY) { - return Cell.NSWE_NORTH_EAST; // Direction.NORTH_EAST; + return GeoStructure.CELL_FLAG_NE; // Direction.NORTH_EAST; } else { - return Cell.NSWE_EAST; // Direction.EAST; + return GeoStructure.CELL_FLAG_E; // Direction.EAST; } } else if (x < lastX) // west { if (y > lastY) { - return Cell.NSWE_SOUTH_WEST; // Direction.SOUTH_WEST; + return GeoStructure.CELL_FLAG_SW; // Direction.SOUTH_WEST; } else if (y < lastY) { - return Cell.NSWE_NORTH_WEST; // Direction.NORTH_WEST; + return GeoStructure.CELL_FLAG_NW; // Direction.NORTH_WEST; } else { - return Cell.NSWE_WEST; // Direction.WEST; + return GeoStructure.CELL_FLAG_W; // Direction.WEST; } } - else if (y > lastY) - { - return Cell.NSWE_SOUTH; // Direction.SOUTH; - } - else if (y < lastY) - { - return Cell.NSWE_NORTH; // Direction.NORTH; - } else + // unchanged x { - throw new RuntimeException(); + if (y > lastY) + { + return GeoStructure.CELL_FLAG_S; // Direction.SOUTH; + } + else if (y < lastY) + { + return GeoStructure.CELL_FLAG_N; // Direction.NORTH; + } + else + { + throw new RuntimeException(); + } } } } \ No newline at end of file diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/util/MathUtil.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/util/MathUtil.java new file mode 100644 index 0000000000..110a9be988 --- /dev/null +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/util/MathUtil.java @@ -0,0 +1,94 @@ +/* + * 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 . + */ +package com.l2jmobius.gameserver.util; + +/** + * @author UnAfraid + */ +public class MathUtil +{ + public static byte add(byte oldValue, byte value) + { + return (byte) (oldValue + value); + } + + public static short add(short oldValue, short value) + { + return (short) (oldValue + value); + } + + public static int add(int oldValue, int value) + { + return oldValue + value; + } + + public static double add(double oldValue, double value) + { + return oldValue + value; + } + + public static byte mul(byte oldValue, byte value) + { + return (byte) (oldValue * value); + } + + public static short mul(short oldValue, short value) + { + return (short) (oldValue * value); + } + + public static int mul(int oldValue, int value) + { + return oldValue * value; + } + + public static double mul(double oldValue, double value) + { + return oldValue * value; + } + + public static byte div(byte oldValue, byte value) + { + return (byte) (oldValue / value); + } + + public static short div(short oldValue, short value) + { + return (short) (oldValue / value); + } + + public static int div(int oldValue, int value) + { + return oldValue / value; + } + + public static double div(double oldValue, double value) + { + 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); + } +} diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/util/StringUtil.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/util/StringUtil.java new file mode 100644 index 0000000000..06d8d20eb2 --- /dev/null +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/util/StringUtil.java @@ -0,0 +1,276 @@ +/* + * 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 . + */ +package com.l2jmobius.gameserver.util; + +import com.l2jmobius.Config; + +/** + * String utilities optimized for the best performance.
+ *

How to Use It

+ *

concat() or append()

If concatenating strings
+ * in single call, use StringUtil.concat(), otherwise use StringUtil.append()
+ * and its variants.
+ *
+ *

Minimum Calls


+ * Bad: + * + *
+ * final StringBuilder sbString = new StringBuilder();
+ * StringUtil.append(sbString, "text 1", String.valueOf(npcId));
+ * StringUtil.append("text 2");
+ * 
+ * + * Good: + * + *
+ * final StringBuilder sbString = new StringBuilder();
+ * StringUtil.append(sbString, "text 1", String.valueOf(npcId), "text 2");
+ * 
+ * + * Why?
+ * Because the less calls you do, the less memory re-allocations have to be done
+ * so the whole text fits into the memory and less array copy tasks has to be
+ * performed. So if using less calls, less memory is used and string concatenation is faster.
+ *
+ *

Size Hints for Loops


+ * Bad: + * + *
+ * final StringBuilder sbString = new StringBuilder();
+ * StringUtil.append(sbString, "header start", someText, "header end");
+ * for (int i = 0; i < 50; i++)
+ * {
+ * 	StringUtil.append(sbString, "text 1", stringArray[i], "text 2");
+ * }
+ * 
+ * + * Good: + * + *
+ * final StringBuilder sbString = StringUtil.startAppend(1300, "header start", someText, "header end");
+ * for (int i = 0; i < 50; i++)
+ * {
+ * 	StringUtil.append(sbString, "text 1", stringArray[i], "text 2");
+ * }
+ * 
+ * + * Why?
+ * When using StringUtil.append(), memory is only allocated to fit in the strings in method argument. So on each loop new memory for the string has to be allocated and old string has to be copied to the new string. With size hint, even if the size hint is above the needed memory, memory is saved + * because new memory has not to be allocated on each cycle. Also it is much faster if no string copy tasks has to be performed. So if concatenating strings in a loop, count approximately the size and set it as the hint for the string builder size. It's better to make the size hint little bit larger + * rather than smaller.
+ * In case there is no text appended before the cycle, just use new + * StringBuilder(1300).
+ *
+ *

Concatenation and Constants


+ * Bad: + * + *
+ * StringUtil.concat("text 1 ", "text 2", String.valueOf(npcId));
+ * 
+ * + * Good: + * + *
+ * StringUtil.concat("text 1 " + "text 2", String.valueOf(npcId));
+ * 
+ * + * or + * + *
+ * StringUtil.concat("text 1 text 2", String.valueOf(npcId));
+ * 
+ * + * Why?
+ * It saves some cycles when determining size of memory that needs to be allocated because less strings are passed to concat() method. But do not use + for concatenation of non-constant strings, that degrades performance and makes extra memory allocations needed.
+ *

Concatenation and Constant Variables

Bad: + * + *
+ * String glue = "some glue";
+ * StringUtil.concat("text 1", glue, "text 2", glue, String.valueOf(npcId));
+ * 
+ * + * Good: + * + *
+ * final String glue = "some glue";
+ * StringUtil.concat("text 1" + glue + "text2" + glue, String.valueOf(npcId));
+ * 
+ * + * Why? Because when using final keyword, the glue is marked as constant string and compiler treats it as a constant string so it is able to create string "text1some gluetext2some glue" during the compilation. But this only works in case the value is known at compilation + * time, so this cannot be used for cases like final String objectIdString = + * String.valueOf(getObjectId).
+ *
+ *

StringBuilder Reuse


+ * Bad: + * + *
+ * final StringBuilder sbString1 = new StringBuilder();
+ * StringUtil.append(sbString1, "text 1", String.valueOf(npcId), "text 2");
+ * ... // output of sbString1, it is no more needed
+ * final StringBuilder sbString2 = new StringBuilder();
+ * StringUtil.append(sbString2, "text 3", String.valueOf(npcId), "text 4");
+ * 
+ * + * Good: + * + *
+ * final StringBuilder sbString = new StringBuilder();
+ * StringUtil.append(sbString, "text 1", String.valueOf(npcId), "text 2");
+ * ... // output of sbString, it is no more needed
+ * sbString.setLength(0);
+ * StringUtil.append(sbString, "text 3", String.valueOf(npcId), "text 4");
+ * 
+ * + * Why?
+ * In first case, new memory has to be allocated for the second string. In second case already allocated memory is reused, but only in case the new string is not longer than the previously allocated string. Anyway, the second way is better because the string either fits in the memory and some memory + * is saved, or it does not fit in the memory, and in that case it works as in the first case. + *

Primitives to Strings

To convert primitives to string, use String.valueOf().
+ *
+ *

How much faster is it?


+ * Here are some results of my tests. Count is number of strings concatenated. Don't take the numbers as 100% true as the numbers are affected by other programs running on my computer at the same time. Anyway, from the results it is obvious that using StringBuilder with predefined size is the + * fastest (and also most memory efficient) solution. It is about 5 times faster when concatenating 7 strings, compared to TextBuilder. Also, with more strings concatenated, the difference between StringBuilder and TextBuilder gets larger. In code, there are many cases, where there are concatenated + * 50+ strings so the time saving is even greater.
+ * + *
+ * Count: 2
+ * TextBuilder: 1893
+ * TextBuilder with size: 1703
+ * String: 1033
+ * StringBuilder: 993
+ * StringBuilder with size: 1024
+ * Count: 3
+ * TextBuilder: 1973
+ * TextBuilder with size: 1872
+ * String: 2583
+ * StringBuilder: 1633
+ * StringBuilder with size: 1156
+ * Count: 4
+ * TextBuilder: 2188
+ * TextBuilder with size: 2229
+ * String: 4207
+ * StringBuilder: 1816
+ * StringBuilder with size: 1444
+ * Count: 5
+ * TextBuilder: 9185
+ * TextBuilder with size: 9464
+ * String: 6937
+ * StringBuilder: 2745
+ * StringBuilder with size: 1882
+ * Count: 6
+ * TextBuilder: 9785
+ * TextBuilder with size: 10082
+ * String: 9471
+ * StringBuilder: 2889
+ * StringBuilder with size: 1857
+ * Count: 7
+ * TextBuilder: 10169
+ * TextBuilder with size: 10528
+ * String: 12746
+ * StringBuilder: 3081
+ * StringBuilder with size: 2139
+ * 
+ * + * @author fordfrog + */ +public final class StringUtil +{ + private StringUtil() + { + } + + /** + * Concatenates strings. + * @param strings strings to be concatenated + * @return concatenated string + */ + public static String concat(String... strings) + { + final StringBuilder sbString = new StringBuilder(); + for (String string : strings) + { + sbString.append(string); + } + return sbString.toString(); + } + + /** + * Creates new string builder with size initializated to sizeHint, unless total length of strings is greater than sizeHint. + * @param sizeHint hint for string builder size allocation + * @param strings strings to be appended + * @return created string builder + */ + public static StringBuilder startAppend(int sizeHint, String... strings) + { + final int length = getLength(strings); + final StringBuilder sbString = new StringBuilder(sizeHint > length ? sizeHint : length); + for (String string : strings) + { + sbString.append(string); + } + return sbString; + } + + /** + * Appends strings to existing string builder. + * @param sbString string builder + * @param strings strings to be appended + */ + public static void append(StringBuilder sbString, String... strings) + { + sbString.ensureCapacity(sbString.length() + getLength(strings)); + + for (String string : strings) + { + sbString.append(string); + } + } + + public static int getLength(Iterable strings) + { + int length = 0; + for (String string : strings) + { + length += (string == null) ? 4 : string.length(); + } + return length; + } + + /** + * Counts total length of all the strings. + * @param strings array of strings + * @return total length of all the strings + */ + public static int getLength(String[] strings) + { + int length = 0; + for (String string : strings) + { + length += (string == null) ? 4 : string.length(); + } + return length; + } + + public static String getTraceString(StackTraceElement[] trace) + { + final StringBuilder sbString = new StringBuilder(); + for (StackTraceElement element : trace) + { + sbString.append(element.toString()).append(Config.EOL); + } + return sbString.toString(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/util/Util.java b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/util/Util.java index 049664d3a8..2143c42c99 100644 --- a/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/util/Util.java +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/gameserver/util/Util.java @@ -33,7 +33,7 @@ import com.l2jmobius.Config; import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.enums.HtmlActionScope; import com.l2jmobius.gameserver.enums.IllegalActionPunishmentType; -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.instance.L2PcInstance; @@ -652,7 +652,7 @@ public final class Util } final L2Character cha = (L2Character) obj; - if (((cha.getZ() < (npc.getZ() - 100)) && (cha.getZ() > (npc.getZ() + 100))) || !GeoData.getInstance().canSeeTarget(cha.getX(), cha.getY(), cha.getZ(), npc.getX(), npc.getY(), npc.getZ())) + if (((cha.getZ() < (npc.getZ() - 100)) && (cha.getZ() > (npc.getZ() + 100))) || !GeoEngine.getInstance().canSeeTarget(cha, npc)) { continue; } diff --git a/L2J_Mobius_HighFive/java/com/l2jmobius/tools/geodataconverter/GeoDataConverter.java b/L2J_Mobius_HighFive/java/com/l2jmobius/tools/geodataconverter/GeoDataConverter.java new file mode 100644 index 0000000000..5fe0abe3e4 --- /dev/null +++ b/L2J_Mobius_HighFive/java/com/l2jmobius/tools/geodataconverter/GeoDataConverter.java @@ -0,0 +1,375 @@ +/* + * 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 . + */ +package com.l2jmobius.tools.geodataconverter; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.RandomAccessFile; +import java.nio.ByteOrder; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.util.Scanner; + +import com.l2jmobius.Config; +import com.l2jmobius.gameserver.geoengine.geodata.ABlock; +import com.l2jmobius.gameserver.geoengine.geodata.BlockComplex; +import com.l2jmobius.gameserver.geoengine.geodata.BlockFlat; +import com.l2jmobius.gameserver.geoengine.geodata.BlockMultilayer; +import com.l2jmobius.gameserver.geoengine.geodata.GeoFormat; +import com.l2jmobius.gameserver.geoengine.geodata.GeoStructure; +import com.l2jmobius.gameserver.model.L2World; +import com.l2jmobius.util.PropertiesParser; + +/** + * @author Hasha + */ +public final class GeoDataConverter +{ + private static GeoFormat _format; + private static ABlock[][] _blocks; + + public static void main(String[] args) + { + // initialize config + loadGeoengineConfigs(); + + // get geodata format + String type = ""; + try (Scanner scn = new Scanner(System.in)) + { + while (!(type.equalsIgnoreCase("J") || type.equalsIgnoreCase("O") || type.equalsIgnoreCase("E"))) + { + System.out.println("GeoDataConverter: Select source geodata type:"); + System.out.println(" J: L2J (e.g. 23_22.l2j)"); + System.out.println(" O: L2OFF (e.g. 23_22_conv.dat)"); + System.out.println(" E: Exit"); + System.out.print("Choice: "); + type = scn.next(); + } + } + if (type.equalsIgnoreCase("E")) + { + System.exit(0); + } + + _format = type.equalsIgnoreCase("J") ? GeoFormat.L2J : GeoFormat.L2OFF; + + // start conversion + System.out.println("GeoDataConverter: Converting all " + _format.toString() + " files."); + + // initialize geodata container + _blocks = new ABlock[GeoStructure.REGION_BLOCKS_X][GeoStructure.REGION_BLOCKS_Y]; + + // initialize multilayer temporarily buffer + BlockMultilayer.initialize(); + + // load geo files + int converted = 0; + for (int rx = L2World.TILE_X_MIN; rx <= L2World.TILE_X_MAX; rx++) + { + for (int ry = L2World.TILE_Y_MIN; ry <= L2World.TILE_Y_MAX; ry++) + { + final String input = String.format(_format.getFilename(), rx, ry); + final String filepath = Config.GEODATA_PATH; + File f = new File(filepath + input); + if (f.exists() && !f.isDirectory()) + { + // load geodata + if (!loadGeoBlocks(input)) + { + System.out.println("GeoDataConverter: Unable to load " + input + " region file."); + continue; + } + + // recalculate nswe + if (!recalculateNswe()) + { + System.out.println("GeoDataConverter: Unable to convert " + input + " region file."); + continue; + } + + // save geodata + final String output = String.format(GeoFormat.L2D.getFilename(), rx, ry); + if (!saveGeoBlocks(output)) + { + System.out.println("GeoDataConverter: Unable to save " + output + " region file."); + continue; + } + + converted++; + System.out.println("GeoDataConverter: Created " + output + " region file."); + } + } + } + System.out.println("GeoDataConverter: Converted " + converted + " " + _format.toString() + " to L2D region file(s)."); + + // release multilayer block temporarily buffer + BlockMultilayer.release(); + } + + /** + * Loads geo blocks from buffer of the region file. + * @param filename : The name of the to load. + * @return boolean : True when successful. + */ + private static final boolean loadGeoBlocks(String filename) + { + // region file is load-able, try to load it + try (RandomAccessFile raf = new RandomAccessFile(Config.GEODATA_PATH + filename, "r"); + FileChannel fc = raf.getChannel()) + { + MappedByteBuffer buffer = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()).load(); + buffer.order(ByteOrder.LITTLE_ENDIAN); + + // load 18B header for L2off geodata (1st and 2nd byte...region X and Y) + if (_format == GeoFormat.L2OFF) + { + for (int i = 0; i < 18; i++) + { + buffer.get(); + } + } + + // loop over region blocks + for (int ix = 0; ix < GeoStructure.REGION_BLOCKS_X; ix++) + { + for (int iy = 0; iy < GeoStructure.REGION_BLOCKS_Y; iy++) + { + if (_format == GeoFormat.L2J) + { + // get block type + final byte type = buffer.get(); + + // load block according to block type + switch (type) + { + case GeoStructure.TYPE_FLAT_L2J_L2OFF: + _blocks[ix][iy] = new BlockFlat(buffer, _format); + break; + + case GeoStructure.TYPE_COMPLEX_L2J: + _blocks[ix][iy] = new BlockComplex(buffer, _format); + break; + + case GeoStructure.TYPE_MULTILAYER_L2J: + _blocks[ix][iy] = new BlockMultilayer(buffer, _format); + break; + + default: + throw new IllegalArgumentException("Unknown block type: " + type); + } + } + else + { + // get block type + final short type = buffer.getShort(); + + // load block according to block type + switch (type) + { + case GeoStructure.TYPE_FLAT_L2J_L2OFF: + _blocks[ix][iy] = new BlockFlat(buffer, _format); + break; + + case GeoStructure.TYPE_COMPLEX_L2OFF: + _blocks[ix][iy] = new BlockComplex(buffer, _format); + break; + + default: + _blocks[ix][iy] = new BlockMultilayer(buffer, _format); + break; + } + } + } + } + + if (buffer.remaining() > 0) + { + System.out.println("GeoDataConverter: Region file " + filename + " can be corrupted, remaining " + buffer.remaining() + " bytes to read."); + return false; + } + + return true; + } + catch (Exception e) + { + System.out.println("GeoDataConverter: Error while loading " + filename + " region file."); + return false; + } + } + + /** + * Recalculate diagonal flags for the region file. + * @return boolean : True when successful. + */ + private static final boolean recalculateNswe() + { + try + { + for (int x = 0; x < GeoStructure.REGION_CELLS_X; x++) + { + for (int y = 0; y < GeoStructure.REGION_CELLS_Y; y++) + { + // get block + ABlock block = _blocks[x / GeoStructure.BLOCK_CELLS_X][y / GeoStructure.BLOCK_CELLS_Y]; + + // skip flat blocks + if (block instanceof BlockFlat) + { + continue; + } + + // for complex and multilayer blocks go though all layers + short height = Short.MAX_VALUE; + int index; + while ((index = block.getIndexBelow(x, y, height)) != -1) + { + // get height and nswe + height = block.getHeight(index); + byte nswe = block.getNswe(index); + + // update nswe with diagonal flags + nswe = updateNsweBelow(x, y, height, nswe); + + // set nswe of the cell + block.setNswe(index, nswe); + } + } + } + + return true; + } + catch (Exception e) + { + return false; + } + } + + /** + * Updates the NSWE flag with diagonal flags. + * @param x : Geodata X coordinate. + * @param y : Geodata Y coordinate. + * @param z : Geodata Z coordinate. + * @param nswe : NSWE flag to be updated. + * @return byte : Updated NSWE flag. + */ + private static final byte updateNsweBelow(int x, int y, short z, byte nswe) + { + // calculate virtual layer height + short height = (short) (z + GeoStructure.CELL_IGNORE_HEIGHT); + + // get NSWE of neighbor cells below virtual layer (NPC/PC can fall down of clif, but can not climb it -> NSWE of cell below) + byte nsweN = getNsweBelow(x, y - 1, height); + byte nsweS = getNsweBelow(x, y + 1, height); + byte nsweW = getNsweBelow(x - 1, y, height); + byte nsweE = getNsweBelow(x + 1, y, height); + + // north-west + if ((((nswe & GeoStructure.CELL_FLAG_N) != 0) && ((nsweN & GeoStructure.CELL_FLAG_W) != 0)) || (((nswe & GeoStructure.CELL_FLAG_W) != 0) && ((nsweW & GeoStructure.CELL_FLAG_N) != 0))) + { + nswe |= GeoStructure.CELL_FLAG_NW; + } + + // north-east + if ((((nswe & GeoStructure.CELL_FLAG_N) != 0) && ((nsweN & GeoStructure.CELL_FLAG_E) != 0)) || (((nswe & GeoStructure.CELL_FLAG_E) != 0) && ((nsweE & GeoStructure.CELL_FLAG_N) != 0))) + { + nswe |= GeoStructure.CELL_FLAG_NE; + } + + // south-west + if ((((nswe & GeoStructure.CELL_FLAG_S) != 0) && ((nsweS & GeoStructure.CELL_FLAG_W) != 0)) || (((nswe & GeoStructure.CELL_FLAG_W) != 0) && ((nsweW & GeoStructure.CELL_FLAG_S) != 0))) + { + nswe |= GeoStructure.CELL_FLAG_SW; + } + + // south-east + if ((((nswe & GeoStructure.CELL_FLAG_S) != 0) && ((nsweS & GeoStructure.CELL_FLAG_E) != 0)) || (((nswe & GeoStructure.CELL_FLAG_E) != 0) && ((nsweE & GeoStructure.CELL_FLAG_S) != 0))) + { + nswe |= GeoStructure.CELL_FLAG_SE; + } + + return nswe; + } + + private static final byte getNsweBelow(int geoX, int geoY, short worldZ) + { + // out of geo coordinates + if ((geoX < 0) || (geoX >= GeoStructure.REGION_CELLS_X)) + { + return 0; + } + + // out of geo coordinates + if ((geoY < 0) || (geoY >= GeoStructure.REGION_CELLS_Y)) + { + return 0; + } + + // get block + final ABlock block = _blocks[geoX / GeoStructure.BLOCK_CELLS_X][geoY / GeoStructure.BLOCK_CELLS_Y]; + + // get index, when valid, return nswe + final int index = block.getIndexBelow(geoX, geoY, worldZ); + return index == -1 ? 0 : block.getNswe(index); + } + + /** + * Save region file to file. + * @param filename : The name of file to save. + * @return boolean : True when successful. + */ + private static final boolean saveGeoBlocks(String filename) + { + try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(Config.GEODATA_PATH + filename), GeoStructure.REGION_BLOCKS * GeoStructure.BLOCK_CELLS * 3)) + { + // loop over region blocks and save each block + for (int ix = 0; ix < GeoStructure.REGION_BLOCKS_X; ix++) + { + for (int iy = 0; iy < GeoStructure.REGION_BLOCKS_Y; iy++) + { + _blocks[ix][iy].saveBlock(bos); + } + } + + // flush data to file + bos.flush(); + + return true; + } + catch (Exception e) + { + return false; + } + } + + private static final void loadGeoengineConfigs() + { + final PropertiesParser geoData = new PropertiesParser(Config.GEODATA_FILE); + Config.GEODATA_PATH = geoData.getString("GeoDataPath", "./data/geodata/"); + Config.COORD_SYNCHRONIZE = geoData.getInt("CoordSynchronize", -1); + Config.PART_OF_CHARACTER_HEIGHT = geoData.getInt("PartOfCharacterHeight", 75); + Config.MAX_OBSTACLE_HEIGHT = geoData.getInt("MaxObstacleHeight", 32); + Config.PATHFINDING = geoData.getBoolean("PathFinding", true); + Config.PATHFIND_BUFFERS = geoData.getString("PathFindBuffers", "100x6;128x6;192x6;256x4;320x4;384x4;500x2"); + Config.BASE_WEIGHT = geoData.getInt("BaseWeight", 10); + Config.DIAGONAL_WEIGHT = geoData.getInt("DiagonalWeight", 14); + Config.OBSTACLE_MULTIPLIER = geoData.getInt("ObstacleMultiplier", 10); + Config.HEURISTIC_WEIGHT = geoData.getInt("HeuristicWeight", 20); + Config.MAX_ITERATIONS = geoData.getInt("MaxIterations", 3500); + } +} \ No newline at end of file diff --git a/L2J_Mobius_HighFive/readme.txt b/L2J_Mobius_HighFive/readme.txt index c424760c39..da03d5b2ce 100644 --- a/L2J_Mobius_HighFive/readme.txt +++ b/L2J_Mobius_HighFive/readme.txt @@ -1,5 +1,8 @@ L2J-Mobius High Five +Client: http://computergames.ro/download/lineage-ii-the-chaotic-throne-high-five-client/ +Geodata: http://www.mediafire.com/file/41cpkch7kyhhzqy/mobius_geodata_h5_l2d.zip + What is done -Dropped Python / Javolution / Trove -Nevit system diff --git a/L2J_Mobius_Underground/build.xml b/L2J_Mobius_Underground/build.xml index 1ae7e7e2bc..651b08aa54 100644 --- a/L2J_Mobius_Underground/build.xml +++ b/L2J_Mobius_Underground/build.xml @@ -74,6 +74,7 @@ + diff --git a/L2J_Mobius_Underground/dist/game/GeoDataConverter.bat b/L2J_Mobius_Underground/dist/game/GeoDataConverter.bat new file mode 100644 index 0000000000..1f199613e9 --- /dev/null +++ b/L2J_Mobius_Underground/dist/game/GeoDataConverter.bat @@ -0,0 +1,6 @@ +@echo off +title L2D geodata converter + +java -Xmx512m -cp ./../libs/*;GameServer.jar com.l2jmobius.tools.geodataconverter.GeoDataConverter + +pause diff --git a/L2J_Mobius_Underground/dist/game/GeoDataConverter.sh b/L2J_Mobius_Underground/dist/game/GeoDataConverter.sh new file mode 100644 index 0000000000..b039beec34 --- /dev/null +++ b/L2J_Mobius_Underground/dist/game/GeoDataConverter.sh @@ -0,0 +1,4 @@ +#! /bin/sh + +java -Xmx512m -cp ./../libs/*;GameServer.jar com.l2jmobius.tools.geodataconverter.GeoDataConverter > log/stdout.log 2>&1 + diff --git a/L2J_Mobius_Underground/dist/game/config/AdminCommands.xml b/L2J_Mobius_Underground/dist/game/config/AdminCommands.xml index d2ff6c880f..1cca083da9 100644 --- a/L2J_Mobius_Underground/dist/game/config/AdminCommands.xml +++ b/L2J_Mobius_Underground/dist/game/config/AdminCommands.xml @@ -413,11 +413,7 @@ - - - - - + diff --git a/L2J_Mobius_Underground/dist/game/config/GeoData.ini b/L2J_Mobius_Underground/dist/game/config/GeoData.ini deleted file mode 100644 index 52ef701461..0000000000 --- a/L2J_Mobius_Underground/dist/game/config/GeoData.ini +++ /dev/null @@ -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 diff --git a/L2J_Mobius_Underground/dist/game/config/GeoEngine.ini b/L2J_Mobius_Underground/dist/game/config/GeoEngine.ini new file mode 100644 index 0000000000..94a0b1ac44 --- /dev/null +++ b/L2J_Mobius_Underground/dist/game/config/GeoEngine.ini @@ -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 diff --git a/L2J_Mobius_Underground/dist/game/data/geodata/Readme.txt b/L2J_Mobius_Underground/dist/game/data/geodata/Readme.txt index bf1f2071aa..8b18814e82 100644 --- a/L2J_Mobius_Underground/dist/game/data/geodata/Readme.txt +++ b/L2J_Mobius_Underground/dist/game/data/geodata/Readme.txt @@ -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 # -# # -##################################################### \ No newline at end of file +############################################## +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. diff --git a/L2J_Mobius_Underground/dist/game/data/pathnode/Readme.txt b/L2J_Mobius_Underground/dist/game/data/pathnode/Readme.txt deleted file mode 100644 index 2dfdaa8aab..0000000000 --- a/L2J_Mobius_Underground/dist/game/data/pathnode/Readme.txt +++ /dev/null @@ -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 # -# # -##################################################### \ No newline at end of file diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/ImperialTomb/FourSepulchers/FourSepulchers.java b/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/ImperialTomb/FourSepulchers/FourSepulchers.java index d53bc8c351..954afd0819 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/ImperialTomb/FourSepulchers/FourSepulchers.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/ImperialTomb/FourSepulchers/FourSepulchers.java @@ -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); diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/KartiasLabyrinth/KartiaHelperAdolph.java b/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/KartiasLabyrinth/KartiaHelperAdolph.java index 2a3e8902fa..1e7527c930 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/KartiasLabyrinth/KartiaHelperAdolph.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/KartiasLabyrinth/KartiaHelperAdolph.java @@ -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)) { diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/KartiasLabyrinth/KartiaSupportTroop.java b/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/KartiasLabyrinth/KartiaSupportTroop.java index 4359ebca01..0b6462a39e 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/KartiasLabyrinth/KartiaSupportTroop.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/KartiasLabyrinth/KartiaSupportTroop.java @@ -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); } diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/PlainsOfDion/PlainsOfDion.java b/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/PlainsOfDion/PlainsOfDion.java index d6334e36c2..c1387a6527 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/PlainsOfDion/PlainsOfDion.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/PlainsOfDion/PlainsOfDion.java @@ -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)]); diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/PrimevalIsle/PrimevalIsle.java b/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/PrimevalIsle/PrimevalIsle.java index d02786fc20..1ccd0b2a99 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/PrimevalIsle/PrimevalIsle.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/PrimevalIsle/PrimevalIsle.java @@ -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) diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/BoyAndGirl.java b/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/BoyAndGirl.java index 64c6501bd8..594ba85809 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/BoyAndGirl.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/BoyAndGirl.java @@ -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); } diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/Devno.java b/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/Devno.java index 3dd3b671cb..5b67a2a2e7 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/Devno.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/Devno.java @@ -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); } diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/Eleve.java b/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/Eleve.java index 7900817585..2258392af4 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/Eleve.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/Eleve.java @@ -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); } diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/Handermonkey.java b/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/Handermonkey.java index cb173a5030..e66acd12da 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/Handermonkey.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/Handermonkey.java @@ -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 diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/Karonf.java b/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/Karonf.java index 7297eeca95..0cd3444fd8 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/Karonf.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/Karonf.java @@ -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); } diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/Marsha.java b/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/Marsha.java index dbbba8d5f0..bae9a9253a 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/Marsha.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/Marsha.java @@ -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); } diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/Morgan.java b/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/Morgan.java index f976d88263..fc7164bd5f 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/Morgan.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/Morgan.java @@ -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); } diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/Rubentis.java b/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/Rubentis.java index 19b9fd7893..e50e2bc306 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/Rubentis.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/ai/areas/TalkingIsland/Rubentis.java @@ -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); } diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/ai/bosses/Frintezza/ScarletVanHalisha.java b/L2J_Mobius_Underground/dist/game/data/scripts/ai/bosses/Frintezza/ScarletVanHalisha.java index 175973cc3d..139154e05a 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/ai/bosses/Frintezza/ScarletVanHalisha.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/ai/bosses/Frintezza/ScarletVanHalisha.java @@ -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; } diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/ai/bosses/Tiat/Stage1.java b/L2J_Mobius_Underground/dist/game/data/scripts/ai/bosses/Tiat/Stage1.java index 6eb16f838e..a852734cb4 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/ai/bosses/Tiat/Stage1.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/ai/bosses/Tiat/Stage1.java @@ -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); } } } diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/ai/bosses/Valakas/Valakas.java b/L2J_Mobius_Underground/dist/game/data/scripts/ai/bosses/Valakas/Valakas.java index 9f5375d349..4275a803e2 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/ai/bosses/Valakas/Valakas.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/ai/bosses/Valakas/Valakas.java @@ -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)); } diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/ai/others/FleeMonsters.java b/L2J_Mobius_Underground/dist/game/data/scripts/ai/others/FleeMonsters.java index b377af5c37..632e19d481 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/ai/others/FleeMonsters.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/ai/others/FleeMonsters.java @@ -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); } diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/actionhandlers/L2PcInstanceAction.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/actionhandlers/L2PcInstanceAction.java index eb06ec5594..13902652f4 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/actionhandlers/L2PcInstanceAction.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/actionhandlers/L2PcInstanceAction.java @@ -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); } diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/actionhandlers/L2PetInstanceAction.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/actionhandlers/L2PetInstanceAction.java index c21b0e6ca1..5c2fe5e762 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/actionhandlers/L2PetInstanceAction.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/actionhandlers/L2PetInstanceAction.java @@ -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(); diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/actionhandlers/L2SummonAction.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/actionhandlers/L2SummonAction.java index b6af1a7ca4..11b1192023 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/actionhandlers/L2SummonAction.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/actionhandlers/L2SummonAction.java @@ -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); } diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminGeodata.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminGeodata.java index bfa36a76d5..551e52bbb0 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminGeodata.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminGeodata.java @@ -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."); } diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminPathNode.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminPathNode.java index 03b3ca8902..9cb85c282f 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminPathNode.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminPathNode.java @@ -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 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 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; } diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminServerInfo.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminServerInfo.java index 6796381333..867836c680 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminServerInfo.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminServerInfo.java @@ -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")); diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminTeleport.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminTeleport.java index 1b738a0264..fbf049aae5 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminTeleport.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminTeleport.java @@ -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); } diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminZones.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminZones.java index d6949af214..d5baa52a73 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminZones.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminZones.java @@ -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); } diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/effecthandlers/Blink.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/effecthandlers/Blink.java index 0e1c1d1aca..db1463c04d 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/effecthandlers/Blink.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/effecthandlers/Blink.java @@ -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)); diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/effecthandlers/Fear.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/effecthandlers/Fear.java index 7525c0f5ec..78fc694005 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/effecthandlers/Fear.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/effecthandlers/Fear.java @@ -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); } } diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/effecthandlers/FlyAway.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/effecthandlers/FlyAway.java index 1da9965557..a4d5e7f74b 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/effecthandlers/FlyAway.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/effecthandlers/FlyAway.java @@ -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); diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/effecthandlers/KnockBack.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/effecthandlers/KnockBack.java index ad73aef663..e2ddb48286 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/effecthandlers/KnockBack.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/effecthandlers/KnockBack.java @@ -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)); diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/effecthandlers/PullBack.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/effecthandlers/PullBack.java index 7850b26d5d..07b43c83d3 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/effecthandlers/PullBack.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/effecthandlers/PullBack.java @@ -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); diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/effecthandlers/TeleportToSummon.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/effecthandlers/TeleportToSummon.java index 8144305363..bffc2aecce 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/effecthandlers/TeleportToSummon.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/effecthandlers/TeleportToSummon.java @@ -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)); diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/effecthandlers/TeleportToTarget.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/effecthandlers/TeleportToTarget.java index 93ffb3174d..81504f196e 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/effecthandlers/TeleportToTarget.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/effecthandlers/TeleportToTarget.java @@ -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)); diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/skillconditionhandlers/OpBlinkSkillCondition.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/skillconditionhandlers/OpBlinkSkillCondition.java index 4b33ad31b2..bea71eb6e5 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/skillconditionhandlers/OpBlinkSkillCondition.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/skillconditionhandlers/OpBlinkSkillCondition.java @@ -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()); } } diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/Enemy.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/Enemy.java index b16408fba4..91fc781e3f 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/Enemy.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/Enemy.java @@ -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) { diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/EnemyNot.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/EnemyNot.java index 005d4e0ee1..00d3d4d8e2 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/EnemyNot.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/EnemyNot.java @@ -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) { diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/EnemyOnly.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/EnemyOnly.java index 2f5a79d6f5..5815598285 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/EnemyOnly.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/EnemyOnly.java @@ -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) { diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/Ground.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/Ground.java index f3b38dcf71..280f19d239 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/Ground.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/Ground.java @@ -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) { diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/NpcBody.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/NpcBody.java index 699fa269c7..7f46507e5b 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/NpcBody.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/NpcBody.java @@ -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) { diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/PcBody.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/PcBody.java index 77a9c9edd3..0ef234b8ac 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/PcBody.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/PcBody.java @@ -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) { diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/Target.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/Target.java index b388976172..f8456ed9f9 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/Target.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/Target.java @@ -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) { diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/affectscope/Fan.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/affectscope/Fan.java index 2487c40d5e..59b2d086d5 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/affectscope/Fan.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/affectscope/Fan.java @@ -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; } diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/affectscope/FanPB.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/affectscope/FanPB.java index ec987c91eb..d6783cff58 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/affectscope/FanPB.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/affectscope/FanPB.java @@ -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; } diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/affectscope/PointBlank.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/affectscope/PointBlank.java index d6c63186a2..2f7568dd13 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/affectscope/PointBlank.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/affectscope/PointBlank.java @@ -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; } diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/affectscope/Range.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/affectscope/Range.java index 90abebd98f..1d8ccd51e8 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/affectscope/Range.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/affectscope/Range.java @@ -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; } diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/affectscope/RingRange.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/affectscope/RingRange.java index 6cbe61fe1c..24c89e82d5 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/affectscope/RingRange.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/affectscope/RingRange.java @@ -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; } diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/affectscope/Square.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/affectscope/Square.java index 3225de6245..c39a270d2c 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/affectscope/Square.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/affectscope/Square.java @@ -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; } diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/affectscope/SquarePB.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/affectscope/SquarePB.java index 7ffad78a8f..1f695cc99d 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/affectscope/SquarePB.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/targethandlers/affectscope/SquarePB.java @@ -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; } diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/quests/Q10753_WindsOfFateChoices/Q10753_WindsOfFateChoices.java b/L2J_Mobius_Underground/dist/game/data/scripts/quests/Q10753_WindsOfFateChoices/Q10753_WindsOfFateChoices.java index 27db36439a..a7b209b403 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/quests/Q10753_WindsOfFateChoices/Q10753_WindsOfFateChoices.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/quests/Q10753_WindsOfFateChoices/Q10753_WindsOfFateChoices.java @@ -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(); } diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/Config.java b/L2J_Mobius_Underground/java/com/l2jmobius/Config.java index 1dd46d6351..6ec607c7b0 100644 --- a/L2J_Mobius_Underground/java/com/l2jmobius/Config.java +++ b/L2J_Mobius_Underground/java/com/l2jmobius/Config.java @@ -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 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); diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/commons/util/MathUtil.java b/L2J_Mobius_Underground/java/com/l2jmobius/commons/util/MathUtil.java index 91dfcc4171..b0867bb70f 100644 --- a/L2J_Mobius_Underground/java/com/l2jmobius/commons/util/MathUtil.java +++ b/L2J_Mobius_Underground/java/com/l2jmobius/commons/util/MathUtil.java @@ -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); + } } diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/GameServer.java index 67d1225b4a..14faa1ccb9 100644 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/GameServer.java @@ -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; diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/ai/FriendlyNpcAI.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/ai/FriendlyNpcAI.java index 3eebee88ea..60fa4b1c8a 100644 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/ai/FriendlyNpcAI.java +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/ai/FriendlyNpcAI.java @@ -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()) { diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java index c363c397b5..46287d4e8e 100644 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java @@ -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) diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/ai/L2CharacterAI.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/ai/L2CharacterAI.java index 0d66c4a387..b046658f42 100644 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/ai/L2CharacterAI.java +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/ai/L2CharacterAI.java @@ -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; diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/ai/L2FortSiegeGuardAI.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/ai/L2FortSiegeGuardAI.java index 79f39cb51d..426228ee50 100644 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/ai/L2FortSiegeGuardAI.java +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/ai/L2FortSiegeGuardAI.java @@ -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 diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/ai/L2SiegeGuardAI.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/ai/L2SiegeGuardAI.java index caf5f39544..7cd4bb5dc1 100644 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/ai/L2SiegeGuardAI.java +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/ai/L2SiegeGuardAI.java @@ -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 diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/ai/L2SummonAI.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/ai/L2SummonAI.java index 00c00b8ff9..e29df8102b 100644 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/ai/L2SummonAI.java +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/ai/L2SummonAI.java @@ -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()); } diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/data/xml/impl/DoorData.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/data/xml/impl/DoorData.java index 973c82b4a8..592f3af578 100644 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/data/xml/impl/DoorData.java +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/data/xml/impl/DoorData.java @@ -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); } diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/GeoData.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/GeoData.java deleted file mode 100644 index a44ba3b703..0000000000 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/GeoData.java +++ /dev/null @@ -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 . - */ -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(); - } -} diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/Cell.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/Cell.java deleted file mode 100644 index 4914b1d72e..0000000000 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/Cell.java +++ /dev/null @@ -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 . - */ -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() - { - } -} diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/GeoDriver.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/GeoDriver.java deleted file mode 100644 index ffef644f31..0000000000 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/GeoDriver.java +++ /dev/null @@ -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 . - */ -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 _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; - } -} diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/IBlock.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/IBlock.java deleted file mode 100644 index 21df97c40d..0000000000 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/IBlock.java +++ /dev/null @@ -1,42 +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 . - */ -package com.l2jmobius.gameserver.geodata.geodriver; - -/** - * @author HorridoJoho - */ -public interface IBlock -{ - int TYPE_FLAT = 0; - int TYPE_COMPLEX = 1; - int TYPE_MULTILAYER = 2; - - /** Cells in a block on the x axis */ - int BLOCK_CELLS_X = 8; - /** Cells in a block on the y axis */ - int BLOCK_CELLS_Y = 8; - /** Cells in a block */ - int BLOCK_CELLS = BLOCK_CELLS_X * BLOCK_CELLS_Y; - - boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe); - - int getNearestZ(int geoX, int geoY, int worldZ); - - int getNextLowerZ(int geoX, int geoY, int worldZ); - - int getNextHigherZ(int geoX, int geoY, int worldZ); -} diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/IRegion.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/IRegion.java deleted file mode 100644 index 3eb23da03e..0000000000 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/IRegion.java +++ /dev/null @@ -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 . - */ -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(); -} diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/ComplexBlock.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/ComplexBlock.java deleted file mode 100644 index 4d6410672e..0000000000 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/ComplexBlock.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/FlatBlock.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/FlatBlock.java deleted file mode 100644 index d5bcff094b..0000000000 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/FlatBlock.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/MultilayerBlock.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/MultilayerBlock.java deleted file mode 100644 index 313131bd5a..0000000000 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/blocks/MultilayerBlock.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/regions/NullRegion.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/regions/NullRegion.java deleted file mode 100644 index 60ecac873a..0000000000 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/regions/NullRegion.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/regions/Region.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/regions/Region.java deleted file mode 100644 index d2d02481ed..0000000000 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/geodriver/regions/Region.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNode.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNode.java deleted file mode 100644 index e3476f28c2..0000000000 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNode.java +++ /dev/null @@ -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 . - */ -package com.l2jmobius.gameserver.geodata.pathfinding; - -public abstract class AbstractNode -{ - private T _loc; - private AbstractNode _parent; - - public AbstractNode(T loc) - { - _loc = loc; - } - - public void setParent(AbstractNode p) - { - _parent = p; - } - - public AbstractNode 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; - } -} \ No newline at end of file diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNodeLoc.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNodeLoc.java deleted file mode 100644 index ec3bd23d44..0000000000 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/AbstractNodeLoc.java +++ /dev/null @@ -1,33 +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 . - */ -package com.l2jmobius.gameserver.geodata.pathfinding; - -/** - * @author -Nemesiss- - */ -public abstract class AbstractNodeLoc -{ - public abstract int getX(); - - public abstract int getY(); - - public abstract int getZ(); - - public abstract int getNodeX(); - - public abstract int getNodeY(); -} diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/PathFinding.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/PathFinding.java deleted file mode 100644 index c1fbd19084..0000000000 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/PathFinding.java +++ /dev/null @@ -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 . - */ -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 findPath(int x, int y, int z, int tx, int ty, int tz, Instance instance, boolean playable); - - // @formatter:off - /* - public List 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 visited = new LinkedList(); - - // List of Nodes to Visit - LinkedList to_visit = new LinkedList(); - 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 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; - } -} diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNode.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNode.java deleted file mode 100644 index dd2c0f2d8e..0000000000 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNode.java +++ /dev/null @@ -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 . - */ -package com.l2jmobius.gameserver.geodata.pathfinding.cellnodes; - -import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNode; - -public class CellNode extends AbstractNode -{ - 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; - } -} \ No newline at end of file diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNodeBuffer.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNodeBuffer.java deleted file mode 100644 index 5747e430ea..0000000000 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellNodeBuffer.java +++ /dev/null @@ -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 . - */ -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 debugPath() - { - final List 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; - } -} \ No newline at end of file diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellPathFinding.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellPathFinding.java deleted file mode 100644 index 1e7da4ca3b..0000000000 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/CellPathFinding.java +++ /dev/null @@ -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 . - */ -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 _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 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 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 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 constructPath(AbstractNode node) - { - final LinkedList 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 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(); - } -} diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/NodeLoc.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/NodeLoc.java deleted file mode 100644 index f0720ae1ae..0000000000 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/cellnodes/NodeLoc.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNode.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNode.java deleted file mode 100644 index e9461b122a..0000000000 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNode.java +++ /dev/null @@ -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 . - */ -package com.l2jmobius.gameserver.geodata.pathfinding.geonodes; - -import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNode; - -/** - * @author -Nemesiss- - */ -public class GeoNode extends AbstractNode -{ - 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); - } - } -} diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNodeLoc.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNodeLoc.java deleted file mode 100644 index 3721b3a75e..0000000000 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoNodeLoc.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoPathFinding.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoPathFinding.java deleted file mode 100644 index 8641ce07e0..0000000000 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/geonodes/GeoPathFinding.java +++ /dev/null @@ -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 . - */ -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 _pathNodes = new ConcurrentHashMap<>(); - private static Map _pathNodesIndex = new ConcurrentHashMap<>(); - - public static GeoPathFinding getInstance() - { - return SingletonHolder._instance; - } - - @Override - public boolean pathNodesExist(short regionoffset) - { - return _pathNodesIndex.containsKey(regionoffset); - } - - @Override - public List 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 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 visited = new ArrayList<>(550); - - // List of Nodes to Visit - final LinkedList 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 constructPath2(AbstractNode node) - { - final LinkedList 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> 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(); - } -} diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/utils/BinaryNodeHeap.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/utils/BinaryNodeHeap.java deleted file mode 100644 index a6aae4c662..0000000000 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geodata/pathfinding/utils/BinaryNodeHeap.java +++ /dev/null @@ -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 . - */ -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; - } -} diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java new file mode 100644 index 0000000000..587aab48e2 --- /dev/null +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java @@ -0,0 +1,1311 @@ +/* + * 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 . + */ +package com.l2jmobius.gameserver.geoengine; + +import java.io.File; +import java.io.RandomAccessFile; +import java.nio.ByteOrder; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.util.List; +import java.util.logging.Logger; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.MathUtil; +import com.l2jmobius.gameserver.data.xml.impl.DoorData; +import com.l2jmobius.gameserver.geoengine.geodata.ABlock; +import com.l2jmobius.gameserver.geoengine.geodata.BlockComplex; +import com.l2jmobius.gameserver.geoengine.geodata.BlockComplexDynamic; +import com.l2jmobius.gameserver.geoengine.geodata.BlockFlat; +import com.l2jmobius.gameserver.geoengine.geodata.BlockMultilayer; +import com.l2jmobius.gameserver.geoengine.geodata.BlockMultilayerDynamic; +import com.l2jmobius.gameserver.geoengine.geodata.BlockNull; +import com.l2jmobius.gameserver.geoengine.geodata.GeoFormat; +import com.l2jmobius.gameserver.geoengine.geodata.GeoLocation; +import com.l2jmobius.gameserver.geoengine.geodata.GeoStructure; +import com.l2jmobius.gameserver.geoengine.geodata.IBlockDynamic; +import com.l2jmobius.gameserver.geoengine.geodata.IGeoObject; +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.actor.L2Character; +import com.l2jmobius.gameserver.model.actor.instance.L2DoorInstance; +import com.l2jmobius.gameserver.model.instancezone.Instance; + +/** + * @author Hasha + */ +public class GeoEngine +{ + protected static final Logger _log = Logger.getLogger(GeoEngine.class.getName()); + + private final ABlock[][] _blocks; + private final BlockNull _nullBlock; + + /** + * Returns the instance of the {@link GeoEngine}. + * @return {@link GeoEngine} : The instance. + */ + public static final GeoEngine getInstance() + { + return SingletonHolder._instance; + } + + /** + * GeoEngine contructor. Loads all geodata files of chosen geodata format. + */ + public GeoEngine() + { + _log.info("GeoEngine: Initializing..."); + + // initialize block container + _blocks = new ABlock[GeoStructure.GEO_BLOCKS_X][GeoStructure.GEO_BLOCKS_Y]; + + // load null block + _nullBlock = new BlockNull(); + + // initialize multilayer temporarily buffer + BlockMultilayer.initialize(); + + // load geo files according to geoengine config setup + int loaded = 0; + int failed = 0; + for (int rx = L2World.TILE_X_MIN; rx <= L2World.TILE_X_MAX; rx++) + { + for (int ry = L2World.TILE_Y_MIN; ry <= L2World.TILE_Y_MAX; ry++) + { + final String filename = String.format(GeoFormat.L2D.getFilename(), rx, ry); + final String filepath = Config.GEODATA_PATH; + File f = new File(filepath + filename); + if (f.exists() && !f.isDirectory()) + { + // region file is load-able, try to load it + if (loadGeoBlocks(rx, ry)) + { + loaded++; + } + else + { + failed++; + } + } + else + { + // region file is not load-able, load null blocks + loadNullBlocks(rx, ry); + } + } + } + _log.info("GeoEngine: Loaded " + loaded + " L2D region files."); + + // Avoid wrong config when no files loaded + if ((loaded == 0) && (Config.COORD_SYNCHRONIZE == 2)) + { + Config.COORD_SYNCHRONIZE = -1; + _log.info("GeoEngine: Forcing CoordSynchronize setting to -1."); + } + + // release multilayer block temporarily buffer + BlockMultilayer.release(); + + if (failed > 0) + { + _log.info("GeoEngine: Failed to load " + failed + " L2D region files. Please consider to check your \"GeoEngine.ini\" settings and location of \"XX_YY.L2D\" geodata files."); + System.exit(1); + } + } + + /** + * Loads geodata from a file. When file does not exist, is corrupted or not consistent, loads none geodata. + * @param regionX : Geodata file region X coordinate. + * @param regionY : Geodata file region Y coordinate. + * @return boolean : True, when geodata file was loaded without problem. + */ + private final boolean loadGeoBlocks(int regionX, int regionY) + { + final String filename = String.format(GeoFormat.L2D.getFilename(), regionX, regionY); + final String filepath = Config.GEODATA_PATH + filename; + + // standard load + try (RandomAccessFile raf = new RandomAccessFile(filepath, "r"); + FileChannel fc = raf.getChannel()) + { + // initialize file buffer + MappedByteBuffer buffer = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()).load(); + buffer.order(ByteOrder.LITTLE_ENDIAN); + + // get block indexes + final int blockX = (regionX - L2World.TILE_X_MIN) * GeoStructure.REGION_BLOCKS_X; + final int blockY = (regionY - L2World.TILE_Y_MIN) * GeoStructure.REGION_BLOCKS_Y; + + // loop over region blocks + for (int ix = 0; ix < GeoStructure.REGION_BLOCKS_X; ix++) + { + for (int iy = 0; iy < GeoStructure.REGION_BLOCKS_Y; iy++) + { + // get block type + final byte type = buffer.get(); + + // load block according to block type + switch (type) + { + case GeoStructure.TYPE_FLAT_L2D: + _blocks[blockX + ix][blockY + iy] = new BlockFlat(buffer, GeoFormat.L2D); + break; + + case GeoStructure.TYPE_COMPLEX_L2D: + _blocks[blockX + ix][blockY + iy] = new BlockComplex(buffer, GeoFormat.L2D); + break; + + case GeoStructure.TYPE_MULTILAYER_L2D: + _blocks[blockX + ix][blockY + iy] = new BlockMultilayer(buffer, GeoFormat.L2D); + break; + + default: + throw new IllegalArgumentException("Unknown block type: " + type); + } + } + } + + // check data consistency + if (buffer.remaining() > 0) + { + _log.warning("GeoEngine: Region file " + filename + " can be corrupted, remaining " + buffer.remaining() + " bytes to read."); + } + + // loading was successful + return true; + } + catch (Exception e) + { + // an error occured while loading, load null blocks + _log.warning("GeoEngine: Error while loading " + filename + " region file."); + _log.warning(e.getMessage()); + e.printStackTrace(); + + // replace whole region file with null blocks + loadNullBlocks(regionX, regionY); + + // loading was not successful + return false; + } + } + + /** + * Loads null blocks. Used when no region file is detected or an error occurs during loading. + * @param regionX : Geodata file region X coordinate. + * @param regionY : Geodata file region Y coordinate. + */ + private final void loadNullBlocks(int regionX, int regionY) + { + // get block indexes + final int blockX = (regionX - L2World.TILE_X_MIN) * GeoStructure.REGION_BLOCKS_X; + final int blockY = (regionY - L2World.TILE_Y_MIN) * GeoStructure.REGION_BLOCKS_Y; + + // load all null blocks + for (int ix = 0; ix < GeoStructure.REGION_BLOCKS_X; ix++) + { + for (int iy = 0; iy < GeoStructure.REGION_BLOCKS_Y; iy++) + { + _blocks[blockX + ix][blockY + iy] = _nullBlock; + } + } + } + + // GEODATA - GENERAL + + /** + * Converts world X to geodata X. + * @param worldX + * @return int : Geo X + */ + public final int getGeoX(int worldX) + { + return (MathUtil.limit(worldX, L2World.MAP_MIN_X, L2World.MAP_MAX_X) - L2World.MAP_MIN_X) >> 4; + } + + /** + * Converts world Y to geodata Y. + * @param worldY + * @return int : Geo Y + */ + public final int getGeoY(int worldY) + { + return (MathUtil.limit(worldY, L2World.MAP_MIN_Y, L2World.MAP_MAX_Y) - L2World.MAP_MIN_Y) >> 4; + } + + /** + * Converts geodata X to world X. + * @param geoX + * @return int : World X + */ + public final int getWorldX(int geoX) + { + return (MathUtil.limit(geoX, 0, GeoStructure.GEO_CELLS_X) << 4) + L2World.MAP_MIN_X + 8; + } + + /** + * Converts geodata Y to world Y. + * @param geoY + * @return int : World Y + */ + public final int getWorldY(int geoY) + { + return (MathUtil.limit(geoY, 0, GeoStructure.GEO_CELLS_Y) << 4) + L2World.MAP_MIN_Y + 8; + } + + /** + * Returns block of geodata on given coordinates. + * @param geoX : Geodata X + * @param geoY : Geodata Y + * @return {@link ABlock} : Bloack of geodata. + */ + public final ABlock getBlock(int geoX, int geoY) + { + return _blocks[geoX / GeoStructure.BLOCK_CELLS_X][geoY / GeoStructure.BLOCK_CELLS_Y]; + } + + /** + * Check if geo coordinates has geo. + * @param geoX : Geodata X + * @param geoY : Geodata Y + * @return boolean : True, if given geo coordinates have geodata + */ + public final boolean hasGeoPos(int geoX, int geoY) + { + return getBlock(geoX, geoY).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, closest to given coordinates. + */ + public final short getHeightNearest(int geoX, int geoY, int worldZ) + { + return getBlock(geoX, geoY).getHeightNearest(geoX, geoY, worldZ); + } + + /** + * Returns the height of cell, which is closest to given coordinates.
+ * 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, closest to given coordinates. + */ + public final short getHeightNearestOriginal(int geoX, int geoY, int worldZ) + { + return getBlock(geoX, geoY).getHeightNearestOriginal(geoX, geoY, worldZ); + } + + /** + * Returns the NSWE flag byte of cell, which is closes 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 coordinate, closest to given coordinates. + */ + public final byte getNsweNearest(int geoX, int geoY, int worldZ) + { + return getBlock(geoX, geoY).getNsweNearest(geoX, geoY, worldZ); + } + + /** + * Returns the NSWE flag byte of cell, which is closes to given coordinates.
+ * 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 coordinate, closest to given coordinates. + */ + public final byte getNsweNearestOriginal(int geoX, int geoY, int worldZ) + { + return getBlock(geoX, geoY).getNsweNearestOriginal(geoX, geoY, worldZ); + } + + /** + * Check if world coordinates has geo. + * @param worldX : World X + * @param worldY : World Y + * @return boolean : True, if given world coordinates have geodata + */ + public final boolean hasGeo(int worldX, int worldY) + { + return hasGeoPos(getGeoX(worldX), getGeoY(worldY)); + } + + /** + * Returns closest Z coordinate according to geodata. + * @param worldX : world x + * @param worldY : world y + * @param worldZ : world z + * @return short : nearest Z coordinates according to geodata + */ + public final short getHeight(int worldX, int worldY, int worldZ) + { + return getHeightNearest(getGeoX(worldX), getGeoY(worldY), worldZ); + } + + // GEODATA - DYNAMIC + + /** + * Returns calculated NSWE flag byte as a description of {@link IGeoObject}.
+ * The {@link IGeoObject} is defined by boolean 2D array, saying if the object is present on given cell or not. + * @param inside : 2D description of {@link IGeoObject} + * @return byte[][] : Returns NSWE flags of {@link IGeoObject}. + */ + public static final byte[][] calculateGeoObject(boolean inside[][]) + { + // get dimensions + final int width = inside.length; + final int height = inside[0].length; + + // create object flags for geodata, according to the geo object 2D description + final byte[][] result = new byte[width][height]; + + // loop over each cell of the geo object + for (int ix = 0; ix < width; ix++) + { + for (int iy = 0; iy < height; iy++) + { + if (inside[ix][iy]) + { + // cell is inside geo object, block whole movement (nswe = 0) + result[ix][iy] = 0; + } + else + { + // cell is outside of geo object, block only movement leading inside geo object + + // set initial value -> no geodata change + byte nswe = (byte) 0xFF; + + // perform axial and diagonal checks + if (iy < (height - 1)) + { + if (inside[ix][iy + 1]) + { + nswe &= ~GeoStructure.CELL_FLAG_S; + } + } + if (iy > 0) + { + if (inside[ix][iy - 1]) + { + nswe &= ~GeoStructure.CELL_FLAG_N; + } + } + if (ix < (width - 1)) + { + if (inside[ix + 1][iy]) + { + nswe &= ~GeoStructure.CELL_FLAG_E; + } + } + if (ix > 0) + { + if (inside[ix - 1][iy]) + { + nswe &= ~GeoStructure.CELL_FLAG_W; + } + } + if ((ix < (width - 1)) && (iy < (height - 1))) + { + if (inside[ix + 1][iy + 1] || inside[ix][iy + 1] || inside[ix + 1][iy]) + { + nswe &= ~GeoStructure.CELL_FLAG_SE; + } + } + if ((ix < (width - 1)) && (iy > 0)) + { + if (inside[ix + 1][iy - 1] || inside[ix][iy - 1] || inside[ix + 1][iy]) + { + nswe &= ~GeoStructure.CELL_FLAG_NE; + } + } + if ((ix > 0) && (iy < (height - 1))) + { + if (inside[ix - 1][iy + 1] || inside[ix][iy + 1] || inside[ix - 1][iy]) + { + nswe &= ~GeoStructure.CELL_FLAG_SW; + } + } + if ((ix > 0) && (iy > 0)) + { + if (inside[ix - 1][iy - 1] || inside[ix][iy - 1] || inside[ix - 1][iy]) + { + nswe &= ~GeoStructure.CELL_FLAG_NW; + } + } + + result[ix][iy] = nswe; + } + } + } + + return result; + } + + /** + * Add {@link IGeoObject} to the geodata. + * @param object : An object using {@link IGeoObject} interface. + */ + public final void addGeoObject(IGeoObject object) + { + toggleGeoObject(object, true); + } + + /** + * Remove {@link IGeoObject} from the geodata. + * @param object : An object using {@link IGeoObject} interface. + */ + public final void removeGeoObject(IGeoObject object) + { + toggleGeoObject(object, false); + } + + /** + * Toggles an {@link IGeoObject} in the geodata. + * @param object : An object using {@link IGeoObject} interface. + * @param add : Add/remove object. + */ + private final void toggleGeoObject(IGeoObject object, boolean add) + { + // get object geo coordinates and data + final int minGX = object.getGeoX(); + final int minGY = object.getGeoY(); + final byte[][] geoData = object.getObjectGeoData(); + + // get min/max block coordinates + int minBX = minGX / GeoStructure.BLOCK_CELLS_X; + int maxBX = ((minGX + geoData.length) - 1) / GeoStructure.BLOCK_CELLS_X; + int minBY = minGY / GeoStructure.BLOCK_CELLS_Y; + int maxBY = ((minGY + geoData[0].length) - 1) / GeoStructure.BLOCK_CELLS_Y; + + // loop over affected blocks in X direction + for (int bx = minBX; bx <= maxBX; bx++) + { + // loop over affected blocks in Y direction + for (int by = minBY; by <= maxBY; by++) + { + ABlock block; + + // conversion to dynamic block must be synchronized to prevent 2 independent threads converting same block + synchronized (_blocks) + { + // get related block + block = _blocks[bx][by]; + + // check for dynamic block + if (!(block instanceof IBlockDynamic)) + { + // null block means no geodata (particular region file is not loaded), no geodata means no geobjects + if (block instanceof BlockNull) + { + continue; + } + + // not a dynamic block, convert it + if (block instanceof BlockFlat) + { + // convert flat block to the dynamic complex block + block = new BlockComplexDynamic(bx, by, (BlockFlat) block); + _blocks[bx][by] = block; + } + else if (block instanceof BlockComplex) + { + // convert complex block to the dynamic complex block + block = new BlockComplexDynamic(bx, by, (BlockComplex) block); + _blocks[bx][by] = block; + } + else if (block instanceof BlockMultilayer) + { + // convert multilayer block to the dynamic multilayer block + block = new BlockMultilayerDynamic(bx, by, (BlockMultilayer) block); + _blocks[bx][by] = block; + } + } + } + + // add/remove geo object to/from dynamic block + if (add) + { + ((IBlockDynamic) block).addGeoObject(object); + } + else + { + ((IBlockDynamic) block).removeGeoObject(object); + } + } + } + } + + // PATHFINDING + + /** + * Check line of sight from {@link L2Object} to {@link L2Object}. + * @param origin : The origin object. + * @param target : The target object. + * @return {@code boolean} : True if origin can see target + */ + public final boolean canSeeTarget(L2Object origin, L2Object target) + { + // get origin and target world coordinates + final int ox = origin.getX(); + final int oy = origin.getY(); + final int oz = origin.getZ(); + final int tx = target.getX(); + final int ty = target.getY(); + final int tz = target.getZ(); + + // get origin and check existing geo coordinates + final int gox = getGeoX(ox); + final int goy = getGeoY(oy); + if (!hasGeoPos(gox, goy)) + { + return true; + } + + final short goz = getHeightNearest(gox, goy, oz); + + // get target and check existing geo coordinates + final int gtx = getGeoX(tx); + final int gty = getGeoY(ty); + if (!hasGeoPos(gtx, gty)) + { + return true; + } + + final boolean door = target.isDoor(); + final short gtz = door ? getHeightNearestOriginal(gtx, gty, tz) : getHeightNearest(gtx, gty, tz); + + // origin and target coordinates are same + if ((gox == gtx) && (goy == gty)) + { + return goz == gtz; + } + + // get origin and target height, real height = collision height * 2 + double oheight = 0; + if (origin.isCharacter()) + { + oheight = ((L2Character) origin).getCollisionHeight() * 2; + } + + double theight = 0; + if (target.isCharacter()) + { + theight = ((L2Character) target).getCollisionHeight() * 2; + } + + // perform geodata check + return door ? checkSeeOriginal(gox, goy, goz, oheight, gtx, gty, gtz, theight) : checkSee(gox, goy, goz, oheight, gtx, gty, gtz, theight); + } + + /** + * Check line of sight from {@link L2Object} to {@link Location}. + * @param origin : The origin object. + * @param position : The target position. + * @return {@code boolean} : True if object can see position + */ + public final boolean canSeeTarget(L2Object origin, Location position) + { + // get origin and target world coordinates + final int ox = origin.getX(); + final int oy = origin.getY(); + final int oz = origin.getZ(); + final int tx = position.getX(); + final int ty = position.getY(); + final int tz = position.getZ(); + + // get origin and check existing geo coordinates + final int gox = getGeoX(ox); + final int goy = getGeoY(oy); + if (!hasGeoPos(gox, goy)) + { + return true; + } + + final short goz = getHeightNearest(gox, goy, oz); + + // get target and check existing geo coordinates + final int gtx = getGeoX(tx); + final int gty = getGeoY(ty); + if (!hasGeoPos(gtx, gty)) + { + return true; + } + + final short gtz = getHeightNearest(gtx, gty, tz); + + // origin and target coordinates are same + if ((gox == gtx) && (goy == gty)) + { + return goz == gtz; + } + + // get origin and target height, real height = collision height * 2 + double oheight = 0; + if (origin instanceof L2Character) + { + oheight = ((L2Character) origin).getTemplate().getCollisionHeight(); + } + + // perform geodata check + return checkSee(gox, goy, goz, oheight, gtx, gty, gtz, 0); + } + + /** + * Simple check for origin to target visibility. + * @param gox : origin X geodata coordinate + * @param goy : origin Y geodata coordinate + * @param goz : origin Z geodata coordinate + * @param oheight : origin height (if instance of {@link Character}) + * @param gtx : target X geodata coordinate + * @param gty : target Y geodata coordinate + * @param gtz : target Z geodata coordinate + * @param theight : target height (if instance of {@link Character}) + * @return {@code boolean} : True, when target can be seen. + */ + protected final boolean checkSee(int gox, int goy, int goz, double oheight, int gtx, int gty, int gtz, double theight) + { + // get line of sight Z coordinates + double losoz = goz + ((oheight * Config.PART_OF_CHARACTER_HEIGHT) / 100); + double lostz = gtz + ((theight * Config.PART_OF_CHARACTER_HEIGHT) / 100); + + // get X delta and signum + final int dx = Math.abs(gtx - gox); + final int sx = gox < gtx ? 1 : -1; + final byte dirox = sx > 0 ? GeoStructure.CELL_FLAG_E : GeoStructure.CELL_FLAG_W; + final byte dirtx = sx > 0 ? GeoStructure.CELL_FLAG_W : GeoStructure.CELL_FLAG_E; + + // get Y delta and signum + final int dy = Math.abs(gty - goy); + final int sy = goy < gty ? 1 : -1; + final byte diroy = sy > 0 ? GeoStructure.CELL_FLAG_S : GeoStructure.CELL_FLAG_N; + final byte dirty = sy > 0 ? GeoStructure.CELL_FLAG_N : GeoStructure.CELL_FLAG_S; + + // get Z delta + final int dm = Math.max(dx, dy); + final double dz = (lostz - losoz) / dm; + + // get direction flag for diagonal movement + final byte diroxy = getDirXY(dirox, diroy); + final byte dirtxy = getDirXY(dirtx, dirty); + + // delta, determines axis to move on (+..X axis, -..Y axis) + int d = dx - dy; + + // NSWE direction of movement + byte diro; + byte dirt; + + // clearDebugItems(); + // dropDebugItem(728, 0, new GeoLocation(gox, goy, goz)); // blue potion + // dropDebugItem(728, 0, new GeoLocation(gtx, gty, gtz)); // blue potion + + // initialize node values + int nox = gox; + int noy = goy; + int ntx = gtx; + int nty = gty; + byte nsweo = getNsweNearest(gox, goy, goz); + byte nswet = getNsweNearest(gtx, gty, gtz); + + // loop + ABlock block; + int index; + for (int i = 0; i < ((dm + 1) / 2); i++) + { + // dropDebugItem(57, 0, new GeoLocation(gox, goy, goz)); // antidote + // dropDebugItem(1831, 0, new GeoLocation(gtx, gty, gtz)); // adena + + // reset direction flag + diro = 0; + dirt = 0; + + // calculate next point coordinates + int e2 = 2 * d; + if ((e2 > -dy) && (e2 < dx)) + { + // calculate next point XY coordinates + d -= dy; + d += dx; + nox += sx; + ntx -= sx; + noy += sy; + nty -= sy; + diro |= diroxy; + dirt |= dirtxy; + } + else if (e2 > -dy) + { + // calculate next point X coordinate + d -= dy; + nox += sx; + ntx -= sx; + diro |= dirox; + dirt |= dirtx; + } + else if (e2 < dx) + { + // calculate next point Y coordinate + d += dx; + noy += sy; + nty -= sy; + diro |= diroy; + dirt |= dirty; + } + + { + // get block of the next cell + block = getBlock(nox, noy); + + // get index of particular layer, based on movement conditions + if ((nsweo & diro) == 0) + { + index = block.getIndexAbove(nox, noy, goz - GeoStructure.CELL_IGNORE_HEIGHT); + } + else + { + index = block.getIndexBelow(nox, noy, goz + GeoStructure.CELL_IGNORE_HEIGHT); + } + + // layer does not exist, return + if (index == -1) + { + return false; + } + + // get layer and next line of sight Z coordinate + goz = block.getHeight(index); + losoz += dz; + + // perform line of sight check, return when fails + if ((goz - losoz) > Config.MAX_OBSTACLE_HEIGHT) + { + return false; + } + + // get layer nswe + nsweo = block.getNswe(index); + } + { + // get block of the next cell + block = getBlock(ntx, nty); + + // get index of particular layer, based on movement conditions + if ((nswet & dirt) == 0) + { + index = block.getIndexAbove(ntx, nty, gtz - GeoStructure.CELL_IGNORE_HEIGHT); + } + else + { + index = block.getIndexBelow(ntx, nty, gtz + GeoStructure.CELL_IGNORE_HEIGHT); + } + + // layer does not exist, return + if (index == -1) + { + return false; + } + + // get layer and next line of sight Z coordinate + gtz = block.getHeight(index); + lostz -= dz; + + // perform line of sight check, return when fails + if ((gtz - lostz) > Config.MAX_OBSTACLE_HEIGHT) + { + return false; + } + + // get layer nswe + nswet = block.getNswe(index); + } + + // update coords + gox = nox; + goy = noy; + gtx = ntx; + gty = nty; + } + + // when iteration is completed, compare final Z coordinates + return Math.abs(goz - gtz) < (GeoStructure.CELL_HEIGHT * 4); + } + + /** + * Simple check for origin to target visibility.
+ * Geodata without {@link IGeoObject} are taken in consideration.
+ * NOTE: When two doors close between each other and the LoS check of one doors is performed through another door, result will not be accurate (the other door are skipped). + * @param gox : origin X geodata coordinate + * @param goy : origin Y geodata coordinate + * @param goz : origin Z geodata coordinate + * @param oheight : origin height (if instance of {@link Character}) + * @param gtx : target X geodata coordinate + * @param gty : target Y geodata coordinate + * @param gtz : target Z geodata coordinate + * @param theight : target height (if instance of {@link Character} or {@link L2DoorInstance}) + * @return {@code boolean} : True, when target can be seen. + */ + protected final boolean checkSeeOriginal(int gox, int goy, int goz, double oheight, int gtx, int gty, int gtz, double theight) + { + // get line of sight Z coordinates + double losoz = goz + ((oheight * Config.PART_OF_CHARACTER_HEIGHT) / 100); + double lostz = gtz + ((theight * Config.PART_OF_CHARACTER_HEIGHT) / 100); + + // get X delta and signum + final int dx = Math.abs(gtx - gox); + final int sx = gox < gtx ? 1 : -1; + final byte dirox = sx > 0 ? GeoStructure.CELL_FLAG_E : GeoStructure.CELL_FLAG_W; + final byte dirtx = sx > 0 ? GeoStructure.CELL_FLAG_W : GeoStructure.CELL_FLAG_E; + + // get Y delta and signum + final int dy = Math.abs(gty - goy); + final int sy = goy < gty ? 1 : -1; + final byte diroy = sy > 0 ? GeoStructure.CELL_FLAG_S : GeoStructure.CELL_FLAG_N; + final byte dirty = sy > 0 ? GeoStructure.CELL_FLAG_N : GeoStructure.CELL_FLAG_S; + + // get Z delta + final int dm = Math.max(dx, dy); + final double dz = (lostz - losoz) / dm; + + // get direction flag for diagonal movement + final byte diroxy = getDirXY(dirox, diroy); + final byte dirtxy = getDirXY(dirtx, dirty); + + // delta, determines axis to move on (+..X axis, -..Y axis) + int d = dx - dy; + + // NSWE direction of movement + byte diro; + byte dirt; + + // clearDebugItems(); + // dropDebugItem(728, 0, new GeoLocation(gox, goy, goz)); // blue potion + // dropDebugItem(728, 0, new GeoLocation(gtx, gty, gtz)); // blue potion + + // initialize node values + int nox = gox; + int noy = goy; + int ntx = gtx; + int nty = gty; + byte nsweo = getNsweNearestOriginal(gox, goy, goz); + byte nswet = getNsweNearestOriginal(gtx, gty, gtz); + + // loop + ABlock block; + int index; + for (int i = 0; i < ((dm + 1) / 2); i++) + { + // dropDebugItem(57, 0, new GeoLocation(gox, goy, goz)); // antidote + // dropDebugItem(1831, 0, new GeoLocation(gtx, gty, gtz)); // adena + + // reset direction flag + diro = 0; + dirt = 0; + + // calculate next point coordinates + int e2 = 2 * d; + if ((e2 > -dy) && (e2 < dx)) + { + // calculate next point XY coordinates + d -= dy; + d += dx; + nox += sx; + ntx -= sx; + noy += sy; + nty -= sy; + diro |= diroxy; + dirt |= dirtxy; + } + else if (e2 > -dy) + { + // calculate next point X coordinate + d -= dy; + nox += sx; + ntx -= sx; + diro |= dirox; + dirt |= dirtx; + } + else if (e2 < dx) + { + // calculate next point Y coordinate + d += dx; + noy += sy; + nty -= sy; + diro |= diroy; + dirt |= dirty; + } + + { + // get block of the next cell + block = getBlock(nox, noy); + + // get index of particular layer, based on movement conditions + if ((nsweo & diro) == 0) + { + index = block.getIndexAboveOriginal(nox, noy, goz - GeoStructure.CELL_IGNORE_HEIGHT); + } + else + { + index = block.getIndexBelowOriginal(nox, noy, goz + GeoStructure.CELL_IGNORE_HEIGHT); + } + + // layer does not exist, return + if (index == -1) + { + return false; + } + + // get layer and next line of sight Z coordinate + goz = block.getHeightOriginal(index); + losoz += dz; + + // perform line of sight check, return when fails + if ((goz - losoz) > Config.MAX_OBSTACLE_HEIGHT) + { + return false; + } + + // get layer nswe + nsweo = block.getNsweOriginal(index); + } + { + // get block of the next cell + block = getBlock(ntx, nty); + + // get index of particular layer, based on movement conditions + if ((nswet & dirt) == 0) + { + index = block.getIndexAboveOriginal(ntx, nty, gtz - GeoStructure.CELL_IGNORE_HEIGHT); + } + else + { + index = block.getIndexBelowOriginal(ntx, nty, gtz + GeoStructure.CELL_IGNORE_HEIGHT); + } + + // layer does not exist, return + if (index == -1) + { + return false; + } + + // get layer and next line of sight Z coordinate + gtz = block.getHeightOriginal(index); + lostz -= dz; + + // perform line of sight check, return when fails + if ((gtz - lostz) > Config.MAX_OBSTACLE_HEIGHT) + { + return false; + } + + // get layer nswe + nswet = block.getNsweOriginal(index); + } + + // update coords + gox = nox; + goy = noy; + gtx = ntx; + gty = nty; + } + + // when iteration is completed, compare final Z coordinates + return Math.abs(goz - gtz) < (GeoStructure.CELL_HEIGHT * 4); + } + + /** + * Check movement from coordinates to coordinates. + * @param ox : origin X coordinate + * @param oy : origin Y coordinate + * @param oz : origin Z coordinate + * @param tx : target X coordinate + * @param ty : target Y coordinate + * @param tz : target Z coordinate + * @param instance + * @return {code boolean} : True if target coordinates are reachable from origin coordinates + */ + public final boolean canMoveToTarget(int ox, int oy, int oz, int tx, int ty, int tz, Instance instance) + { + if (DoorData.getInstance().checkIfDoorsBetween(ox, oy, oz, tx, ty, tz, instance, false)) + { + return false; + } + + if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(ox, oy, oz), new Location(tx, ty, tz), instance)) + { + return false; + } + + // get origin and check existing geo coordinates + final int gox = getGeoX(ox); + final int goy = getGeoY(oy); + if (!hasGeoPos(gox, goy)) + { + return true; + } + + final short goz = getHeightNearest(gox, goy, oz); + + // get target and check existing geo coordinates + final int gtx = getGeoX(tx); + final int gty = getGeoY(ty); + if (!hasGeoPos(gtx, gty)) + { + return true; + } + + final short gtz = getHeightNearest(gtx, gty, tz); + + // target coordinates reached + if ((gox == gtx) && (goy == gty) && (goz == gtz)) + { + return true; + } + + // perform geodata check + GeoLocation loc = checkMove(gox, goy, goz, gtx, gty, gtz, instance); + return (loc.getGeoX() == gtx) && (loc.getGeoY() == gty); + } + + /** + * Check movement from origin to target. Returns last available point in the checked path. + * @param ox : origin X coordinate + * @param oy : origin Y coordinate + * @param oz : origin Z coordinate + * @param tx : target X coordinate + * @param ty : target Y coordinate + * @param tz : target Z coordinate + * @param instance + * @return {@link Location} : Last point where object can walk (just before wall) + */ + public final Location canMoveToTargetLoc(int ox, int oy, int oz, int tx, int ty, int tz, Instance instance) + { + if (DoorData.getInstance().checkIfDoorsBetween(ox, oy, oz, tx, ty, tz, instance, false)) + { + return new Location(ox, oy, getHeight(ox, oy, oz)); + } + + if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(ox, oy, oz), new Location(tx, ty, tz), instance)) + { + return new Location(ox, oy, getHeight(ox, oy, oz)); + } + + // get origin and check existing geo coordinates + final int gox = getGeoX(ox); + final int goy = getGeoY(oy); + if (!hasGeoPos(gox, goy)) + { + return new Location(tx, ty, tz); + } + + final short goz = getHeightNearest(gox, goy, oz); + + // get target and check existing geo coordinates + final int gtx = getGeoX(tx); + final int gty = getGeoY(ty); + if (!hasGeoPos(gtx, gty)) + { + return new Location(tx, ty, tz); + } + + final short gtz = getHeightNearest(gtx, gty, tz); + + // target coordinates reached + if ((gox == gtx) && (goy == gty) && (goz == gtz)) + { + return new Location(tx, ty, tz); + } + + // perform geodata check + return checkMove(gox, goy, goz, gtx, gty, gtz, instance); + } + + /** + * With this method you can check if a position is visible or can be reached by beeline movement.
+ * Target X and Y reachable and Z is on same floor: + *
    + *
  • Location of the target with corrected Z value from geodata.
  • + *
+ * Target X and Y reachable but Z is on another floor: + *
    + *
  • Location of the origin with corrected Z value from geodata.
  • + *
+ * Target X and Y not reachable: + *
    + *
  • Last accessible location in destination to target.
  • + *
+ * @param gox : origin X geodata coordinate + * @param goy : origin Y geodata coordinate + * @param goz : origin Z geodata coordinate + * @param gtx : target X geodata coordinate + * @param gty : target Y geodata coordinate + * @param gtz : target Z geodata coordinate + * @param instance + * @return {@link GeoLocation} : The last allowed point of movement. + */ + protected final GeoLocation checkMove(int gox, int goy, int goz, int gtx, int gty, int gtz, Instance instance) + { + if (DoorData.getInstance().checkIfDoorsBetween(gox, goy, goz, gtx, gty, gtz, instance, false)) + { + return new GeoLocation(gox, goy, goz); + } + + if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(gox, goy, goz), new Location(gtx, gty, gtz), instance)) + { + return new GeoLocation(gox, goy, goz); + } + + // get X delta, signum and direction flag + final int dx = Math.abs(gtx - gox); + final int sx = gox < gtx ? 1 : -1; + final byte dirX = sx > 0 ? GeoStructure.CELL_FLAG_E : GeoStructure.CELL_FLAG_W; + + // get Y delta, signum and direction flag + final int dy = Math.abs(gty - goy); + final int sy = goy < gty ? 1 : -1; + final byte dirY = sy > 0 ? GeoStructure.CELL_FLAG_S : GeoStructure.CELL_FLAG_N; + + // get direction flag for diagonal movement + final byte dirXY = getDirXY(dirX, dirY); + + // delta, determines axis to move on (+..X axis, -..Y axis) + int d = dx - dy; + + // NSWE direction of movement + byte direction; + + // load pointer coordinates + int gpx = gox; + int gpy = goy; + int gpz = goz; + + // load next pointer + int nx = gpx; + int ny = gpy; + + // loop + do + { + direction = 0; + + // calculate next point coordinates + int e2 = 2 * d; + if ((e2 > -dy) && (e2 < dx)) + { + d -= dy; + d += dx; + nx += sx; + ny += sy; + direction |= dirXY; + } + else if (e2 > -dy) + { + d -= dy; + nx += sx; + direction |= dirX; + } + else if (e2 < dx) + { + d += dx; + ny += sy; + direction |= dirY; + } + + // obstacle found, return + if ((getNsweNearest(gpx, gpy, gpz) & direction) == 0) + { + return new GeoLocation(gpx, gpy, gpz); + } + + // update pointer coordinates + gpx = nx; + gpy = ny; + gpz = getHeightNearest(nx, ny, gpz); + + // target coordinates reached + if ((gpx == gtx) && (gpy == gty)) + { + if (gpz == gtz) + { + // path found, Z coordinates are okay, return target point + return new GeoLocation(gtx, gty, gtz); + } + + // path found, Z coordinates are not okay, return origin point + return new GeoLocation(gox, goy, goz); + } + } + while (true); + } + + /** + * Returns diagonal NSWE flag format of combined two NSWE flags. + * @param dirX : X direction NSWE flag + * @param dirY : Y direction NSWE flag + * @return byte : NSWE flag of combined direction + */ + private static final byte getDirXY(byte dirX, byte dirY) + { + // check axis directions + if (dirY == GeoStructure.CELL_FLAG_N) + { + if (dirX == GeoStructure.CELL_FLAG_W) + { + return GeoStructure.CELL_FLAG_NW; + } + + return GeoStructure.CELL_FLAG_NE; + } + + if (dirX == GeoStructure.CELL_FLAG_W) + { + return GeoStructure.CELL_FLAG_SW; + } + + return GeoStructure.CELL_FLAG_SE; + } + + /** + * Returns the list of location objects as a result of complete path calculation. + * @param ox : origin x + * @param oy : origin y + * @param oz : origin z + * @param tx : target x + * @param ty : target y + * @param tz : target z + * @param instance + * @param playable : moving object is playable? + * @return {@code List} : complete path from nodes + */ + public List findPath(int ox, int oy, int oz, int tx, int ty, int tz, Instance instance, boolean playable) + { + return null; + } + + private static class SingletonHolder + { + protected static final GeoEngine _instance = Config.PATHFINDING ? new GeoEnginePathfinding() : new GeoEngine(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/GeoEnginePathfinding.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/GeoEnginePathfinding.java new file mode 100644 index 0000000000..b9def83228 --- /dev/null +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/GeoEnginePathfinding.java @@ -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 . + */ +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 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 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 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 : list of node location + */ + private static final List constructPath(Node target) + { + // create empty list + LinkedList 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 _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(); + } + } +} \ No newline at end of file diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/ABlock.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/ABlock.java new file mode 100644 index 0000000000..7fca5a9f52 --- /dev/null +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/ABlock.java @@ -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 . + */ +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.
+ * 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.
+ * 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.
+ * 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.
+ * 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.
+ * 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.
+ * 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; +} \ No newline at end of file diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplex.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplex.java new file mode 100644 index 0000000000..de0a7b8524 --- /dev/null +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplex.java @@ -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 . + */ +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); + } +} \ No newline at end of file diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplexDynamic.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplexDynamic.java new file mode 100644 index 0000000000..9f49e41899 --- /dev/null +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/BlockComplexDynamic.java @@ -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 . + */ +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 _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; + } + } + } + } + } +} \ No newline at end of file diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/BlockFlat.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/BlockFlat.java new file mode 100644 index 0000000000..e1d82814eb --- /dev/null +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/BlockFlat.java @@ -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 . + */ +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)); + } +} \ No newline at end of file diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayer.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayer.java new file mode 100644 index 0000000000..56d4de75e1 --- /dev/null +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayer.java @@ -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 . + */ +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; + } + } +} \ No newline at end of file diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayerDynamic.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayerDynamic.java new file mode 100644 index 0000000000..2361135de5 --- /dev/null +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/BlockMultilayerDynamic.java @@ -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 . + */ +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 _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; + } + } + } + } + } +} \ No newline at end of file diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/BlockNull.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/BlockNull.java new file mode 100644 index 0000000000..225bdef947 --- /dev/null +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/BlockNull.java @@ -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 . + */ +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) + { + } +} \ No newline at end of file diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/GeoFormat.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/GeoFormat.java new file mode 100644 index 0000000000..57885fc734 --- /dev/null +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/GeoFormat.java @@ -0,0 +1,39 @@ +/* + * 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 . + */ +package com.l2jmobius.gameserver.geoengine.geodata; + +/** + * @author Hasha + */ +public enum GeoFormat +{ + L2J("%d_%d.l2j"), + L2OFF("%d_%d_conv.dat"), + L2D("%d_%d.l2d"); + + private final String _filename; + + private GeoFormat(String filename) + { + _filename = filename; + } + + public String getFilename() + { + return _filename; + } +} \ No newline at end of file diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/GeoLocation.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/GeoLocation.java new file mode 100644 index 0000000000..850fcdbfcd --- /dev/null +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/GeoLocation.java @@ -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 . + */ +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; + } +} \ No newline at end of file diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/GeoStructure.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/GeoStructure.java new file mode 100644 index 0000000000..e1925e6e57 --- /dev/null +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/GeoStructure.java @@ -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 . + */ +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; +} \ No newline at end of file diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/IBlockDynamic.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/IBlockDynamic.java new file mode 100644 index 0000000000..e241e73b1c --- /dev/null +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/IBlockDynamic.java @@ -0,0 +1,35 @@ +/* + * 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 . + */ +package com.l2jmobius.gameserver.geoengine.geodata; + +/** + * @author Hasha + */ +public interface IBlockDynamic +{ + /** + * 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); + + /** + * 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); +} \ No newline at end of file diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/IGeoObject.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/IGeoObject.java new file mode 100644 index 0000000000..2726378e3a --- /dev/null +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/geodata/IGeoObject.java @@ -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 . + */ +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(); +} diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/pathfinding/Node.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/pathfinding/Node.java new file mode 100644 index 0000000000..27430a65cd --- /dev/null +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/pathfinding/Node.java @@ -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 . + */ +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; + } +} \ No newline at end of file diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/pathfinding/NodeBuffer.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/pathfinding/NodeBuffer.java new file mode 100644 index 0000000000..300fe31190 --- /dev/null +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/geoengine/pathfinding/NodeBuffer.java @@ -0,0 +1,351 @@ +/* + * 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 . + */ +package com.l2jmobius.gameserver.geoengine.pathfinding; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.locks.ReentrantLock; + +import com.l2jmobius.Config; +import com.l2jmobius.gameserver.geoengine.geodata.GeoStructure; + +/** + * @author DS, Hasha; Credits to Diamond + */ +public class NodeBuffer +{ + private final ReentrantLock _lock = new ReentrantLock(); + private final int _size; + private final Node[][] _buffer; + + // center coordinates + private int _cx = 0; + private int _cy = 0; + + // target coordinates + private int _gtx = 0; + private int _gty = 0; + private short _gtz = 0; + + // pathfinding statistics + private long _timeStamp = 0; + private long _lastElapsedTime = 0; + + private Node _current = null; + + /** + * Constructor of NodeBuffer. + * @param size : one dimension size of buffer + */ + public NodeBuffer(int size) + { + // set size + _size = size; + + // initialize buffer + _buffer = new Node[size][size]; + for (int x = 0; x < size; x++) + { + for (int y = 0; y < size; y++) + { + _buffer[x][y] = new Node(); + } + } + } + + /** + * Find path consisting of Nodes. Starts at origin coordinates, ends in target coordinates. + * @param gox : origin point x + * @param goy : origin point y + * @param goz : origin point z + * @param gtx : target point x + * @param gty : target point y + * @param gtz : target point z + * @return Node : first node of path + */ + public final Node findPath(int gox, int goy, short goz, int gtx, int gty, short gtz) + { + // load timestamp + _timeStamp = System.currentTimeMillis(); + + // set coordinates (middle of the line (gox,goy) - (gtx,gty), will be in the center of the buffer) + _cx = gox + ((gtx - gox - _size) / 2); + _cy = goy + ((gty - goy - _size) / 2); + + _gtx = gtx; + _gty = gty; + _gtz = gtz; + + _current = getNode(gox, goy, goz); + _current.setCost(getCostH(gox, goy, goz)); + + int count = 0; + do + { + // reached target? + if ((_current.getLoc().getGeoX() == _gtx) && (_current.getLoc().getGeoY() == _gty) && (Math.abs(_current.getLoc().getZ() - _gtz) < 8)) + { + return _current; + } + + // expand current node + expand(); + + // move pointer + _current = _current.getChild(); + } + while ((_current != null) && (++count < Config.MAX_ITERATIONS)); + + return null; + } + + /** + * Creates list of Nodes to show debug path. + * @return List : nodes + */ + public final List debugPath() + { + List result = new ArrayList<>(); + + for (Node n = _current; n.getParent() != null; n = n.getParent()) + { + result.add(n); + n.setCost(-n.getCost()); + } + + for (Node[] nodes : _buffer) + { + for (Node node : nodes) + { + if ((node.getLoc() == null) || (node.getCost() <= 0)) + { + continue; + } + + result.add(node); + } + } + + return result; + } + + public final boolean isLocked() + { + return _lock.tryLock(); + } + + public final void free() + { + _current = null; + + for (Node[] nodes : _buffer) + { + for (Node node : nodes) + { + if (node.getLoc() != null) + { + node.free(); + } + } + } + + _lock.unlock(); + _lastElapsedTime = System.currentTimeMillis() - _timeStamp; + } + + public final long getElapsedTime() + { + return _lastElapsedTime; + } + + /** + * Check _current Node and add its neighbors to the buffer. + */ + private final void expand() + { + // can't move anywhere, don't expand + byte nswe = _current.getLoc().getNSWE(); + if (nswe == 0) + { + return; + } + + // get geo coords of the node to be expanded + final int x = _current.getLoc().getGeoX(); + final int y = _current.getLoc().getGeoY(); + final short z = (short) _current.getLoc().getZ(); + + // can move north, expand + if ((nswe & GeoStructure.CELL_FLAG_N) != 0) + { + addNode(x, y - 1, z, Config.BASE_WEIGHT); + } + + // can move south, expand + if ((nswe & GeoStructure.CELL_FLAG_S) != 0) + { + addNode(x, y + 1, z, Config.BASE_WEIGHT); + } + + // can move west, expand + if ((nswe & GeoStructure.CELL_FLAG_W) != 0) + { + addNode(x - 1, y, z, Config.BASE_WEIGHT); + } + + // can move east, expand + if ((nswe & GeoStructure.CELL_FLAG_E) != 0) + { + addNode(x + 1, y, z, Config.BASE_WEIGHT); + } + + // can move north-west, expand + if ((nswe & GeoStructure.CELL_FLAG_NW) != 0) + { + addNode(x - 1, y - 1, z, Config.DIAGONAL_WEIGHT); + } + + // can move north-east, expand + if ((nswe & GeoStructure.CELL_FLAG_NE) != 0) + { + addNode(x + 1, y - 1, z, Config.DIAGONAL_WEIGHT); + } + + // can move south-west, expand + if ((nswe & GeoStructure.CELL_FLAG_SW) != 0) + { + addNode(x - 1, y + 1, z, Config.DIAGONAL_WEIGHT); + } + + // can move south-east, expand + if ((nswe & GeoStructure.CELL_FLAG_SE) != 0) + { + addNode(x + 1, y + 1, z, Config.DIAGONAL_WEIGHT); + } + } + + /** + * Returns node, if it exists in buffer. + * @param x : node X coord + * @param y : node Y coord + * @param z : node Z coord + * @return Node : node, if exits in buffer + */ + private final Node getNode(int x, int y, short z) + { + // check node X out of coordinates + final int ix = x - _cx; + if ((ix < 0) || (ix >= _size)) + { + return null; + } + + // check node Y out of coordinates + final int iy = y - _cy; + if ((iy < 0) || (iy >= _size)) + { + return null; + } + + // get node + Node result = _buffer[ix][iy]; + + // check and update + if (result.getLoc() == null) + { + result.setLoc(x, y, z); + } + + // return node + return result; + } + + /** + * Add node given by coordinates to the buffer. + * @param x : geo X coord + * @param y : geo Y coord + * @param z : geo Z coord + * @param weight : weight of movement to new node + */ + private final void addNode(int x, int y, short z, int weight) + { + // get node to be expanded + Node node = getNode(x, y, z); + if (node == null) + { + return; + } + + // Z distance between nearby cells is higher than cell size + if (node.getLoc().getZ() > (z + (2 * GeoStructure.CELL_HEIGHT))) + { + return; + } + + // node was already expanded, return + if (node.getCost() >= 0) + { + return; + } + + node.setParent(_current); + if (node.getLoc().getNSWE() != (byte) 0xFF) + { + node.setCost(getCostH(x, y, node.getLoc().getZ()) + (weight * Config.OBSTACLE_MULTIPLIER)); + } + else + { + node.setCost(getCostH(x, y, node.getLoc().getZ()) + weight); + } + + Node current = _current; + int count = 0; + while ((current.getChild() != null) && (count < (Config.MAX_ITERATIONS * 4))) + { + count++; + if (current.getChild().getCost() > node.getCost()) + { + node.setChild(current.getChild()); + break; + } + current = current.getChild(); + } + + if (count >= (Config.MAX_ITERATIONS * 4)) + { + System.err.println("Pathfinding: too long loop detected, cost:" + node.getCost()); + } + + current.setChild(node); + } + + /** + * @param x : node X coord + * @param y : node Y coord + * @param i : node Z coord + * @return double : node cost + */ + private final double getCostH(int x, int y, int i) + { + final int dX = x - _gtx; + final int dY = y - _gty; + final int dZ = (i - _gtz) / GeoStructure.CELL_HEIGHT; + + // return (Math.abs(dX) + Math.abs(dY) + Math.abs(dZ)) * Config.HEURISTIC_WEIGHT; // Manhattan distance + return Math.sqrt((dX * dX) + (dY * dY) + (dZ * dZ)) * Config.HEURISTIC_WEIGHT; // Direct distance + } +} \ No newline at end of file diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/instancemanager/WarpedSpaceManager.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/instancemanager/WarpedSpaceManager.java index 4f61421f83..cde24700ba 100644 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/instancemanager/WarpedSpaceManager.java +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/instancemanager/WarpedSpaceManager.java @@ -18,7 +18,6 @@ package com.l2jmobius.gameserver.instancemanager; import java.util.concurrent.ConcurrentHashMap; -import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNodeLoc; import com.l2jmobius.gameserver.model.Location; import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.holders.WarpedSpaceHolder; @@ -52,11 +51,6 @@ public class WarpedSpaceManager _warpedSpace.remove(creature); } - public boolean checkForWarpedSpace(AbstractNodeLoc start, AbstractNodeLoc end, Instance instance) - { - return checkForWarpedSpace(new Location(start.getX(), start.getY(), start.getZ()), new Location(end.getX(), end.getY(), end.getZ()), instance); - } - public boolean checkForWarpedSpace(Location origin, Location destination, Instance instance) { if (_warpedSpace != null) diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/Fishing.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/Fishing.java index e9cfd27a75..d0b69fa3e9 100644 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/Fishing.java +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/Fishing.java @@ -25,7 +25,7 @@ import com.l2jmobius.commons.util.Rnd; import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.data.xml.impl.FishingData; import com.l2jmobius.gameserver.enums.ShotType; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.instancemanager.ZoneManager; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.events.EventDispatcher; @@ -420,19 +420,19 @@ public class Fishing // always use water zone, fishing zone high z is high in the air... final int baitZ = waterZone.getWaterZ(); - // if (!GeoData.getInstance().canSeeTarget(player.getX(), player.getY(), player.getZ(), baitX, baitY, baitZ)) + // if (!GeoEngine.getInstance().canSeeTarget(player.getX(), player.getY(), player.getZ(), baitX, baitY, baitZ)) // // return Integer.MIN_VALUE; // } - if (GeoData.getInstance().hasGeo(baitX, baitY)) + if (GeoEngine.getInstance().hasGeo(baitX, baitY)) { - if (GeoData.getInstance().getHeight(baitX, baitY, baitZ) > baitZ) + if (GeoEngine.getInstance().getHeight(baitX, baitY, baitZ) > baitZ) { return Integer.MIN_VALUE; } - if (GeoData.getInstance().getHeight(baitX, baitY, player.getZ()) > baitZ) + if (GeoEngine.getInstance().getHeight(baitX, baitY, player.getZ()) > baitZ) { return Integer.MIN_VALUE; } diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/L2Spawn.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/L2Spawn.java index 3ddb0761ac..e9978f7863 100644 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/L2Spawn.java +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/L2Spawn.java @@ -26,7 +26,7 @@ import java.util.logging.Logger; import com.l2jmobius.commons.util.Rnd; import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.data.xml.impl.NpcData; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2NpcInstance; import com.l2jmobius.gameserver.model.actor.templates.L2NpcTemplate; @@ -544,7 +544,7 @@ public class L2Spawn implements IPositionable, IIdentifiable, INamable // don't correct z of flying npc's if (!npc.isFlying()) { - newlocz = GeoData.getInstance().getSpawnHeight(newlocx, newlocy, newlocz); + newlocz = GeoEngine.getInstance().getHeight(newlocx, newlocy, newlocz); } // Set is not random walk default value diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/Location.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/Location.java index dd88541a50..4b5e290517 100644 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/Location.java +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/Location.java @@ -26,9 +26,9 @@ import com.l2jmobius.gameserver.model.interfaces.IPositionable; */ public class Location implements IPositionable { - private int _x; - private int _y; - private int _z; + protected int _x; + protected int _y; + protected int _z; private int _heading; public Location(int x, int y, int z) diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/actor/L2Character.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/actor/L2Character.java index 8ab8348d64..8d4e253ccc 100644 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/actor/L2Character.java +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/actor/L2Character.java @@ -63,9 +63,7 @@ import com.l2jmobius.gameserver.enums.ShotType; import com.l2jmobius.gameserver.enums.StatusUpdateType; import com.l2jmobius.gameserver.enums.Team; import com.l2jmobius.gameserver.enums.UserInfoType; -import com.l2jmobius.gameserver.geodata.GeoData; -import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNodeLoc; -import com.l2jmobius.gameserver.geodata.pathfinding.PathFinding; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.idfactory.IdFactory; import com.l2jmobius.gameserver.instancemanager.MapRegionManager; import com.l2jmobius.gameserver.instancemanager.TimersManager; @@ -1053,7 +1051,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe stopEffectsOnAction(); // GeoData Los Check here (or dz > 1000) - if (!GeoData.getInstance().canSeeTarget(this, target)) + if (!GeoEngine.getInstance().canSeeTarget(this, target)) { sendPacket(SystemMessageId.CANNOT_SEE_TARGET); getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE); @@ -2851,7 +2849,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe public boolean disregardingGeodata; public int onGeodataPathIndex; - public List geoPath; + public List geoPath; public int geoPathAccurateTx; public int geoPathAccurateTy; public int geoPathGtx; @@ -3269,9 +3267,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe // Z coordinate will follow geodata or client values if ((Config.COORD_SYNCHRONIZE == 2) && !isFloating && !m.disregardingGeodata && ((GameTimeController.getInstance().getGameTicks() % 10) == 0 // once a second to reduce possible cpu load - ) && GeoData.getInstance().hasGeo(xPrev, yPrev)) + ) && GeoEngine.getInstance().hasGeo(xPrev, yPrev)) { - final int geoHeight = GeoData.getInstance().getSpawnHeight(xPrev, yPrev, zPrev); + final int geoHeight = GeoEngine.getInstance().getHeight(xPrev, yPrev, zPrev); dz = m._zDestination - geoHeight; // quite a big difference, compare to validatePosition packet if (isPlayer() && (Math.abs(getActingPlayer().getClientZ() - geoHeight) > 200) && (Math.abs(getActingPlayer().getClientZ() - geoHeight) < 1500)) @@ -3554,9 +3552,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe { // Notify the AI that the L2Character is arrived at destination getAI().notifyEvent(CtrlEvent.EVT_ARRIVED); - return; } + // Calculate movement angles needed sin = dy / distance; cos = dx / distance; @@ -3581,7 +3579,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe m.onGeodataPathIndex = -1; // Initialize not on geodata path m.disregardingGeodata = false; - if (!isFlying() && !isInsideZone(ZoneId.WATER)) + if (!isFlying() && !isInsideZone(ZoneId.WATER) && !isWalker()) { final boolean isInVehicle = isPlayer() && (getActingPlayer().getVehicle() != null); if (isInVehicle) @@ -3596,16 +3594,11 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe final int gtx = (originalX - L2World.MAP_MIN_X) >> 4; final int gty = (originalY - L2World.MAP_MIN_Y) >> 4; - final Location destiny = GeoData.getInstance().moveCheck(curX, curY, curZ, x, y, z, getInstanceWorld()); - - // location different if destination wasn't reached (or just z coord is different) - x = destiny.getX(); - y = destiny.getY(); - z = destiny.getZ(); - // Movement checks: - // when PATHFINDING > 0, for all characters except mobs returning home (could be changed later to teleport if pathfinding fails) - if (Config.PATHFINDING > 0) + // when geodata == 2, for all characters except mobs returning home (could be changed later to teleport if pathfinding fails) + // when geodata == 1, for l2playableinstance + // assuming intention_follow only when following owner + if ((Config.PATHFINDING && !(isAttackable() && ((L2Attackable) this).isReturningToSpawnPoint())) || (isPlayer() && !(isInVehicle && (distance > 1500))) || (isSummon() && !(getAI().getIntention() == CtrlIntention.AI_INTENTION_FOLLOW))) { if (isOnGeodataPath()) { @@ -3634,7 +3627,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe } else if (isSummon()) { - return; // preventation when summon get out of world coords, player will not loose him, unsummon handled from pcinstance + return; // prevention when summon get out of world coords, player will not loose him, unsummon handled from pcinstance } else { @@ -3643,6 +3636,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe return; } // location different if destination wasn't reached (or just z coord is different) + Location destiny = GeoEngine.getInstance().canMoveToTargetLoc(curX, curY, curZ, x, y, z, getInstanceWorld()); x = destiny.getX(); y = destiny.getY(); z = destiny.getZ(); @@ -3651,85 +3645,86 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe dz = z - curZ; distance = verticalMovementOnly ? Math.pow(dz, 2) : Math.hypot(dx, dy); } - // Pathfinding checks. Only when geodata setting is 2, the LoS check gives shorter result - // than the original movement was and the LoS gives a shorter distance than 2000 + // Pathfinding checks. Only when geodata setting is 2, the LoS check gives shorter result than the original movement was and the LoS gives a shorter distance than 2000 // This way of detecting need for pathfinding could be changed. - if ((Config.PATHFINDING > 0) && ((originalDistance - distance) > 30) && !isControlBlocked() && !isInVehicle) + if (Config.PATHFINDING && ((originalDistance - distance) > 30) && (distance < 2000) && !isControlBlocked() && !isInVehicle) { - m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayable()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + // Path calculation -- overrides previous movement check + if (isPlayable() || isMinion() || isInCombat()) { - // * Even though there's no path found (remember geonodes aren't perfect), - // the mob is attacking and right now we set it so that the mob will go - // after target anyway, is dz is small enough. - // * With cellpathfinding this approach could be changed but would require taking - // off the geonodes and some more checks. - // * Summons will follow their masters no matter what. - // * Currently minions also must move freely since L2AttackableAI commands - // them to move along with their leader - if (isPlayer() || (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) || (isSummon() && !((L2Summon) this).getFollowStatus())) + m.geoPath = GeoEngine.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayable()); + if ((m.geoPath == null) || (m.geoPath.size() < 2)) { - getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); - return; + // No path found + // Even though there's no path found (remember geonodes aren't perfect), the mob is attacking and right now we set it so that the mob will go after target anyway, is dz is small enough. + // With cellpathfinding this approach could be changed but would require taking off the geonodes and some more checks. + // Summons will follow their masters no matter what. + // Currently minions also must move freely since L2AttackableAI commands them to move along with their leader + if (isPlayer() || (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) || (isSummon() && !((L2Summon) this).getFollowStatus())) + { + getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); + return; + } + + m.disregardingGeodata = true; + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; } - - m.disregardingGeodata = true; - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; - } - else - { - m.onGeodataPathIndex = 0; // on first segment - m.geoPathGtx = gtx; - m.geoPathGty = gty; - m.geoPathAccurateTx = originalX; - m.geoPathAccurateTy = originalY; - - x = m.geoPath.get(m.onGeodataPathIndex).getX(); - y = m.geoPath.get(m.onGeodataPathIndex).getY(); - z = m.geoPath.get(m.onGeodataPathIndex).getZ(); - - // check for doors in the route - if (DoorData.getInstance().checkIfDoorsBetween(curX, curY, curZ, x, y, z, getInstanceWorld())) + else { - m.geoPath = null; - getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); - return; - } - if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(curX, curY, curZ), new Location(x, y, z), getInstanceWorld())) - { - m.geoPath = null; - getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); - return; - } - for (int i = 0; i < (m.geoPath.size() - 1); i++) - { - if (DoorData.getInstance().checkIfDoorsBetween(m.geoPath.get(i), m.geoPath.get(i + 1), getInstanceWorld())) + m.onGeodataPathIndex = 0; // on first segment + m.geoPathGtx = gtx; + m.geoPathGty = gty; + m.geoPathAccurateTx = originalX; + m.geoPathAccurateTy = originalY; + + x = m.geoPath.get(m.onGeodataPathIndex).getX(); + y = m.geoPath.get(m.onGeodataPathIndex).getY(); + z = m.geoPath.get(m.onGeodataPathIndex).getZ(); + + // check for doors in the route + if (DoorData.getInstance().checkIfDoorsBetween(curX, curY, curZ, x, y, z, getInstanceWorld())) { m.geoPath = null; getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); return; } - if (WarpedSpaceManager.getInstance().checkForWarpedSpace(m.geoPath.get(i), m.geoPath.get(i + 1), getInstanceWorld())) + if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(curX, curY, curZ), new Location(x, y, z), getInstanceWorld())) { m.geoPath = null; getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); return; } + for (int i = 0; i < (m.geoPath.size() - 1); i++) + { + if (DoorData.getInstance().checkIfDoorsBetween(m.geoPath.get(i), m.geoPath.get(i + 1), getInstanceWorld())) + { + m.geoPath = null; + getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); + return; + } + if (WarpedSpaceManager.getInstance().checkForWarpedSpace(m.geoPath.get(i), m.geoPath.get(i + 1), getInstanceWorld())) + { + m.geoPath = null; + getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); + return; + } + } + + dx = x - curX; + dy = y - curY; + dz = z - curZ; + distance = verticalMovementOnly ? Math.pow(dz, 2) : Math.hypot(dx, dy); + sin = dy / distance; + cos = dx / distance; } - - dx = x - curX; - dy = y - curY; - dz = z - curZ; - distance = verticalMovementOnly ? Math.pow(dz, 2) : Math.hypot(dx, dy); - sin = dy / distance; - cos = dx / distance; } } + // If no distance to go through, the movement is canceled - if ((distance < 1) && ((Config.PATHFINDING > 0) || isPlayable())) + if ((distance < 1) && (Config.PATHFINDING || isPlayable() || isControlBlocked())) { if (isSummon()) { @@ -3751,7 +3746,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe final int ticksToMove = 1 + (int) ((GameTimeController.TICKS_PER_SECOND * distance) / speed); m._xDestination = x; m._yDestination = y; - m._zDestination = z; // this is what was requested from client + m._zDestination = z; // Calculate and set the heading of the L2Character m._heading = 0; // initial value for coordinate sync @@ -4240,7 +4235,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe return; } // GeoData Los Check or dz > 1000 - if (!GeoData.getInstance().canSeeTarget(player, this)) + if (!GeoEngine.getInstance().canSeeTarget(player, this)) { player.sendPacket(SystemMessageId.CANNOT_SEE_TARGET); player.sendPacket(ActionFailed.STATIC_PACKET); diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/actor/L2Tower.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/actor/L2Tower.java index ac1d703e27..8390083019 100644 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/actor/L2Tower.java +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/actor/L2Tower.java @@ -17,7 +17,7 @@ package com.l2jmobius.gameserver.model.actor; import com.l2jmobius.gameserver.ai.CtrlIntention; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.actor.templates.L2NpcTemplate; import com.l2jmobius.gameserver.network.serverpackets.ActionFailed; @@ -63,7 +63,7 @@ public abstract class L2Tower extends L2Npc } else if (interact) { - if (isAutoAttackable(player) && (Math.abs(player.getZ() - getZ()) < 100) && GeoData.getInstance().canSeeTarget(player, this)) + if (isAutoAttackable(player) && (Math.abs(player.getZ() - getZ()) < 100) && GeoEngine.getInstance().canSeeTarget(player, this)) { // Notify the L2PcInstance AI with AI_INTENTION_INTERACT player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this); diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java index a402f427ff..48d9543f24 100644 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java @@ -97,7 +97,7 @@ import com.l2jmobius.gameserver.enums.StatusUpdateType; import com.l2jmobius.gameserver.enums.SubclassInfoType; import com.l2jmobius.gameserver.enums.Team; import com.l2jmobius.gameserver.enums.UserInfoType; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.handler.AdminCommandHandler; import com.l2jmobius.gameserver.handler.IAdminCommandHandler; import com.l2jmobius.gameserver.handler.IItemHandler; @@ -12475,7 +12475,7 @@ public final class L2PcInstance extends L2Playable } // If there is no geodata loaded for the place we are client Z correction might cause falling damage. - if (!GeoData.getInstance().hasGeo(getX(), getY())) + if (!GeoEngine.getInstance().hasGeo(getX(), getY())) { return false; } diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java index af1054767c..2337da2419 100644 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java @@ -49,7 +49,7 @@ import com.l2jmobius.gameserver.enums.ItemLocation; import com.l2jmobius.gameserver.enums.ItemSkillType; import com.l2jmobius.gameserver.enums.ShotType; import com.l2jmobius.gameserver.enums.UserInfoType; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.idfactory.IdFactory; import com.l2jmobius.gameserver.instancemanager.CastleManager; import com.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager; @@ -1512,7 +1512,7 @@ public final class L2ItemInstance extends L2Object if (_dropper != null) { final Instance instance = _dropper.getInstanceWorld(); - final Location dropDest = GeoData.getInstance().moveCheck(_dropper.getX(), _dropper.getY(), _dropper.getZ(), _x, _y, _z, instance); + final Location dropDest = GeoEngine.getInstance().canMoveToTargetLoc(_dropper.getX(), _dropper.getY(), _dropper.getZ(), _x, _y, _z, instance); _x = dropDest.getX(); _y = dropDest.getY(); _z = dropDest.getZ(); diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java index 9780892efe..9c70018363 100644 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java @@ -37,7 +37,7 @@ import com.l2jmobius.gameserver.datatables.ItemTable; import com.l2jmobius.gameserver.enums.ItemSkillType; import com.l2jmobius.gameserver.enums.NextActionType; import com.l2jmobius.gameserver.enums.StatusUpdateType; -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; @@ -1009,7 +1009,7 @@ public class SkillCaster implements Runnable } } - final Location destination = GeoData.getInstance().moveCheck(creature.getX(), creature.getY(), creature.getZ(), x, y, z, creature.getInstanceWorld()); + final Location destination = GeoEngine.getInstance().canMoveToTargetLoc(creature.getX(), creature.getY(), creature.getZ(), x, y, z, creature.getInstanceWorld()); creature.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); creature.broadcastPacket(new FlyToLocation(creature, destination, flyType, 0, 0, 333)); diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/skills/SkillChannelizer.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/skills/SkillChannelizer.java index 3875eb6830..cc1667a637 100644 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/skills/SkillChannelizer.java +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/skills/SkillChannelizer.java @@ -25,7 +25,7 @@ import java.util.logging.Logger; import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.data.xml.impl.SkillData; import com.l2jmobius.gameserver.enums.ShotType; -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.instance.L2PcInstance; @@ -185,7 +185,7 @@ public class SkillChannelizer implements Runnable { continue; } - else if (!GeoData.getInstance().canSeeTarget(_channelizer, character)) + else if (!GeoEngine.getInstance().canSeeTarget(_channelizer, character)) { continue; } diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/zone/form/ZoneCuboid.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/zone/form/ZoneCuboid.java index 58d967f84d..4433e97b28 100644 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/zone/form/ZoneCuboid.java +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/zone/form/ZoneCuboid.java @@ -19,7 +19,7 @@ package com.l2jmobius.gameserver.model.zone.form; import java.awt.Rectangle; import com.l2jmobius.commons.util.Rnd; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.model.Location; import com.l2jmobius.gameserver.model.itemcontainer.Inventory; import com.l2jmobius.gameserver.model.zone.L2ZoneForm; @@ -131,6 +131,6 @@ public class ZoneCuboid extends L2ZoneForm final int x = Rnd.get(_r.x, _r.x + _r.width); final int y = Rnd.get(_r.y, _r.y + _r.height); - return new Location(x, y, GeoData.getInstance().getHeight(x, y, _z1)); + return new Location(x, y, GeoEngine.getInstance().getHeight(x, y, _z1)); } } diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/zone/form/ZoneCylinder.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/zone/form/ZoneCylinder.java index 969dd7d029..afdfd3fade 100644 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/zone/form/ZoneCylinder.java +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/zone/form/ZoneCylinder.java @@ -17,7 +17,7 @@ package com.l2jmobius.gameserver.model.zone.form; import com.l2jmobius.commons.util.Rnd; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.model.Location; import com.l2jmobius.gameserver.model.itemcontainer.Inventory; import com.l2jmobius.gameserver.model.zone.L2ZoneForm; @@ -146,6 +146,6 @@ public class ZoneCylinder extends L2ZoneForm x = (int) ((_rad * r * Math.cos(q)) + _x); y = (int) ((_rad * r * Math.sin(q)) + _y); - return new Location(x, y, GeoData.getInstance().getHeight(x, y, _z1)); + return new Location(x, y, GeoEngine.getInstance().getHeight(x, y, _z1)); } } diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/zone/form/ZoneNPoly.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/zone/form/ZoneNPoly.java index 6da33d788e..2340c1b218 100644 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/zone/form/ZoneNPoly.java +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/zone/form/ZoneNPoly.java @@ -19,7 +19,7 @@ package com.l2jmobius.gameserver.model.zone.form; import java.awt.Polygon; import com.l2jmobius.commons.util.Rnd; -import com.l2jmobius.gameserver.geodata.GeoData; +import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.model.Location; import com.l2jmobius.gameserver.model.itemcontainer.Inventory; import com.l2jmobius.gameserver.model.zone.L2ZoneForm; @@ -138,7 +138,7 @@ public class ZoneNPoly extends L2ZoneForm y = Rnd.get(_minY, _maxY); } - return new Location(x, y, GeoData.getInstance().getHeight(x, y, _z1)); + return new Location(x, y, GeoEngine.getInstance().getHeight(x, y, _z1)); } public int[] getX() diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/util/GeoUtils.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/util/GeoUtils.java index 21540f2215..dba01759ef 100644 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/util/GeoUtils.java +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/util/GeoUtils.java @@ -18,8 +18,8 @@ package com.l2jmobius.gameserver.util; import java.awt.Color; -import com.l2jmobius.gameserver.geodata.GeoData; -import com.l2jmobius.gameserver.geodata.geodriver.Cell; +import com.l2jmobius.gameserver.geoengine.GeoEngine; +import com.l2jmobius.gameserver.geoengine.geodata.GeoStructure; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.network.serverpackets.ExServerPrimitive; @@ -30,21 +30,21 @@ public final class GeoUtils { public static void debug2DLine(L2PcInstance player, int x, int y, int tx, int ty, int z) { - final int gx = GeoData.getInstance().getGeoX(x); - final int gy = GeoData.getInstance().getGeoY(y); + final int gx = GeoEngine.getInstance().getGeoX(x); + final int gy = GeoEngine.getInstance().getGeoY(y); - final int tgx = GeoData.getInstance().getGeoX(tx); - final int tgy = GeoData.getInstance().getGeoY(ty); + final int tgx = GeoEngine.getInstance().getGeoX(tx); + final int tgy = GeoEngine.getInstance().getGeoY(ty); final ExServerPrimitive prim = new ExServerPrimitive("Debug2DLine", x, y, z); - prim.addLine(Color.BLUE, GeoData.getInstance().getWorldX(gx), GeoData.getInstance().getWorldY(gy), z, GeoData.getInstance().getWorldX(tgx), GeoData.getInstance().getWorldY(tgy), z); + prim.addLine(Color.BLUE, GeoEngine.getInstance().getWorldX(gx), GeoEngine.getInstance().getWorldY(gy), z, GeoEngine.getInstance().getWorldX(tgx), GeoEngine.getInstance().getWorldY(tgy), z); final LinePointIterator iter = new LinePointIterator(gx, gy, tgx, tgy); while (iter.next()) { - final int wx = GeoData.getInstance().getWorldX(iter.x()); - final int wy = GeoData.getInstance().getWorldY(iter.y()); + final int wx = GeoEngine.getInstance().getWorldX(iter.x()); + final int wy = GeoEngine.getInstance().getWorldY(iter.y()); prim.addPoint(Color.RED, wx, wy, z); } @@ -53,21 +53,21 @@ public final class GeoUtils public static void debug3DLine(L2PcInstance player, int x, int y, int z, int tx, int ty, int tz) { - final int gx = GeoData.getInstance().getGeoX(x); - final int gy = GeoData.getInstance().getGeoY(y); + final int gx = GeoEngine.getInstance().getGeoX(x); + final int gy = GeoEngine.getInstance().getGeoY(y); - final int tgx = GeoData.getInstance().getGeoX(tx); - final int tgy = GeoData.getInstance().getGeoY(ty); + final int tgx = GeoEngine.getInstance().getGeoX(tx); + final int tgy = GeoEngine.getInstance().getGeoY(ty); final ExServerPrimitive prim = new ExServerPrimitive("Debug3DLine", x, y, z); - prim.addLine(Color.BLUE, GeoData.getInstance().getWorldX(gx), GeoData.getInstance().getWorldY(gy), z, GeoData.getInstance().getWorldX(tgx), GeoData.getInstance().getWorldY(tgy), tz); + prim.addLine(Color.BLUE, GeoEngine.getInstance().getWorldX(gx), GeoEngine.getInstance().getWorldY(gy), z, GeoEngine.getInstance().getWorldX(tgx), GeoEngine.getInstance().getWorldY(tgy), tz); final LinePointIterator3D iter = new LinePointIterator3D(gx, gy, z, tgx, tgy, tz); iter.next(); int prevX = iter.x(); int prevY = iter.y(); - int wx = GeoData.getInstance().getWorldX(prevX); - int wy = GeoData.getInstance().getWorldY(prevY); + int wx = GeoEngine.getInstance().getWorldX(prevX); + int wy = GeoEngine.getInstance().getWorldY(prevY); int wz = iter.z(); prim.addPoint(Color.RED, wx, wy, wz); @@ -78,8 +78,8 @@ public final class GeoUtils if ((curX != prevX) || (curY != prevY)) { - wx = GeoData.getInstance().getWorldX(curX); - wy = GeoData.getInstance().getWorldY(curY); + wx = GeoEngine.getInstance().getWorldX(curX); + wy = GeoEngine.getInstance().getWorldY(curY); wz = iter.z(); prim.addPoint(Color.RED, wx, wy, wz); @@ -93,7 +93,7 @@ public final class GeoUtils private static Color getDirectionColor(int x, int y, int z, int nswe) { - if (GeoData.getInstance().checkNearestNswe(x, y, z, nswe)) + if ((GeoEngine.getInstance().getNsweNearest(x, y, z) & nswe) == nswe) { return Color.GREEN; } @@ -109,7 +109,7 @@ public final class GeoUtils int iPacket = 0; ExServerPrimitive exsp = null; - final GeoData gd = GeoData.getInstance(); + final GeoEngine gd = GeoEngine.getInstance(); final int playerGx = gd.getGeoX(player.getX()); final int playerGy = gd.getGeoY(player.getY()); for (int dx = -geoRadius; dx <= geoRadius; ++dx) @@ -137,30 +137,30 @@ public final class GeoUtils final int x = gd.getWorldX(gx); final int y = gd.getWorldY(gy); - final int z = gd.getNearestZ(gx, gy, player.getZ()); + final int z = gd.getHeightNearest(gx, gy, player.getZ()); // north arrow - Color col = getDirectionColor(gx, gy, z, Cell.NSWE_NORTH); + Color col = getDirectionColor(gx, gy, z, GeoStructure.CELL_FLAG_N); exsp.addLine(col, x - 1, y - 7, z, x + 1, y - 7, z); exsp.addLine(col, x - 2, y - 6, z, x + 2, y - 6, z); exsp.addLine(col, x - 3, y - 5, z, x + 3, y - 5, z); exsp.addLine(col, x - 4, y - 4, z, x + 4, y - 4, z); // east arrow - col = getDirectionColor(gx, gy, z, Cell.NSWE_EAST); + col = getDirectionColor(gx, gy, z, GeoStructure.CELL_FLAG_E); exsp.addLine(col, x + 7, y - 1, z, x + 7, y + 1, z); exsp.addLine(col, x + 6, y - 2, z, x + 6, y + 2, z); exsp.addLine(col, x + 5, y - 3, z, x + 5, y + 3, z); exsp.addLine(col, x + 4, y - 4, z, x + 4, y + 4, z); // south arrow - col = getDirectionColor(gx, gy, z, Cell.NSWE_SOUTH); + col = getDirectionColor(gx, gy, z, GeoStructure.CELL_FLAG_S); exsp.addLine(col, x - 1, y + 7, z, x + 1, y + 7, z); exsp.addLine(col, x - 2, y + 6, z, x + 2, y + 6, z); exsp.addLine(col, x - 3, y + 5, z, x + 3, y + 5, z); exsp.addLine(col, x - 4, y + 4, z, x + 4, y + 4, z); - col = getDirectionColor(gx, gy, z, Cell.NSWE_WEST); + col = getDirectionColor(gx, gy, z, GeoStructure.CELL_FLAG_W); exsp.addLine(col, x - 7, y - 1, z, x - 7, y + 1, z); exsp.addLine(col, x - 6, y - 2, z, x - 6, y + 2, z); exsp.addLine(col, x - 5, y - 3, z, x - 5, y + 3, z); @@ -188,30 +188,30 @@ public final class GeoUtils { if (y > lastY) { - return Cell.NSWE_SOUTH_EAST; // Direction.SOUTH_EAST; + return GeoStructure.CELL_FLAG_SE; // Direction.SOUTH_EAST; } else if (y < lastY) { - return Cell.NSWE_NORTH_EAST; // Direction.NORTH_EAST; + return GeoStructure.CELL_FLAG_NE; // Direction.NORTH_EAST; } else { - return Cell.NSWE_EAST; // Direction.EAST; + return GeoStructure.CELL_FLAG_E; // Direction.EAST; } } else if (x < lastX) // west { if (y > lastY) { - return Cell.NSWE_SOUTH_WEST; // Direction.SOUTH_WEST; + return GeoStructure.CELL_FLAG_SW; // Direction.SOUTH_WEST; } else if (y < lastY) { - return Cell.NSWE_NORTH_WEST; // Direction.NORTH_WEST; + return GeoStructure.CELL_FLAG_NW; // Direction.NORTH_WEST; } else { - return Cell.NSWE_WEST; // Direction.WEST; + return GeoStructure.CELL_FLAG_W; // Direction.WEST; } } else @@ -219,11 +219,11 @@ public final class GeoUtils { if (y > lastY) { - return Cell.NSWE_SOUTH; // Direction.SOUTH; + return GeoStructure.CELL_FLAG_S; // Direction.SOUTH; } else if (y < lastY) { - return Cell.NSWE_NORTH; // Direction.NORTH; + return GeoStructure.CELL_FLAG_N; // Direction.NORTH; } else { diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/tools/geodataconverter/GeoDataConverter.java b/L2J_Mobius_Underground/java/com/l2jmobius/tools/geodataconverter/GeoDataConverter.java new file mode 100644 index 0000000000..81621d8ee6 --- /dev/null +++ b/L2J_Mobius_Underground/java/com/l2jmobius/tools/geodataconverter/GeoDataConverter.java @@ -0,0 +1,375 @@ +/* + * 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 . + */ +package com.l2jmobius.tools.geodataconverter; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.RandomAccessFile; +import java.nio.ByteOrder; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.util.Scanner; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.PropertiesParser; +import com.l2jmobius.gameserver.geoengine.geodata.ABlock; +import com.l2jmobius.gameserver.geoengine.geodata.BlockComplex; +import com.l2jmobius.gameserver.geoengine.geodata.BlockFlat; +import com.l2jmobius.gameserver.geoengine.geodata.BlockMultilayer; +import com.l2jmobius.gameserver.geoengine.geodata.GeoFormat; +import com.l2jmobius.gameserver.geoengine.geodata.GeoStructure; +import com.l2jmobius.gameserver.model.L2World; + +/** + * @author Hasha + */ +public final class GeoDataConverter +{ + private static GeoFormat _format; + private static ABlock[][] _blocks; + + public static void main(String[] args) + { + // initialize config + loadGeoengineConfigs(); + + // get geodata format + String type = ""; + try (Scanner scn = new Scanner(System.in)) + { + while (!(type.equalsIgnoreCase("J") || type.equalsIgnoreCase("O") || type.equalsIgnoreCase("E"))) + { + System.out.println("GeoDataConverter: Select source geodata type:"); + System.out.println(" J: L2J (e.g. 23_22.l2j)"); + System.out.println(" O: L2OFF (e.g. 23_22_conv.dat)"); + System.out.println(" E: Exit"); + System.out.print("Choice: "); + type = scn.next(); + } + } + if (type.equalsIgnoreCase("E")) + { + System.exit(0); + } + + _format = type.equalsIgnoreCase("J") ? GeoFormat.L2J : GeoFormat.L2OFF; + + // start conversion + System.out.println("GeoDataConverter: Converting all " + _format.toString() + " files."); + + // initialize geodata container + _blocks = new ABlock[GeoStructure.REGION_BLOCKS_X][GeoStructure.REGION_BLOCKS_Y]; + + // initialize multilayer temporarily buffer + BlockMultilayer.initialize(); + + // load geo files + int converted = 0; + for (int rx = L2World.TILE_X_MIN; rx <= L2World.TILE_X_MAX; rx++) + { + for (int ry = L2World.TILE_Y_MIN; ry <= L2World.TILE_Y_MAX; ry++) + { + final String input = String.format(_format.getFilename(), rx, ry); + final String filepath = Config.GEODATA_PATH; + File f = new File(filepath + input); + if (f.exists() && !f.isDirectory()) + { + // load geodata + if (!loadGeoBlocks(input)) + { + System.out.println("GeoDataConverter: Unable to load " + input + " region file."); + continue; + } + + // recalculate nswe + if (!recalculateNswe()) + { + System.out.println("GeoDataConverter: Unable to convert " + input + " region file."); + continue; + } + + // save geodata + final String output = String.format(GeoFormat.L2D.getFilename(), rx, ry); + if (!saveGeoBlocks(output)) + { + System.out.println("GeoDataConverter: Unable to save " + output + " region file."); + continue; + } + + converted++; + System.out.println("GeoDataConverter: Created " + output + " region file."); + } + } + } + System.out.println("GeoDataConverter: Converted " + converted + " " + _format.toString() + " to L2D region file(s)."); + + // release multilayer block temporarily buffer + BlockMultilayer.release(); + } + + /** + * Loads geo blocks from buffer of the region file. + * @param filename : The name of the to load. + * @return boolean : True when successful. + */ + private static final boolean loadGeoBlocks(String filename) + { + // region file is load-able, try to load it + try (RandomAccessFile raf = new RandomAccessFile(Config.GEODATA_PATH + filename, "r"); + FileChannel fc = raf.getChannel()) + { + MappedByteBuffer buffer = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()).load(); + buffer.order(ByteOrder.LITTLE_ENDIAN); + + // load 18B header for L2off geodata (1st and 2nd byte...region X and Y) + if (_format == GeoFormat.L2OFF) + { + for (int i = 0; i < 18; i++) + { + buffer.get(); + } + } + + // loop over region blocks + for (int ix = 0; ix < GeoStructure.REGION_BLOCKS_X; ix++) + { + for (int iy = 0; iy < GeoStructure.REGION_BLOCKS_Y; iy++) + { + if (_format == GeoFormat.L2J) + { + // get block type + final byte type = buffer.get(); + + // load block according to block type + switch (type) + { + case GeoStructure.TYPE_FLAT_L2J_L2OFF: + _blocks[ix][iy] = new BlockFlat(buffer, _format); + break; + + case GeoStructure.TYPE_COMPLEX_L2J: + _blocks[ix][iy] = new BlockComplex(buffer, _format); + break; + + case GeoStructure.TYPE_MULTILAYER_L2J: + _blocks[ix][iy] = new BlockMultilayer(buffer, _format); + break; + + default: + throw new IllegalArgumentException("Unknown block type: " + type); + } + } + else + { + // get block type + final short type = buffer.getShort(); + + // load block according to block type + switch (type) + { + case GeoStructure.TYPE_FLAT_L2J_L2OFF: + _blocks[ix][iy] = new BlockFlat(buffer, _format); + break; + + case GeoStructure.TYPE_COMPLEX_L2OFF: + _blocks[ix][iy] = new BlockComplex(buffer, _format); + break; + + default: + _blocks[ix][iy] = new BlockMultilayer(buffer, _format); + break; + } + } + } + } + + if (buffer.remaining() > 0) + { + System.out.println("GeoDataConverter: Region file " + filename + " can be corrupted, remaining " + buffer.remaining() + " bytes to read."); + return false; + } + + return true; + } + catch (Exception e) + { + System.out.println("GeoDataConverter: Error while loading " + filename + " region file."); + return false; + } + } + + /** + * Recalculate diagonal flags for the region file. + * @return boolean : True when successful. + */ + private static final boolean recalculateNswe() + { + try + { + for (int x = 0; x < GeoStructure.REGION_CELLS_X; x++) + { + for (int y = 0; y < GeoStructure.REGION_CELLS_Y; y++) + { + // get block + ABlock block = _blocks[x / GeoStructure.BLOCK_CELLS_X][y / GeoStructure.BLOCK_CELLS_Y]; + + // skip flat blocks + if (block instanceof BlockFlat) + { + continue; + } + + // for complex and multilayer blocks go though all layers + short height = Short.MAX_VALUE; + int index; + while ((index = block.getIndexBelow(x, y, height)) != -1) + { + // get height and nswe + height = block.getHeight(index); + byte nswe = block.getNswe(index); + + // update nswe with diagonal flags + nswe = updateNsweBelow(x, y, height, nswe); + + // set nswe of the cell + block.setNswe(index, nswe); + } + } + } + + return true; + } + catch (Exception e) + { + return false; + } + } + + /** + * Updates the NSWE flag with diagonal flags. + * @param x : Geodata X coordinate. + * @param y : Geodata Y coordinate. + * @param z : Geodata Z coordinate. + * @param nswe : NSWE flag to be updated. + * @return byte : Updated NSWE flag. + */ + private static final byte updateNsweBelow(int x, int y, short z, byte nswe) + { + // calculate virtual layer height + short height = (short) (z + GeoStructure.CELL_IGNORE_HEIGHT); + + // get NSWE of neighbor cells below virtual layer (NPC/PC can fall down of clif, but can not climb it -> NSWE of cell below) + byte nsweN = getNsweBelow(x, y - 1, height); + byte nsweS = getNsweBelow(x, y + 1, height); + byte nsweW = getNsweBelow(x - 1, y, height); + byte nsweE = getNsweBelow(x + 1, y, height); + + // north-west + if ((((nswe & GeoStructure.CELL_FLAG_N) != 0) && ((nsweN & GeoStructure.CELL_FLAG_W) != 0)) || (((nswe & GeoStructure.CELL_FLAG_W) != 0) && ((nsweW & GeoStructure.CELL_FLAG_N) != 0))) + { + nswe |= GeoStructure.CELL_FLAG_NW; + } + + // north-east + if ((((nswe & GeoStructure.CELL_FLAG_N) != 0) && ((nsweN & GeoStructure.CELL_FLAG_E) != 0)) || (((nswe & GeoStructure.CELL_FLAG_E) != 0) && ((nsweE & GeoStructure.CELL_FLAG_N) != 0))) + { + nswe |= GeoStructure.CELL_FLAG_NE; + } + + // south-west + if ((((nswe & GeoStructure.CELL_FLAG_S) != 0) && ((nsweS & GeoStructure.CELL_FLAG_W) != 0)) || (((nswe & GeoStructure.CELL_FLAG_W) != 0) && ((nsweW & GeoStructure.CELL_FLAG_S) != 0))) + { + nswe |= GeoStructure.CELL_FLAG_SW; + } + + // south-east + if ((((nswe & GeoStructure.CELL_FLAG_S) != 0) && ((nsweS & GeoStructure.CELL_FLAG_E) != 0)) || (((nswe & GeoStructure.CELL_FLAG_E) != 0) && ((nsweE & GeoStructure.CELL_FLAG_S) != 0))) + { + nswe |= GeoStructure.CELL_FLAG_SE; + } + + return nswe; + } + + private static final byte getNsweBelow(int geoX, int geoY, short worldZ) + { + // out of geo coordinates + if ((geoX < 0) || (geoX >= GeoStructure.REGION_CELLS_X)) + { + return 0; + } + + // out of geo coordinates + if ((geoY < 0) || (geoY >= GeoStructure.REGION_CELLS_Y)) + { + return 0; + } + + // get block + final ABlock block = _blocks[geoX / GeoStructure.BLOCK_CELLS_X][geoY / GeoStructure.BLOCK_CELLS_Y]; + + // get index, when valid, return nswe + final int index = block.getIndexBelow(geoX, geoY, worldZ); + return index == -1 ? 0 : block.getNswe(index); + } + + /** + * Save region file to file. + * @param filename : The name of file to save. + * @return boolean : True when successful. + */ + private static final boolean saveGeoBlocks(String filename) + { + try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(Config.GEODATA_PATH + filename), GeoStructure.REGION_BLOCKS * GeoStructure.BLOCK_CELLS * 3)) + { + // loop over region blocks and save each block + for (int ix = 0; ix < GeoStructure.REGION_BLOCKS_X; ix++) + { + for (int iy = 0; iy < GeoStructure.REGION_BLOCKS_Y; iy++) + { + _blocks[ix][iy].saveBlock(bos); + } + } + + // flush data to file + bos.flush(); + + return true; + } + catch (Exception e) + { + return false; + } + } + + private static final void loadGeoengineConfigs() + { + final PropertiesParser geoData = new PropertiesParser(Config.GEODATA_FILE); + Config.GEODATA_PATH = geoData.getString("GeoDataPath", "./data/geodata/"); + Config.COORD_SYNCHRONIZE = geoData.getInt("CoordSynchronize", -1); + Config.PART_OF_CHARACTER_HEIGHT = geoData.getInt("PartOfCharacterHeight", 75); + Config.MAX_OBSTACLE_HEIGHT = geoData.getInt("MaxObstacleHeight", 32); + Config.PATHFINDING = geoData.getBoolean("PathFinding", true); + Config.PATHFIND_BUFFERS = geoData.getString("PathFindBuffers", "100x6;128x6;192x6;256x4;320x4;384x4;500x2"); + Config.BASE_WEIGHT = geoData.getInt("BaseWeight", 10); + Config.DIAGONAL_WEIGHT = geoData.getInt("DiagonalWeight", 14); + Config.OBSTACLE_MULTIPLIER = geoData.getInt("ObstacleMultiplier", 10); + Config.HEURISTIC_WEIGHT = geoData.getInt("HeuristicWeight", 20); + Config.MAX_ITERATIONS = geoData.getInt("MaxIterations", 3500); + } +} \ No newline at end of file diff --git a/L2J_Mobius_Underground/readme.txt b/L2J_Mobius_Underground/readme.txt index 56687c120a..d1719fb4a5 100644 --- a/L2J_Mobius_Underground/readme.txt +++ b/L2J_Mobius_Underground/readme.txt @@ -3,7 +3,7 @@ L2J-Mobius Underground Client: https://mega.nz/#!h1FXyByZ!XmyZBtk4qSOlKb435rx7X372_NreN1PTH8l7A4lNCoo Use mega downloader to download https://megadownloader.en.softonic.com/ -Geodata: http://www.mediafire.com/download/byirhqxws5jr56a/Mobius_Underground_Geodata.zip +Geodata: http://www.mediafire.com/file/9c99ys5iq6364np/mobius_geodata_underground_l2d.zip What is done -Underground packet compatibility