Skip to content

Driver

Driver is one of the core modules of the library.

The main purpose of the module is to encapsulate the low-level interactions with the game client's memory and provide an interface for accessing and manipulating game data.

Key responsibilities include:

  • Memory access and manipulation
  • Game entity management
  • Process interaction handling

Important implementation details

The GameDriver class automatically handles the following scenarios:

  • Game client recreation
  • Local player change
  • Logging out & Logging in

The driver detects any of these events and automatically reinitiates affected dependencies.

icecap.infrastructure.driver

The module provides low-level tooling for interacting with the game client.

Classes:

  • GameDriver

    Provides an interface to interact with the game's memory and objects.

  • ObjectManager

    Represents the Object Manager in the game client.

GameDriver

GameDriver(
    game_process_manager: GameProcessManager, memory_manager_getter: MemoryManagerGetter
)

Provides an interface to interact with the game's memory and objects.

It serves as the main entry point for low-level accessing game data and functionality.

Source code in icecap/infrastructure/driver/driver.py
def __init__(
    self, game_process_manager: GameProcessManager, memory_manager_getter: MemoryManagerGetter
):
    self.game_process_manager = game_process_manager
    self.memory_manager_getter = memory_manager_getter

    self._name_resolver: NameResolver | None = None
    self._memory_manager: MemoryManager | None = None
    self._object_manager: ObjectManager | None = None
    self._last_known_object_manager_address: int | None = None

game_process_manager instance-attribute

game_process_manager: GameProcessManager = game_process_manager

Game process manager for interacting with the game process.

memory_manager property

memory_manager: MemoryManager

A memory manager instance for accessing the game's memory.

The attribute may return different objects depending on the state of the driver.

memory_manager_getter instance-attribute

memory_manager_getter: MemoryManagerGetter = memory_manager_getter

Callable that returns a MemoryManager instance for the game process.

This is used to access the game's memory and objects. Can't use static memory_manager because game process may change.

name_resolver property

name_resolver: NameResolver

A name resolver instance for resolving names of game entities.

The attribute may return different objects depending on the state of the driver.

object_manager property

object_manager: ObjectManager

The object manager instance for accessing the game's objects.

The attribute may return different objects depending on the state of the driver.

get_client_connection_address

get_client_connection_address() -> int

This method reads the client connection address from memory using a static offset.

Source code in icecap/infrastructure/driver/driver.py
def get_client_connection_address(self) -> int:
    """This method reads the client connection address from memory using a static offset."""
    address = self.memory_manager.read_uint(CLIENT_CONNECTION_OFFSET)
    return address

get_local_player_guid

get_local_player_guid() -> int

Retrieve the GUID of the local player using a static offset.

Uses static offset which is less reliable than dynamic address, but it is faster and does not require reading the object manager.

This is useful for quick checks or when the object manager is not available. For example, this can be used to check if the player is in the game world.

Source code in icecap/infrastructure/driver/driver.py
def get_local_player_guid(self) -> int:
    """Retrieve the GUID of the local player using a static offset.

    Uses static offset which is less reliable than dynamic address,
    but it is faster and does not require reading the object manager.

    This is useful for quick checks or when the object manager is not available.
    For example, this can be used to check if the player is in the game world.
    """
    return self.memory_manager.read_ulonglong(LOCAL_PLAYER_GUID_STATIC_OFFSET)

is_game_running

is_game_running() -> bool

Check if the game is running.

Source code in icecap/infrastructure/driver/driver.py
def is_game_running(self) -> bool:
    """Check if the game is running."""

    return bool(self.game_process_manager.get_process_id())

is_player_in_game

is_player_in_game() -> bool

Check if the player is in the game world.

This method uses the local player GUID to determine if the player is in the game. The GUID is non-zero only when the player is in the game.

Source code in icecap/infrastructure/driver/driver.py
def is_player_in_game(self) -> bool:
    """Check if the player is in the game world.

    This method uses the local player GUID to determine if the player is in the game.
    The GUID is non-zero only when the player is in the game.
    """
    return self.get_local_player_guid() != 0

ObjectManager

ObjectManager(memory_manager: MemoryManager, address: int, max_objects: int = 1000)

Represents the Object Manager in the game client.

The Object Manager is responsible for keeping track of all game objects, units, and players in the game world. This class provides methods to access and interact with these entities through memory reading operations.

Source code in icecap/infrastructure/driver/object_manager.py
def __init__(
    self,
    memory_manager: MemoryManager,
    address: int,
    max_objects: int = 1000,
):
    self.memory_manager = memory_manager
    self.address = address
    self.max_objects = max_objects

get_entity_position

get_entity_position(entity: Entity) -> ObjectPosition

Retrieve the position of an entity in the game world.

This method reads the entity's position data from memory and returns it as an ObjectPosition object containing x, y, z coordinates and rotation.

Source code in icecap/infrastructure/driver/object_manager.py
def get_entity_position(self, entity: Entity) -> ObjectPosition:
    """Retrieve the position of an entity in the game world.

    This method reads the entity's position data from memory and returns it
    as an ObjectPosition object containing x, y, z coordinates and rotation.
    """
    position_offset = (
        GAME_OBJECT_X_POSITION_OFFSET
        if entity.entity_type == EntityType.GAME_OBJECT
        else UNIT_X_POSITION_OFFSET
    )

    object_position = self.memory_manager.read_ctype_dataclass(
        entity.object_address + position_offset, ObjectPosition
    )

    return object_position

get_game_object_fields

get_game_object_fields(entity: Entity) -> GameObjectFields

Retrieve the game object fields of a game object entity.

This method reads the game object's field data from memory and returns it as a GameObjectFields object that corresponds to the C struct definition.

Source code in icecap/infrastructure/driver/object_manager.py
def get_game_object_fields(self, entity: Entity) -> GameObjectFields:
    """Retrieve the game object fields of a game object entity.

    This method reads the game object's field data from memory and returns it as a
    GameObjectFields object that corresponds to the C struct definition.
    """
    fields_address = self.memory_manager.read_uint(entity.object_address + OBJECT_FIELDS_OFFSET)

    game_object_fields = self.memory_manager.read_ctype_dataclass(
        fields_address, GameObjectFields
    )

    return game_object_fields

get_local_player_guid

get_local_player_guid() -> int

Retrieve the GUID of the local player using a dynamic address.

This method uses a dynamic address that should be more reliable than static offsets. It reads the local player GUID directly from the object manager.

Source code in icecap/infrastructure/driver/object_manager.py
def get_local_player_guid(self) -> int:
    """Retrieve the GUID of the local player using a dynamic address.

    This method uses a dynamic address that should be more reliable than static offsets.
    It reads the local player GUID directly from the object manager.
    """
    return self.memory_manager.read_ulonglong(self.address + LOCAL_PLAYER_GUID_OFFSET)

get_map_id

get_map_id() -> int

Retrieve the map ID from the object manager.

It can be used to identify the current map and get extra information from the map database.

Source code in icecap/infrastructure/driver/object_manager.py
def get_map_id(self) -> int:
    """Retrieve the map ID from the object manager.

    It can be used to identify the current map and get extra information
    from the map database.
    """

    return self.memory_manager.read_uint(self.address + MAP_ID_OFFSET)

get_unit_fields

get_unit_fields(entity: Entity) -> UnitFields

Retrieve the unit fields of an entity.

This method reads the unit's field data from memory and returns it as a UnitFields object that corresponds to the C struct definition.

Source code in icecap/infrastructure/driver/object_manager.py
def get_unit_fields(self, entity: Entity) -> UnitFields:
    """Retrieve the unit fields of an entity.

    This method reads the unit's field data from memory and returns it as a
    UnitFields object that corresponds to the C struct definition.
    """
    unit_fields_address = self.memory_manager.read_uint(
        entity.object_address + OBJECT_FIELDS_OFFSET
    )

    unit_fields = self.memory_manager.read_ctype_dataclass(unit_fields_address, UnitFields)

    return unit_fields

yield_objects

yield_objects() -> Generator[Entity, None, None]

Yield all objects in the Object Manager.

This method iterates through the linked list of objects in the Object Manager and yields each one as an Entity object.

Source code in icecap/infrastructure/driver/object_manager.py
def yield_objects(self) -> Generator[Entity, None, None]:
    """Yield all objects in the Object Manager.

    This method iterates through the linked list of objects in the Object Manager
    and yields each one as an Entity object.
    """
    checked_objects = 0
    current_object_address = self.memory_manager.read_uint(self.address + FIRST_OBJECT_OFFSET)

    while checked_objects < self.max_objects:
        try:
            object_type = EntityType(
                self.memory_manager.read_uint(current_object_address + OBJECT_TYPE_OFFSET)
            )
        except Exception:
            break

        object_guid = self.memory_manager.read_ulonglong(
            current_object_address + OBJECT_GUID_OFFSET
        )

        yield Entity(
            guid=object_guid,
            object_address=current_object_address,
            entity_type=object_type,
        )

        checked_objects += 1
        current_object_address = self.memory_manager.read_uint(
            current_object_address + NEXT_OBJECT_OFFSET
        )