Skip to content

Commit

Permalink
massive rework to map change system
Browse files Browse the repository at this point in the history
  • Loading branch information
Hexalgo committed Nov 30, 2024
1 parent c815b27 commit 043c57c
Show file tree
Hide file tree
Showing 20 changed files with 375 additions and 119 deletions.
11 changes: 11 additions & 0 deletions pydofus2/com/ankamagames/dofus/datacenter/world/Hint.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,20 @@ class Hint(IDataCenter, IPostInit):

_subArea: SubArea = None

_zaapMapIds: list[float] = None

def __init__(self):
super().__init__()

@classmethod
def getZaapMapIds(cls):
if cls._zaapMapIds is None:
cls._zaapMapIds = []
for hint in Hint.getHints():
if hint.gfx == DataEnum.ZAAP_GFX:
cls._zaapMapIds.append(hint.mapId)
return cls._zaapMapIds

@classmethod
def getHintById(cls, id: int) -> "Hint":
return GameData().getObject(cls.MODULE, id)
Expand Down
12 changes: 12 additions & 0 deletions pydofus2/com/ankamagames/dofus/internalDatacenter/DataEnum.py
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,8 @@ class DataEnum:

FISH_TYPE_ID = 41

CEREAL_TYPE_ID = 34

RESOURCE_BAGS_TYPE_ID = 100

ROSE_OF_SANDS_TYPE_ID = 50
Expand All @@ -505,3 +507,13 @@ class DataEnum:
TREASURE_MAX_FRAG_BOX_TYPE_ID = 176

ZAAP_TYPEID = 16

ZAAP_GFX = 410

ANKARNAM_AREA_ID = 45

ASTRUB_AREA_ID = 95

NEW_VALONIA_AREA_ID = 93

CELESTIAL_SUBAREA_ID = 446
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ def onRefuseDrop(self) -> None:
def useItem(self, iw: ItemWrapper, quantity=0, useOnCell=False, use_multiple=True):
if useOnCell and iw.targetable:
if Kernel().battleFrame:
return
return False
else:
if quantity > 1 and use_multiple:
oumsg = ObjectUseMultipleMessage()
Expand All @@ -247,3 +247,4 @@ def useItem(self, iw: ItemWrapper, quantity=0, useOnCell=False, use_multiple=Tru
Logger().error("Can't use item because player is moving")
else:
ConnectionsHandler().send(oumsg)
return True
Original file line number Diff line number Diff line change
Expand Up @@ -108,18 +108,12 @@
from pydofus2.com.ankamagames.dofus.network.types.game.context.roleplay.GameRolePlayMerchantInformations import (
GameRolePlayMerchantInformations,
)
from pydofus2.com.ankamagames.dofus.network.types.game.context.roleplay.GameRolePlayMountInformations import (
GameRolePlayMountInformations,
)
from pydofus2.com.ankamagames.dofus.network.types.game.context.roleplay.GameRolePlayNpcInformations import (
GameRolePlayNpcInformations,
)
from pydofus2.com.ankamagames.dofus.network.types.game.context.roleplay.GameRolePlayNpcWithQuestInformations import (
GameRolePlayNpcWithQuestInformations,
)
from pydofus2.com.ankamagames.dofus.network.types.game.context.roleplay.GameRolePlayPortalInformations import (
GameRolePlayPortalInformations,
)
from pydofus2.com.ankamagames.dofus.network.types.game.context.roleplay.GameRolePlayPrismInformations import (
GameRolePlayPrismInformations,
)
Expand Down Expand Up @@ -592,13 +586,6 @@ def addOrUpdateActor(self, infos: GameContextActorInformations) -> AnimatedChara
self._npcList[infos.contextualId] = ac
elif isinstance(
infos,
(
GameRolePlayTaxCollectorInformations,
GameRolePlayPrismInformations,
GameRolePlayPortalInformations,
GameRolePlayMountInformations,
),
(GameRolePlayTaxCollectorInformations, GameRolePlayPrismInformations),
):
ac.allowMovementThrough = True
else:
Logger().error(f"Unknown actor type {type(infos)}")
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
)
from pydofus2.com.ankamagames.dofus.kernel.Kernel import Kernel
from pydofus2.com.ankamagames.dofus.kernel.net.ConnectionsHandler import ConnectionsHandler
from pydofus2.com.ankamagames.dofus.logic.common.managers.PlayerManager import PlayerManager
from pydofus2.com.ankamagames.dofus.logic.game.common.managers.PlayedCharacterManager import PlayedCharacterManager
from pydofus2.com.ankamagames.dofus.network.enums.DialogTypeEnum import DialogTypeEnum
from pydofus2.com.ankamagames.dofus.network.enums.TeleporterTypeEnum import TeleporterTypeEnum
Expand Down Expand Up @@ -34,14 +35,15 @@


class ZaapFrame(Frame):
DATASTORE_SAVED_ZAAP = DataStoreType(
"spawnMapId", True, DataStoreEnum.LOCATION_LOCAL, DataStoreEnum.BIND_CHARACTER
)

def __init__(self):
super().__init__()
self._zaapsList = []
self.spawnMapId = StoreDataManager().getData(self.DATASTORE_SAVED_ZAAP, "spawnMapId")
self.DATASTORE_SAVED_ZAAP = DataStoreType(
f"{PlayerManager().accountId}_spawnMapId", True, DataStoreEnum.LOCATION_LOCAL, DataStoreEnum.BIND_CHARACTER
)
self.spawnMapId = StoreDataManager().getData(
self.DATASTORE_SAVED_ZAAP, f"{PlayedCharacterManager().id}_spawnMapId"
)
if self.spawnMapId is None:
self.spawnMapId = 0
else:
Expand Down Expand Up @@ -97,7 +99,9 @@ def process(self, msg):
)
)
self.spawnMapId = msg.spawnMapId
StoreDataManager().setData(self.DATASTORE_SAVED_ZAAP, "spawnMapId", msg.spawnMapId)
StoreDataManager().setData(
self.DATASTORE_SAVED_ZAAP, f"{PlayedCharacterManager().id}_spawnMapId", msg.spawnMapId
)
KernelEventsManager().send(
KernelEvent.TeleportDestinationList,
self._zaapsList,
Expand Down Expand Up @@ -141,7 +145,9 @@ def process(self, msg):
for zaap in self._zaapsList:
zaap.spawn = zaap.mapId == msg.mapId
self.spawnMapId = msg.mapId
StoreDataManager().setData(self.DATASTORE_SAVED_ZAAP, "spawnMapId", msg.mapId)
StoreDataManager().setData(
self.DATASTORE_SAVED_ZAAP, f"{PlayedCharacterManager().id}_spawnMapId", msg.mapId
)
KernelEventsManager().send(
KernelEvent.TeleportDestinationList, self._zaapsList, TeleporterTypeEnum.TELEPORTER_ZAAP
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
from typing import List, Union

from pydofus2.com.ankamagames.dofus.datacenter.world.MapPosition import MapPosition
from pydofus2.com.ankamagames.dofus.datacenter.world.SubArea import SubArea
from pydofus2.com.ankamagames.dofus.misc.utils.GameDataQuery import GameDataQuery
from pydofus2.com.ankamagames.dofus.kernel.Kernel import Kernel
from pydofus2.com.ankamagames.dofus.modules.utils.pathFinding.world.Edge import Edge
from pydofus2.com.ankamagames.dofus.modules.utils.pathFinding.world.MapMemoryManager import MapMemoryManager
from pydofus2.com.ankamagames.dofus.modules.utils.pathFinding.world.Node import Node
from pydofus2.com.ankamagames.dofus.modules.utils.pathFinding.world.TransitionTypeEnum import TransitionTypeEnum
from pydofus2.com.ankamagames.dofus.modules.utils.pathFinding.world.Vertex import Vertex
from pydofus2.com.ankamagames.dofus.modules.utils.pathFinding.world.WorldGraph import WorldGraph
from pydofus2.com.ankamagames.jerakine.logger.Logger import Logger
Expand Down Expand Up @@ -61,14 +62,17 @@ def search(
return self.compute()

def initForbiddenSubareaList(self) -> None:
self._forbiddenSubareaIds = GameDataQuery.queryEquals(SubArea, "mountAutoTripAllowed", False)
# self._forbiddenSubareaIds = GameDataQuery.queryEquals(SubArea, "mountAutoTripAllowed", False)
self._forbiddenSubareaIds = []

def stopSearch(self) -> None:
if self.running != None:
self.callbackWithResult(None)

def compute(self, e=None) -> None:
while self.openList:
if Kernel().worker._terminating.is_set():
return
if self.iterations > self.MAX_ITERATION:
raise Exception("Too many iterations")
self.iterations += 1
Expand All @@ -88,8 +92,9 @@ def compute(self, e=None) -> None:
if self.DEBUG:
Logger().debug(f"Processing Outgoing edges from {current.vertex}")
for edge in edges:
if self.DEBUG:
Logger().debug(f"Checking Outgoing edge {edge}")
if Kernel().worker._terminating.is_set():
return

if (
edge not in self._forbiddenEdges
and self.hasValidTransition(edge)
Expand All @@ -100,16 +105,6 @@ def compute(self, e=None) -> None:
node = Node(self, edge.dst, current)
self.openDic[edge.dst] = node
heapq.heappush(self.openList, (node.totalCost, id(node), node))
else:
if self.DEBUG:
reasons = []
if edge in self._forbiddenEdges:
reasons.append("Edge is in forbidden edges list")
if not self.hasValidTransition(edge):
reasons.append("Edge has a non valid transition")
if not self.hasValidDestinationSubarea(edge):
reasons.append("Edge has a non valid destination subarea")
Logger().debug(f"Edge dismissed for reason {', '.join(reasons)}")
self.running = False
return None

Expand All @@ -130,6 +125,10 @@ def hasValidTransition(cls, edge: Edge) -> bool:

valid = False
for transition in edge.transitions:
if TransitionTypeEnum(transition.type) == TransitionTypeEnum.HAVEN_BAG_ZAAP:
allowed = MapMemoryManager().is_havenbag_allowed(edge.src.mapId)
if allowed is not None and not allowed:
continue
if transition.criterion:
if (
"&" not in transition.criterion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,19 @@ def transitions(self) -> list[Transition]:

def addTransition(
self,
direction: int,
type: int,
direction: int = -1,
skill: int = -1,
criterion: str = "",
transitionMapId: float = -1,
cell: int = -1,
ieElemId: int = -1,
npcTravelInfos=None,
itemGID: int = -1,
) -> None:
self.transitions.append(Transition(type, direction, skill, criterion, transitionMapId, cell, ieElemId))
self.transitions.append(
Transition(type, direction, skill, criterion, transitionMapId, cell, ieElemId, npcTravelInfos, itemGID)
)

def __str__(self):
return "Edge(src={}, dst={}, transitions={})".format(self.src, self.dst, self.transitions)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import os
from typing import Optional, Tuple

from tinydb import Query, TinyDB

from pydofus2.com.ankamagames.dofus.datacenter.houses.HavenbagTheme import HavenbagTheme
from pydofus2.com.ankamagames.dofus.modules.utils.pathFinding.world.Vertex import Vertex
from pydofus2.com.ankamagames.jerakine.logger.Logger import Logger
from pydofus2.com.ankamagames.jerakine.metaclass.ThreadSharedSingleton import ThreadSharedSingleton

__dir__ = os.path.dirname(os.path.abspath(__file__))
MAP_MEMORY_FILE = os.path.join(__dir__, "map_memory.json")

from threading import Lock


class MapMemoryManager(metaclass=ThreadSharedSingleton):
"""Manages persistent memory for map-related information using TinyDB."""

def __init__(self):
"""Initialize the memory manager with the database path."""
self._lock = Lock()
self._db = TinyDB(MAP_MEMORY_FILE)
self._zaap_table = self._db.table("zaap_vertices")
self._havenbag_table = self._db.table("allow_havenbag")
self._query = Query()

def is_havenbag_allowed(self, map_id: float) -> Optional[bool]:
"""
Check if haven bag teleportation is allowed from a map.
Thread-safe implementation.
"""
with self._lock:
result = self._havenbag_table.get(self._query.map_id == map_id)
return result.get("allowed") if result else None

def register_havenbag_allowance(self, map_id: float, allowed: bool) -> None:
"""
Register whether haven bag teleportation is allowed from a map.
Thread-safe implementation.
"""
with self._lock:
self._havenbag_table.upsert({"map_id": map_id, "allowed": allowed}, self._query.map_id == map_id)
Logger().debug(f"Registered haven bag allowance for map {map_id}: {allowed}")

def register_zaap_vertex(self, vertex: Vertex, is_zaap: bool = True) -> None:
"""
Register a vertex as a zaap location.
Thread-safe implementation.
"""
if not vertex or HavenbagTheme.isMapIdInHavenbag(vertex.mapId):
return

with self._lock:
key = self._get_vertex_key(vertex)
self._zaap_table.upsert(
{"key": key, "is_zaap": is_zaap, "map_id": vertex.mapId, "zone_id": vertex.zoneId},
self._query.key == key,
)
Logger().debug(f"Registered zaap vertex {key} with status {is_zaap}")

def _get_vertex_key(self, vertex: Vertex) -> str:
"""Generate a unique key for a vertex."""
return f"{vertex.mapId},{vertex.zoneId}"

def is_zaap_vertex(self, vertex: Vertex) -> str:
"""
Check if a vertex is a zaap location.
Thread-safe implementation.
"""
with self._lock:
key = self._get_vertex_key(vertex)
result = self._zaap_table.get(self._query.key == key)
if result is None:
return "unknown"
return "yes" if result["is_zaap"] else "no"

def get_zaap_vertex(self, map_id: float) -> Optional[Tuple[float, int]]:
"""
Get the zaap vertex information for a given map ID.
Thread-safe implementation.
"""
with self._lock:
results = self._zaap_table.search((self._query.map_id == map_id) & (self._query.is_zaap == True))
if not results:
return None
return (results[0]["map_id"], results[0]["zone_id"])

def clear_all(self) -> None:
"""
Clear all stored data.
Thread-safe implementation.
"""
with self._lock:
self._zaap_table.truncate()
self._havenbag_table.truncate()
Logger().debug("Cleared all map memory data")

def __del__(self):
"""Ensure the database is closed properly."""
with self._lock:
self._db.close()
Loading

0 comments on commit 043c57c

Please sign in to comment.