From d717c5c078f6168277b49772041cc4245c128cd5 Mon Sep 17 00:00:00 2001 From: denNorske Date: Sun, 14 Jul 2024 22:56:11 +0200 Subject: [PATCH] Updating and reformatting existing docstrings. Also adding new docstrings. Updated two methods in `Player` module with **breaking changes** # Breaking Changes: 1. Player.get_target_player: Returns a `Player` object if the player is targeting another player. Returns None otherwise. Before, this was returning an integer which represented the playerid. 2. Player.get_target_actor: Returns an `Actor` object if the player is targeting an actor. Returns None otherwise. Before, this was returning an integer. --- pysamp/__init__.py | 55 +++--- pysamp/actor.py | 111 ++++++++--- pysamp/commands.py | 89 +++++---- pysamp/dialog.py | 8 +- pysamp/event.py | 27 ++- pysamp/gangzone.py | 41 +++- pysamp/menu.py | 28 +-- pysamp/object.py | 53 ++--- pysamp/pickup.py | 15 +- pysamp/player.py | 403 +++++++++++++++++++++++++++++++++------ pysamp/playerobject.py | 18 +- pysamp/playertextdraw.py | 10 +- pysamp/textdraw.py | 33 ++-- pysamp/textlabel.py | 60 ++++-- pysamp/timer.py | 4 - pysamp/vehicle.py | 139 ++++++++++---- 16 files changed, 806 insertions(+), 288 deletions(-) delete mode 100644 pysamp/timer.py diff --git a/pysamp/__init__.py b/pysamp/__init__.py index 04e897b..0812985 100644 --- a/pysamp/__init__.py +++ b/pysamp/__init__.py @@ -1,10 +1,18 @@ """Snake case wrappers for PEP8 compatibility.""" -from typing import Tuple, Callable -import functools -from pysamp.event import registry +# Disable warnings for missing docstrings in modukle: +# pylint: disable=C0114 + +import functools +from typing import Callable, Tuple +from pysamp.event import registry from samp import ( + CAMERA_CUT, + INVALID_PLAYER_ID, + INVALID_VEHICLE_ID, + MAPICON_LOCAL, + SPECTATE_MODE_NORMAL, AddMenuItem, AddPlayerClass, AddPlayerClassEx, @@ -32,7 +40,6 @@ BlockIpAddress, CallNativeFunction, CallRemoteFunction, - RegisterCallback, CancelEdit, CancelSelectTextDraw, ChangeVehicleColor, @@ -196,7 +203,6 @@ GetWeaponName, GivePlayerMoney, GivePlayerWeapon, - gpci as _gpci, HideMenuForPlayer, InterpolateCameraLookAt, InterpolateCameraPos, @@ -222,6 +228,7 @@ IsValidVehicle, IsVehicleStreamedIn, Kick, + KillTimer, LimitGlobalChatRadius, LimitPlayerMarkerRadius, LinkVehicleToInterior, @@ -237,6 +244,7 @@ NetStats_MessagesRecvPerSecond, NetStats_MessagesSent, NetStats_PacketLossPercent, + OBJECT_MATERIAL_SIZE_256x128, PlayAudioStreamForPlayer, PlayCrimeReportForPlayer, PlayerPlaySound, @@ -262,6 +270,7 @@ PlayerTextDrawTextSize, PlayerTextDrawUseBox, PutPlayerInVehicle, + RegisterCallback, RemoveBuildingForPlayer, RemovePlayerAttachedObject, RemovePlayerFromVehicle, @@ -342,7 +351,6 @@ SetSVarString, SetTeamCount, SetTimer, - KillTimer, SetVehicleAngularVelocity, SetVehicleHealth, SetVehicleNumberPlate, @@ -399,13 +407,8 @@ UpdateVehicleDamageStatus, UsePlayerPedAnims, VectorSize, - CAMERA_CUT, - MAPICON_LOCAL, - SPECTATE_MODE_NORMAL, - OBJECT_MATERIAL_SIZE_256x128, - INVALID_PLAYER_ID, - INVALID_VEHICLE_ID ) +from samp import gpci as _gpci from .callbacks import _path_hook # noqa @@ -715,8 +718,7 @@ def remove_building_for_player( def get_player_last_shot_vectors( player_id: int, ) -> Tuple[float, float, float, float, float, float]: - """ - This function returns two coordinates in a tuple. + """This function returns two coordinates in a tuple. The first three values are the coordinate where the shot was shot from. The last three values are where the bullet hit (if it hit something). @@ -2364,7 +2366,7 @@ def get_vehicle_z_angle(vehicle_id: int) -> float: def get_vehicle_rotation_quat( - vehicle_id: int + vehicle_id: int, ) -> Tuple[float, float, float, float]: return GetVehicleRotationQuat(vehicle_id) @@ -2699,7 +2701,7 @@ def create_player_3d_text_label( draw_distance, attached_player, attached_vehicle, - test_line_of_sight + test_line_of_sight, ) @@ -2718,10 +2720,7 @@ def gpci(playerid: int) -> str: def set_timer( - function: Callable, - interval_ms: int, - repeating: bool = False, - *args: Tuple + function: Callable, interval_ms: int, repeating: bool = False, *args: Tuple ) -> int: return SetTimer(function, interval_ms, repeating, *args) @@ -2744,24 +2743,24 @@ def register_callback(name: str, arguments: str): on_gamemode_init = functools.partial( registry.register_callback, - 'OnGameModeInit', - group='pysamp.on_gamemode_init', + "OnGameModeInit", + group="pysamp.on_gamemode_init", ) on_gamemode_exit = functools.partial( registry.register_callback, - 'OnGameModeExit', - group='pysamp.on_gamemode_exit', + "OnGameModeExit", + group="pysamp.on_gamemode_exit", ) on_rcon_login_attempt = functools.partial( registry.register_callback, - 'OnRconLoginAttempt', - group='pysamp.on_rcon_login_attempt', + "OnRconLoginAttempt", + group="pysamp.on_rcon_login_attempt", ) on_incoming_connection = functools.partial( registry.register_callback, - 'OnIncomingConnection', - group='pysamp.on_incoming_connection', + "OnIncomingConnection", + group="pysamp.on_incoming_connection", ) diff --git a/pysamp/actor.py b/pysamp/actor.py index 7df122d..70c6350 100644 --- a/pysamp/actor.py +++ b/pysamp/actor.py @@ -1,3 +1,11 @@ +"""Actors module, to handle and create actors. + +These 'actors' are like NPCs, however they have limited functionality. +They do not take up server player slots. +""" + +from typing import Optional, Tuple + from pysamp import ( apply_actor_animation, clear_actor_animations, @@ -16,7 +24,6 @@ set_actor_pos, set_actor_virtual_world, ) -from typing import Optional, Tuple from pysamp.event import event @@ -30,17 +37,12 @@ class Actor: https://open.mp/docs/scripting/functions/CreateActor """ - def __init__(self, id: int) -> None: + def __init__(self, id: int) -> None: # noqa: D107 self.id: int = id @classmethod def create( - cls, - modelid: int, - x: float, - y: float, - z: float, - rotation: float + cls, modelid: int, x: float, y: float, z: float, rotation: float ) -> Optional["Actor"]: """Create a new actor. @@ -52,11 +54,10 @@ def create( :return: An :class:`Actor` object. Will return ``None`` if the actor limit is reached of 1000 actors. """ - return cls( - create_actor(modelid, x, y, z, rotation) - ) + return cls(create_actor(modelid, x, y, z, rotation)) def get_id(self) -> int: + """Get the actor ID.""" return self.id def destroy(self) -> bool: @@ -72,7 +73,11 @@ def get_virtual_world(self) -> int: return get_actor_virtual_world(self.id) def set_virtual_world(self, virtual_world: int) -> bool: - """Set the actor to a specific virtual world id.""" + """Set the actor to a specific virtual world id. + + :param int virtual_world: The virtual world ID (0-65535). + :return: This method does not return anything. + """ return set_actor_virtual_world(self.id, virtual_world) def apply_animation( @@ -86,7 +91,18 @@ def apply_animation( freeze: bool, time: int, ) -> bool: - """Set an animation on the actor.""" + """Set an animation on the actor. + + :param str animation_library: The name of the animation library. + :param str animation_name: The name of the animation. + :param float delta: The animation delta. + :param bool loop: Whether the animation should loop. + :param bool lock_x: Whether the animation should lock the X axis. + :param bool lock_y: Whether the animation should lock the Y axis. + :param bool freeze: Whether the animation should freeze. + :param int time: The animation time. + :return: This method does not return anything. + """ return apply_actor_animation( self.id, animation_library, @@ -100,51 +116,98 @@ def apply_animation( ) def clear_animations(self) -> bool: - """Clear the animations that are in use by the actor, if any.""" + """Clear the animations that are in use by the actor, if any. + + :return: This method does not return anything. + """ return clear_actor_animations(self.id) def get_position(self) -> Tuple[float, float, float]: - """Gets the current world coordinates of where the actor is located.""" + """Get the current world coordinates of where the actor is located. + + :return: A tuple of (x, y, z). + """ return get_actor_pos(self.id) def set_position(self, x: float, y: float, z: float) -> bool: - """Set a new position for the actor.""" + """Set a new position for the actor. + + For rotation, check out method :meth:`~set_facing_angle`. + """ + if not self.is_valid(): + return False return set_actor_pos(self.id, x, y, z) def get_facing_angle(self) -> float: - """Get the actor's facing angle.""" + """Get the actor's facing angle. + + :return: The actor's facing angle. + """ return get_actor_facing_angle(self.id) def set_facing_angle(self, angle: float) -> bool: - """Set the actor's facing angle.""" + """Set the actor's facing angle. + + For position, check out method :meth:`~set_position`. + """ + if not self.is_valid(): + return False return set_actor_facing_angle(self.id, angle) def get_health(self) -> float: - """Get how much health the actor has.""" + """Get how much health the actor has. + + :return: The actor's health, between `0.0` and `100.0`. + """ return get_actor_health(self.id) def set_health(self, health: float) -> bool: - """Set the health of the actor.""" + """Set the health of the actor. + + :param health: A float between `0.0` and `100.0`. + :return: This method does not return anything. + """ return set_actor_health(self.id, health) def is_invulnerable(self) -> bool: - """See if the actor is invulnerable to damage.""" + """See if the actor is invulnerable to damage. + + :return: ``True`` if the actor is invulnerable, ``False`` otherwise. + """ return is_actor_invulnerable(self.id) def set_invulnerable(self, invulnerable: bool = True) -> bool: - """Set the actor to be invlunerable to damage.""" + """Set the actor to be invlunerable to damage. + + :param bool invulnerable: Whether the actor should be invulnerable. + :return: This method does not return anything. + """ return set_actor_invulnerable(self.id, invulnerable) def is_valid(self) -> bool: - """Check if the actor is valid.""" + """Check if the actor is valid. + + :return: ``True`` if valid, otherwise ``False``. + """ return is_valid_actor(self.id) @event("OnActorStreamIn") def on_stream_in(cls, actorid: int, forplayerid: int): + """Event that is triggered when an actor is streamed in to a player. + + :param Actor actor: The actor that was streamed in. + :param Player forplayer: The player that streamed the actor in. + """ return (cls(actorid), Player(forplayerid)) @event("OnActorStreamOut") def on_stream_out(cls, actorid: int, forplayerid: int): + """Event that is triggered when an actor is streamed out of a player. + + :param Actor actor: The actor that was streamed out. + :param Player forplayer: The player that streamed the actor out. + """ return (cls(actorid), Player(forplayerid)) -from pysamp.player import Player # noqa \ No newline at end of file + +from pysamp.player import Player # noqa diff --git a/pysamp/commands.py b/pysamp/commands.py index 0ddd6e3..483e18b 100644 --- a/pysamp/commands.py +++ b/pysamp/commands.py @@ -1,3 +1,8 @@ +"""Handle player commands. + +This is a module that can be used to create and handle player commands. +""" + import functools import inspect from dataclasses import dataclass, field @@ -14,6 +19,7 @@ def __call__(self, playerid: int, *args: str) -> None: ... class Validator(Protocol): """Return True if playerid is allowed, False otherwise.""" + def __call__(self, playerid: int) -> bool: ... @@ -34,22 +40,29 @@ class Command: def __post_init__(self): parameters = list(inspect.signature(self.handler).parameters.values()) - self._min_params = len([ - parameter - for parameter in parameters - if parameter.default is inspect._empty - and parameter.kind != inspect.Parameter.VAR_POSITIONAL - ]) - self._max_params = len(parameters) if not any( - parameter.kind == inspect.Parameter.VAR_POSITIONAL - for parameter in parameters - ) else None + self._min_params = len( + [ + parameter + for parameter in parameters + if parameter.default is inspect._empty + and parameter.kind != inspect.Parameter.VAR_POSITIONAL + ] + ) + self._max_params = ( + len(parameters) + if not any( + parameter.kind == inspect.Parameter.VAR_POSITIONAL + for parameter in parameters + ) + else None + ) self._usage_message = BaseMessage( - text=f'USAGE: {list(self.triggers)[0]} ' + ' '.join( + text=f"USAGE: {list(self.triggers)[0]} " + + " ".join( parameter.name if parameter.default is inspect._empty and parameter.kind != inspect.Parameter.VAR_POSITIONAL - else f'[{parameter.name}]' + else f"[{parameter.name}]" for parameter in parameters[1:] ), color=0xFF0000FF, @@ -65,14 +78,12 @@ def handle(self, playerid: int, args_text: str) -> None: if not self.split_args: args = [args_text] else: - args = [arg for arg in args_text.split(' ') if arg] + args = [arg for arg in args_text.split(" ") if arg] # +1 because of playerid arg_count = len(args) + 1 max_params = ( - self._max_params - if self._max_params is not None - else arg_count + self._max_params if self._max_params is not None else arg_count ) if not (self._min_params <= arg_count <= max_params): @@ -94,10 +105,9 @@ def _register(self, command: Command) -> None: checks in addition to looking much better. """ self._commands.append(command) - self._commands_by_trigger.update({ - trigger: command - for trigger in command.triggers - }) + self._commands_by_trigger.update( + {trigger: command for trigger in command.triggers} + ) def handle(self, playerid: int, command_text: str) -> bool: """Attempt to handle command_text sent by playerid. @@ -105,7 +115,7 @@ def handle(self, playerid: int, command_text: str) -> bool: Returns True if a Command was found, False otherwise. Should be used in OnPlayerCommandText. """ - trigger, _, args_text = command_text.partition(' ') + trigger, _, args_text = command_text.partition(" ") command = self._commands_by_trigger.get(trigger) if not command: @@ -118,6 +128,7 @@ def handle(self, playerid: int, command_text: str) -> bool: @dataclass class BaseMessage: """Bare message class implementing Message protocol.""" + text: str color: int @@ -129,7 +140,7 @@ def _NO_FUNCTION(playerid: int, *args: str) -> None: ... DEFAULT_ERROR_MESSAGE = BaseMessage( - text='You are not allowed to use this command.', + text="You are not allowed to use this command.", color=0xFF0000FF, ) @@ -146,23 +157,23 @@ def cmd( ) -> Callable[[Any], Any]: """Decorate a command handler to register it with the given options. - function: The command handler to register. Useful when there is no need for + :param function: The command handler to register. Useful when there is no need for other arguments, one can use the bare decorator without calling it. - aliases: Alternative command names to trigger the handler with. If this is + :param aliases: Alternative command names to trigger the handler with. If this is empty and use_function_name is False, a ValueError is raised. - use_function_name: Whether to use the function name as a command name to + :param use_function_name: Whether to use the function name as a command name to trigger the handler with. If this is False and aliases is empty, a ValueError is raised. - split_args: Whether command arguments should be passed to the function as + :param split_args: Whether command arguments should be passed to the function as individual string arguments (split by whitespace) or as a single string argument (all text after the issued command). Prefer to use *args instead if possible, which does the same thing but collapses contiguous whitespace. - requires: Tuple of callables implementing the Validator protocol. If + :param requires: Tuple of callables implementing the Validator protocol. If specified, they will be called in order with a playerid as argument and should return False if the player is not allowed to use this command, in which case error_message will be issued. - error_message: An object implementing the Message protocol. It will be sent + :param error_message: An object implementing the Message protocol. It will be sent to the player in case they are not allowed to use this command. """ if function is _NO_FUNCTION: @@ -184,22 +195,24 @@ def cmd( triggers.update(aliases) if not triggers: - raise ValueError('Unable to register a command without triggers.') + raise ValueError("Unable to register a command without triggers.") - dispatcher._register(Command( - triggers={f'/{trigger}' for trigger in triggers}, - handler=function, - split_args=split_args, - requires=requires, - error_message=error_message, - )) + dispatcher._register( + Command( + triggers={f"/{trigger}" for trigger in triggers}, + handler=function, + split_args=split_args, + requires=requires, + error_message=error_message, + ) + ) return function dispatcher = CommandDispatcher() registry.register_callback( - 'OnPlayerCommandText', + "OnPlayerCommandText", dispatcher.handle, - 'pysamp.commands', + "pysamp.commands", ) diff --git a/pysamp/dialog.py b/pysamp/dialog.py index bc15c40..f66af88 100644 --- a/pysamp/dialog.py +++ b/pysamp/dialog.py @@ -1,3 +1,5 @@ +"""Handles player dialogs.""" + import string from typing import Callable, Dict, Optional @@ -9,7 +11,7 @@ class ColorCompatibleFormatter(string.Formatter): def get_value(self, key, args, kwargs): # Allow color escapes like {FF0000} or {808080} if key not in kwargs: - return '{%s}' % key + return "{%s}" % key return kwargs[key] @@ -144,9 +146,9 @@ def handle( registry.register_callback( - 'OnDialogResponse', + "OnDialogResponse", Dialog.handle, - 'pysamp.dialogs', + "pysamp.dialogs", ) from pysamp.player import Player # noqa diff --git a/pysamp/event.py b/pysamp/event.py index a13ee26..1f6a324 100644 --- a/pysamp/event.py +++ b/pysamp/event.py @@ -1,3 +1,24 @@ +"""Event registration helpers. + +A callback can be registered using the `@event` decorator. The decorator +will register the callback with the given name, and the name will be +used to dispatch events. + +The signature of the callback is `(cls, *args)`. + +The callback name should be unique. + +Example: +------- + from pysamp.event import event + from pysamp.player import Player + + @event("player_join") + def on_join(player): + print(f"{player} joined") + +""" + import functools import io import traceback @@ -17,11 +38,11 @@ def wrapper(*args): if handler.__name__ == callback_name: message = io.StringIO() traceback.print_stack(file=message, limit=2) - location = message.getvalue().rsplit('\n', 4)[0].lstrip() + location = message.getvalue().rsplit("\n", 4)[0].lstrip() warnings.warn( - f'Handler {handler} has the same name as callback ' + f"Handler {handler} has the same name as callback " f'"{callback_name}", this is probably not what you want.\n' - f'{location}', + f"{location}", stacklevel=2, ) diff --git a/pysamp/gangzone.py b/pysamp/gangzone.py index 1fd9af7..0afe51e 100644 --- a/pysamp/gangzone.py +++ b/pysamp/gangzone.py @@ -1,3 +1,5 @@ +"""Create and manage gangzones on the server.""" + from pysamp import ( gang_zone_create, gang_zone_destroy, @@ -33,7 +35,7 @@ class Gangzone: ``` """ - def __init__( + def __init__( # noqa: D107 self, id: int, min_x: float, min_y: float, max_x: float, max_y: float ) -> None: self.id = id @@ -63,23 +65,39 @@ def create( ) def get_id(self) -> int: - """Get the gangzone id.""" + """Get the gangzone id. + + :return: The gangzone id. + """ return self.id def destroy(self) -> bool: - """Destroy the gangzone.""" + """Destroy the gangzone. + + :return: ``True`` if the gangzone was destroyed, ``False`` otherwise. + """ return gang_zone_destroy(self.id) def show_for_player(self, player: "Player", color: int) -> bool: - """Show the gangzone for a player.""" + """Show the gangzone for a player. + + :param player: The player to show the gangzone for. + :param color: The color of the gangzone. + """ return gang_zone_show_for_player(player.id, self.id, color) def hide_for_player(self, player: "Player") -> bool: - """Hide the ganzone for a player.""" + """Hide the ganzone for a player. + + :param player: The player to hide the gangzone for. + """ return gang_zone_hide_for_player(player.id, self.id) def show_for_all(self, color: int) -> bool: - """Show the ganzone for all players, with the desired color.""" + """Show the ganzone for all players, with the desired color. + + :param color: The color of the gangzone. + """ return gang_zone_show_for_all(self.id, color) def hide_for_all(self) -> bool: @@ -89,16 +107,25 @@ def hide_for_all(self) -> bool: def flash_for_player(self, player: "Player", flash_color: int) -> bool: """Make the gangzone flash for the given player, with the desired color. + + :param player: The player to flash the gangzone for. + :param flash_color: The color of the flash. + :return: ``True`` if the gangzone was flashed, ``False`` otherwise. """ return gang_zone_flash_for_player(player.id, self.id, flash_color) def flash_for_all(self, flash_color: int) -> bool: - """Make the gangzone flash for all players.""" + """Make the gangzone flash for all players. + + :param flash_color: The color of the flash. + """ return gang_zone_flash_for_all(self.id, flash_color) def stop_flash_for_player(self, player: "Player") -> bool: """If a gangzone is flashing for a player, this can be used to stop it. + + :param player: The player to stop the flashing for. """ return gang_zone_stop_flash_for_player(player.id, self.id) diff --git a/pysamp/menu.py b/pysamp/menu.py index 5eeda39..e284232 100644 --- a/pysamp/menu.py +++ b/pysamp/menu.py @@ -1,15 +1,18 @@ +"""Create and manage menus using this class.""" + from typing import Optional + from pysamp import ( + add_menu_item, create_menu, destroy_menu, - add_menu_item, - set_menu_column_header, - show_menu_for_player, - hide_menu_for_player, - is_valid_menu, disable_menu, disable_menu_row, - get_player_menu + get_player_menu, + hide_menu_for_player, + is_valid_menu, + set_menu_column_header, + show_menu_for_player, ) from samp import INVALID_MENU @@ -20,10 +23,8 @@ class Menu: Create a new menu with :meth:`create`. Then add items to it with :meth:`add_item`, and finally show it to players using :meth:`show`. """ - def __init__( - self, - id: int - ) -> None: + + def __init__(self, id: int) -> None: self.id = id @classmethod @@ -34,7 +35,7 @@ def create( x: float, y: float, column_1_width: float, - column_2_width: float = 0.0 + column_2_width: float = 0.0, ) -> "Menu": """Create a new menu. @@ -54,9 +55,7 @@ def create( 128 menus in total. """ return cls( - create_menu( - title, columns, x, y, column_1_width, column_2_width - ) + create_menu(title, columns, x, y, column_1_width, column_2_width) ) def add_item(self, column: int, text: str) -> None: @@ -152,4 +151,5 @@ def show(self, player: "Player") -> None: show_menu_for_player(self.id, player.id) return + from pysamp.player import Player # noqa diff --git a/pysamp/object.py b/pysamp/object.py index 3353118..b0fb43d 100644 --- a/pysamp/object.py +++ b/pysamp/object.py @@ -1,26 +1,26 @@ +"""Object module, to handle and create objects.""" + +from typing import Tuple + from pysamp import ( create_object, + destroy_object, get_object_model, get_object_pos, - set_object_pos, - set_object_rot, get_object_rot, - set_object_no_camera_col, + is_object_moving, is_valid_object, - destroy_object, move_object, - stop_object, - is_object_moving, set_object_material, set_object_material_text, - set_objects_default_camera_col + set_object_no_camera_col, + set_object_pos, + set_object_rot, + set_objects_default_camera_col, + stop_object, ) from pysamp.event import event -from samp import ( - OBJECT_MATERIAL_SIZE_256x128 -) - -from typing import Tuple +from samp import OBJECT_MATERIAL_SIZE_256x128 class Object: @@ -58,15 +58,24 @@ def create( rotation_x: float, rotation_y: float, rotation_z: float, - draw_distance: float = 0.0 + draw_distance: float = 0.0, ) -> "Object": """Create a new object. :return: An instance of an :class:`Object`. """ - return cls(create_object( - model, x, y, z, rotation_x, rotation_y, rotation_z, draw_distance - )) + return cls( + create_object( + model, + x, + y, + z, + rotation_x, + rotation_y, + rotation_z, + draw_distance, + ) + ) def set_position(self, x: float, y: float, z: float) -> bool: """Set a new position for the object using world coordinates. @@ -80,10 +89,7 @@ def get_position(self) -> Tuple[float, float, float]: return get_object_pos(self.id) def set_rotation( - self, - rotation_x: float, - rotation_y: float, - rotation_z: float + self, rotation_x: float, rotation_y: float, rotation_z: float ) -> bool: """Set the new rotation the object should have.""" return set_object_rot(self.id, rotation_x, rotation_y, rotation_z) @@ -153,7 +159,7 @@ def set_material( model_id: int, txd_name: str, texture_name: str, - material_color: int = 0 + material_color: int = 0, ) -> bool: """Change the object materials. @@ -183,7 +189,7 @@ def set_material_text( bold: bool = True, font_color: int = 0xFFFFFFFF, back_color: int = 0x00000000, - text_alignment: int = 0 + text_alignment: int = 0, ) -> bool: """Change the material text of the object. @@ -221,7 +227,7 @@ def set_material_text( bold, font_color, back_color, - text_alignment + text_alignment, ) @staticmethod @@ -240,4 +246,5 @@ def set_default_camera_col(disable: bool) -> bool: @event("OnObjectMoved") def on_moved(cls, objectid: int): + """Event that is called whenever an object is moved.""" return (cls(objectid),) diff --git a/pysamp/pickup.py b/pysamp/pickup.py index 326dccd..63b7d5f 100644 --- a/pysamp/pickup.py +++ b/pysamp/pickup.py @@ -1,7 +1,9 @@ -from pysamp import ( - create_pickup, destroy_pickup, - # add_static_pickup -) +"""A pickup is a global item that can be picked up by a player. + +Pickups triggers :meth:`~pysamp.Player.on_pick_up_pickup` when picked up. +""" + +from pysamp import create_pickup, destroy_pickup # add_static_pickup class Pickup: @@ -14,7 +16,7 @@ class Pickup: created and have pre-made actions that make them work (such as health). """ - def __init__(self, id: int) -> None: + def __init__(self, id: int) -> None: # noqa: D107 self.id = id """The pickup ID (readonly int).""" @@ -51,8 +53,7 @@ def create( for example using an M4 model in the pickup will automatically\ give the player the weapon and some ammo. """ - return cls( - create_pickup(model, type, x, y, z, virtual_world)) + return cls(create_pickup(model, type, x, y, z, virtual_world)) def destroy(self) -> bool: """Destroy the pickup. diff --git a/pysamp/player.py b/pysamp/player.py index d21eb1d..6476cfe 100644 --- a/pysamp/player.py +++ b/pysamp/player.py @@ -1,23 +1,11 @@ +"""A module that wraps player related functions. + +This module contains all player related functions. +""" + import functools from typing import Optional, Tuple -from samp import ( - BULLET_HIT_TYPE_NONE, - BULLET_HIT_TYPE_OBJECT, - BULLET_HIT_TYPE_PLAYER, - BULLET_HIT_TYPE_PLAYER_OBJECT, - BULLET_HIT_TYPE_VEHICLE, - CAMERA_CUT, - INVALID_ACTOR_ID, - INVALID_OBJECT_ID, - INVALID_PLAYER_ID, - INVALID_VEHICLE_ID, - MAPICON_LOCAL, - SELECT_OBJECT_GLOBAL_OBJECT, - SELECT_OBJECT_PLAYER_OBJECT, - SPECTATE_MODE_NORMAL, -) - from pysamp import ( allow_player_teleport, apply_animation, @@ -163,6 +151,22 @@ toggle_player_controllable, toggle_player_spectating, ) +from samp import ( + BULLET_HIT_TYPE_NONE, + BULLET_HIT_TYPE_OBJECT, + BULLET_HIT_TYPE_PLAYER, + BULLET_HIT_TYPE_PLAYER_OBJECT, + BULLET_HIT_TYPE_VEHICLE, + CAMERA_CUT, + INVALID_ACTOR_ID, + INVALID_OBJECT_ID, + INVALID_PLAYER_ID, + INVALID_VEHICLE_ID, + MAPICON_LOCAL, + SELECT_OBJECT_GLOBAL_OBJECT, + SELECT_OBJECT_PLAYER_OBJECT, + SPECTATE_MODE_NORMAL, +) from .commands import _NO_FUNCTION, cmd from .event import event @@ -232,21 +236,28 @@ def spawn(self) -> bool: return spawn_player(self.id) def set_pos_find_z(self, x: float, y: float, z: float) -> bool: - """This sets the players position then adjusts the players + """Set the player's position then adjust the player's z-coordinate to the nearest solid ground under the position. - This function does not work if the new coordinates are far away - from where the player currently is. The Z height will then be 0, - which will likely put them underground. + This method is useful for setting a player's position but also + making sure they do not spawn in an inappropriate location, + such as in water or underground. However, this method does not + work if the new coordinates are far away from where the player + currently is. In such a case the z-coordinate will be set to 0, + which will likely put them underground or into a body of water. + + In order to get the most out of setting a player's position and + avoid this problem, look into using an external plugin such as + MapAndreas or ColAndreas. """ return set_player_pos_find_z(self.id, x, y, z) def get_pos(self) -> Tuple[float, float, float]: - """Get the position of the player.""" + """Get the position of the player as a tuple (x, y, z).""" return get_player_pos(self.id) def set_pos(self, x: float, y: float, z: float) -> bool: - """Set the player's position""" + """Set the player's position to a given coordinate.""" return set_player_pos(self.id, x, y, z) def get_facing_angle(self) -> float: @@ -266,7 +277,7 @@ def set_facing_angle(self, angle: float) -> bool: def is_in_range_of_point( self, range: float, x: float, y: float, z: float ) -> bool: - """Checks if the player is in range of a point. + """Check if the player is in range of a point. :param range: The radius of the circle around the point. :param x,y,z: The coordinate of the point. @@ -279,7 +290,7 @@ def distance_from_point(self, x: float, y: float, z: float) -> float: return get_player_distance_from_point(self.id, x, y, z) def is_streamed_in(self, player: "Player") -> bool: - """Checks if the player is streamed in on another player's client.""" + """Check if the player is streamed in on another player's client.""" return is_player_streamed_in(self.id, player.id) def get_interior(self) -> int: @@ -293,8 +304,9 @@ def get_interior(self) -> int: return get_player_interior(self.id) def set_interior(self, interior_id: int) -> bool: - """Set the interior the player to be in. Syncs for all players even - when the player is desynced + """Set the interior the player to be in. + + Syncs for all players even if the player is desynced. """ return set_player_interior(self.id, interior_id) @@ -303,6 +315,11 @@ def get_health(self) -> float: return get_player_health(self.id) def set_health(self, health: float) -> bool: + """Set the player's health. + + :param health: A float between `0.0` and `100.0`. + :return: This method does not return anything. + """ return set_player_health(self.id, health) def get_armour(self) -> float: @@ -313,6 +330,11 @@ def get_armour(self) -> float: return get_player_armour(self.id) def set_armour(self, armour: float) -> bool: + """Set the player's armour. + + :param armour: A float between `0.0` and `100.0`. + :return: This method does not return anything. + """ return set_player_armour(self.id, armour) def get_ammo(self) -> int: @@ -351,21 +373,37 @@ def get_weapon_state(self) -> int: # PS - this is a test docstring w/rst! - he player is reloading their weapon Example: + ------- .. code-block:: python if player.weapon_state = WEAPONSTATE_LAST_BULLET: player.send_client_message(-1, "You only have 1 bullet left!") + """ return get_player_weapon_state(self.id) - def get_target_player(self) -> int: - """Check who the player is aiming at. Returns the player""" - return get_player_target_player(self.id) + def get_target_player(self) -> "Player" | None: + """Check who the player is aiming at. + + :return: The player instance the player is aiming at. If the player + is not aiming at anyone, will return None. + """ + target_player_id = get_player_target_player(self.id) + if target_player_id == INVALID_PLAYER_ID: + return None + return Player(target_player_id) + + def get_target_actor(self) -> "Player" | None: + """Get which actor that the player is currently aiming at. - def get_target_actor(self) -> int: - """Get which actor that the player is currently aiming at.""" - return get_player_target_actor(self.id) + :return: The player instance the player is aiming at. If the player + is not aiming at anyone, will return None. + """ + target_actor_id = get_player_target_actor(self.id) + if target_actor_id == INVALID_PLAYER_ID: + return None + return Player(target_actor_id) def get_team(self) -> int: """Get the player's team ID. @@ -480,6 +518,7 @@ def set_skin(self, skinid: int) -> bool: around them. Breaks the sitting animation on bikes. Example: + ------- .. code-block:: python @@ -513,7 +552,7 @@ def reset_weapons(self) -> bool: return reset_player_weapons(self.id) def set_armed_weapon(self, weapon_id: int) -> bool: - """Sets which weapon the player is holding. + """Set which weapon the player should be armed with. The player needs to have this weapon for it to work. Calling this method will not give the player a new weapon. @@ -527,6 +566,7 @@ def get_weapon_data(self, slot: int) -> Tuple[int, int]: The tuple returned contains `weapon, ammo`. Example: + ------- .. code-block:: python @@ -559,7 +599,7 @@ def get_name(self) -> str: return get_player_name(self.id) def set_name(self, name: str) -> int: - """Set a new name for the player. + r"""Set a new name for the player. :param name: The name to set. Must be 2-24 characters long and only contain valid characters (0-9, a-z, A-Z, [], (), \\$ @ . _ and =). @@ -763,10 +803,10 @@ def set_weather(self, weather: int) -> bool: return set_player_weather(self.id, weather) def force_class_selection(self) -> bool: - """Forces a player to go back to class selection on next spawn. + """Force a player to go back to class selection on next spawn. .. note:: You can quickly get the player into class selection by - toggling spectating on and then off. Will not perform a state + toggling spectating on and then off. It will not trigger a state change to ``PLAYER_STATE_WASTED`` if the spectate toggle method is used. """ @@ -821,6 +861,7 @@ def get_velocity(self) -> Tuple[float, float, float]: direction. Example: + ------- .. code-block:: python @@ -828,6 +869,7 @@ def get_velocity(self) -> Tuple[float, float, float]: print(f"Current velocity: {x}, {y}, {z}") # prints: 'Current velocity: 0.0, 0.0, 0.0' # given that the player is not moving. + """ return get_player_velocity(self.id) @@ -931,11 +973,11 @@ def play_audio_stream( ) def stop_audio_stream(self) -> bool: - """Stops the player's audio stream.""" + """Stop the player's audio stream, if any.""" return stop_audio_stream_for_player(self.id) def set_shop_name(self, shop_name: str) -> bool: - """Loads or unloads an interior script for a player. + """Load or unload an interior script for a player. This can for example be the ammunation menu, that belongs to the ammunition interior. @@ -993,7 +1035,7 @@ def get_surfing_vehicle(self) -> Optional["Vehicle"]: surfed. """ veh_id = get_player_surfing_vehicle_id(self.id) - if (veh_id == INVALID_VEHICLE_ID): + if veh_id == INVALID_VEHICLE_ID: return None return Vehicle(veh_id) @@ -1004,14 +1046,14 @@ def get_surfing_object(self) -> Optional["Object"]: standing on, or ``None`` if there's no moving object found. """ obj_id = get_player_surfing_object_id(self.id) - if (obj_id == INVALID_OBJECT_ID): + if obj_id == INVALID_OBJECT_ID: return None return Object(obj_id) def remove_building( self, model_id: int, x: float, y: float, z: float, radius: float ) -> bool: - """Removes a standard San Andreas model for a single player within a + """Remove a standard San Andreas model for a single player within a specified range. .. list-table:: Parameters @@ -1190,6 +1232,7 @@ def set_attached_object( - Jaw Example: + ------- .. code-block:: python @@ -1209,6 +1252,7 @@ def set_attached_object( 1.0, 0xFF00FF00 ) + """ return set_player_attached_object( self.id, @@ -1284,7 +1328,7 @@ def edit_attached_object(self, index: int) -> bool: return edit_attached_object(self.id, index) def cancel_edit(self): - """Cancel object edition mode for a player""" + """Cancel object edition mode for a player.""" return cancel_edit(self.id) def get_pvar_int(self, var_name: str) -> int: @@ -1360,7 +1404,7 @@ def set_pvar_float(self, var_name: str, value: float) -> bool: return set_pvar_float(self.id, var_name, value) def delete_pvar(self, var_name: str) -> bool: - """Deletes a player variable. + """Delete a player variable. :param var_name: The variable name to delete. :returns: This method does not return anything. @@ -1390,7 +1434,7 @@ def get_pvars_upper_index(self) -> int: print(f"You have {pvar_count} player-variables set. \\ Upper index (highest ID):\\ {pvar_upper_index - 1}.") - """ + """ # noqa return get_pvars_upper_index(self.id) def get_pvar_name_at_index(self, index: int) -> str: @@ -1402,7 +1446,7 @@ def get_pvar_name_at_index(self, index: int) -> str: return get_pvar_name_at_index(self.id, index) def get_pvar_type(self, var_name: str) -> int: - """Gets the type (integer, float or string) of a player variable. + """Get the type (integer, float or string) of a player variable. :param var_name: The name of the variable you want to get the type of. :returns: An ID that represent either of the types. See table below. @@ -1472,7 +1516,7 @@ def put_in_vehicle(self, vehicle_id: int, seat_id: int) -> bool: return put_player_in_vehicle(self.id, vehicle_id, seat_id) def get_vehicle_id(self) -> int: - """This method gets the ID of the vehicle the player is currently in. + """Get the ID of the vehicle the player is currently in. :returns: Vehicle ID of the vehicle. @@ -1703,7 +1747,7 @@ def set_race_checkpoint( ) def disable_race_checkpoint(self) -> bool: - """Removes the active race checkpoint for the player. + """Remove the active race checkpoint for the player. :returns: This method does not return anything. """ @@ -1759,8 +1803,8 @@ def set_marker(self, showplayer: "Player", color: int) -> bool: return set_player_marker_for_player(self.id, showplayer.id, color) def show_name_tag(self, showplayer: "Player", show: bool) -> bool: - """This method allows you to toggle the drawing of player nametags, - healthbars and armor bars which display above their head. + """Show or toggle the player nametags, + healthbars and armor bars above their head. :param showplayer: Player whose name tag will be shown or hidden. :param show: ``False`` to hide, ``True`` to show. @@ -1811,7 +1855,7 @@ def set_map_icon( ) def remove_map_icon(self, icon_id: int) -> bool: - """This removes a map icon that was set with ``player.set_map_icon``. + """Remove a map icon that was set with ``player.set_map_icon``. :param icon_id: The icon slot to remove the icon from (0-99). :return: No return value. @@ -1875,7 +1919,7 @@ def set_camera_position(self, x: float, y: float, z: float) -> bool: return set_player_camera_pos(self.id, x, y, z) def get_camera_front_vector(self) -> Tuple[float, float, float]: - """This function will return the current direction of player's aiming + """Get the current direction of player's aiming in 3-D space, the coords are relative to the camera position, see :meth:`Player.get_camera_pos`. @@ -1885,7 +1929,7 @@ def get_camera_front_vector(self) -> Tuple[float, float, float]: return get_player_camera_front_vector(self.id) def get_camera_mode(self) -> int: - """Returns the current GTA camera mode for the requested player. + """Get the GTA camera mode for the requested player. :return: A number that represents the camera mode the player currently is in. @@ -1982,8 +2026,7 @@ def enable_camera_target(self, enable: bool) -> bool: return enable_player_camera_target(self.id, enable) def get_camera_target_object(self) -> Optional["Object"]: - """Allows you to retrieve the map object the player is looking - at. + """Retrieve the map object the player is looking at. :return: The :class:`~object.Object` the player is looking at. If ``None`` is returned, player isn't @@ -1999,8 +2042,7 @@ def get_camera_target_object(self) -> Optional["Object"]: return Object(object_id) def get_camera_target_vehicle(self) -> Optional["Vehicle"]: - """Allows you to retrieve the ID of the vehicle the player is looking - at. + """Retrieve the ID of the vehicle the player is looking at. :return: The :class:`~vehicle.Vehicle` the player is looking at. If ``None`` is returned, player isn't @@ -2059,7 +2101,7 @@ def get_camera_aspect_ratio(self) -> float: return get_player_camera_aspect_ratio(self.id) def get_camera_zoom(self) -> float: - """Retrieves the game camera zoom level for a given player. + """Get the game camera zoom level for a given player. :return: The zoom level as a float. Useful to check zoom level when using a sniper, etc. @@ -2080,7 +2122,6 @@ def interpolate_camera_position( time: int, cut: int = CAMERA_CUT, ) -> bool: - """Smoothly move the camera position from one coordinate to another, using a given time on the transition. @@ -2285,12 +2326,11 @@ def spectate_vehicle( return player_spectate_vehicle(self.id, target_vehicle.id, mode) def start_recording_data(self, recordtype: int, recordname: str) -> bool: - """Used to record NPC data.""" + """Start recording NPC data.""" return start_recording_player_data(self.id, recordtype, recordname) def stop_recording_data(self) -> bool: - """Stop recording NPC data, started with :meth:`start_recording_data`. - """ + """Stop recording NPC data, started with :meth:`start_recording_data`.""" return stop_recording_player_data(self.id) def create_explosion( @@ -2395,7 +2435,7 @@ def ban(self) -> bool: return ban(self.id) def ban_ex(self, reason: str) -> bool: - """This method does the exact same as :meth:`ban`, but adds a reason. + """Ban the player from the server with a given reason. :param str reason: The reason to write together with the ban. :return: No value is returned. @@ -2435,22 +2475,51 @@ def attach_camera_to_player_object( def on_enter_exit_mod_shop( cls, playerid: int, enterexit: int, interiorid: int ): + """Event that is called when a player enters or exits a mod shop. + + :param Player player: The player that entered or exited. + :param int enterexit: 1 if entering, 0 if exiting. + :param int interiorid: The ID of the interior. + """ return (cls(playerid), enterexit, interiorid) @event("OnPlayerConnect") def on_connect(cls, playerid: int): + """Event that is called when a player connects to the server. + + :param Player player: The player that connected. + """ return (cls(playerid),) @event("OnPlayerDisconnect") def on_disconnect(cls, playerid: int, reason: int): + """Event that is called when a player disconnects from the server. + + :param Player player: The player that disconnected. + :param int reason: The reason of the disconnect. + Reason is a number from 0 to 2. + """ return (cls(playerid), reason) @event("OnPlayerSpawn") def on_spawn(cls, playerid: int): + """Event that is called when a player spawns. + + :param Player player: The player that spawned. + """ return (cls(playerid),) @event("OnPlayerDeath") def on_death(cls, playerid: int, killerid: int, reason: int): + """Event that is called when a player dies. + + :param Player player: The player that died. + :param Player killer: The killer is the player who killed the player. + If the killer is not a player, it is set to INVALID_PLAYER_ID. + :param int reason: The reason is the weapon that caused the player to + die. See: https://www.open.mp/docs/scripting/resources/weaponids + for the available weapons. + """ return ( cls(playerid), killerid if killerid == INVALID_PLAYER_ID else cls(killerid), @@ -2459,14 +2528,34 @@ def on_death(cls, playerid: int, killerid: int, reason: int): @event("OnPlayerText") def on_text(cls, playerid: int, text: str): + """Event that is called when a player sends a message in the chat. + + :param Player player: The player that sent the message. + :param str text: The text that was sent in chat. + """ return (cls(playerid), text) @event("OnPlayerCommandText") def on_command_text(cls, playerid: int, command_text: str): + """Event that is called when a player sends a command text. + + For creating and using commands, it is recommended to take a look + at the `pysamp.commands` module, instead of using this event. + + :param Player player: The player that sent the command. + :param str command_text: The text that was sent in chat, including the + forward slash. + + """ return (cls(playerid), command_text) @event("OnPlayerRequestClass") def on_request_class(cls, playerid: int, classid: int): + """Event that is called when a player requests a class. + + :param Player player: The player. + :param int classid: The ID of the class. + """ return (cls(playerid), classid) @event("OnPlayerEnterVehicle") @@ -2476,46 +2565,104 @@ def on_enter_vehicle( vehicleid: int, is_passenger: bool, ): + """Event that is called when a player enters a vehicle by pressing + ENTER / F. + + :param Player player: The player that entered. + :param Vehicle vehicle: The vehicle that the player entered. + :param bool is_passenger: Whether the player is a passenger or not. + + """ return (cls(playerid), Vehicle(vehicleid), is_passenger) @event("OnPlayerExitVehicle") def on_exit_vehicle(cls, playerid: int, vehicleid: int): + """Event that is called when a player exits a vehicle by pressing + ENTER / F. + + :param Player player: The player that exited. + :param Vehicle vehicle: The vehicle that the player exited. + """ return (cls(playerid), Vehicle(vehicleid)) @event("OnPlayerStateChange") def on_state_change(cls, playerid, newstate: int, oldstate: int): + """Event that is called when a player changes state. For example + changing from spectator to onfoot, or dies. + + :param Player player: The player that changed state. + :param int newstate: The new state of the player. + :param int oldstate: The old state of the player. + + States can be found here: + https://www.open.mp/docs/scripting/resources/playerstates + """ return (cls(playerid), newstate, oldstate) @event("OnPlayerEnterCheckpoint") def on_enter_checkpoint(cls, playerid: int): + """Event that is called when a player enters a checkpoint. + + :param Player player: The player that entered the checkpoint. + """ return (cls(playerid),) @event("OnPlayerLeaveCheckpoint") def on_leave_checkpoint(cls, playerid: int): + """Event that is called when a player leaves a checkpoint. + + :param Player player: The player that left the checkpoint. + """ return (cls(playerid),) @event("OnPlayerEnterRaceCheckpoint") def on_enter_race_checkpoint(cls, playerid: int): + """Event that is called when a player enters a race checkpoint. + + :param Player player: The player that entered the checkpoint. + """ return (cls(playerid),) @event("OnPlayerLeaveRaceCheckpoint") def on_leave_race_checkpoint(cls, playerid: int): + """Event that is called when a player leaves a race checkpoint. + + :param Player player: The player that left the checkpoint. + """ return (cls(playerid),) @event("OnPlayerRequestSpawn") def on_request_spawn(cls, playerid: int): + """Event that is called when a player requests to spawn. + + :param Player player: The player that requested to spawn. + """ return (cls(playerid),) @event("OnPlayerPickUpPickup") def on_pick_up_pickup(cls, playerid, pickupid: int): + """Event that is called when a player picks up a pickup. + + :param Player player: The player that picked up the pickup. + :param Pickup pickup: The pickup that was picked up. + """ return (cls(playerid), Pickup(pickupid)) @event("OnPlayerSelectedMenuRow") def on_selected_menu_row(cls, playerid: int, row: int): + """Event that is called when a player selects a menu row. + + :param Player player: The player that selected the menu row. + :param int row: The row that was selected. + """ return (cls(playerid), row) @event("OnPlayerExitedMenu") def on_exited_menu(cls, playerid: int): + """Event that is called when a player exits a menu. + + :param Player player: The player that exited the menu. + """ return (cls(playerid),) @event("OnPlayerInteriorChange") @@ -2525,22 +2672,48 @@ def on_interior_change( newinteriorid: int, oldinteriorid: int, ): + """Event that is called when a player changes interior. + + :param Player player: The player that changed interior. + :param int newinteriorid: The ID of the new interior. + :param int oldinteriorid: The ID of the old interior. + """ return (cls(playerid), newinteriorid, oldinteriorid) @event("OnPlayerKeyStateChange") def on_key_state_change(cls, playerid: int, newkeys: int, oldkeys: int): + """Event that is called when a player changes keys. + + :param Player player: The player that changed keys. + :param int newkeys: The new keys of the player. + :param int oldkeys: The old keys of the player. + """ return (cls(playerid), newkeys, oldkeys) @event("OnPlayerUpdate") def on_update(cls, playerid: int): + """Event that is called when a player updates. + + :param Player player: The player that updated. + """ return (cls(playerid),) @event("OnPlayerStreamIn") def on_stream_in(cls, playerid: int, forplayerid: int): + """Event that is called when a player streams in. + + :param Player player: The player that streamed in. + :param Player forplayer: The player that streamed in. + """ return (cls(playerid), cls(forplayerid)) @event("OnPlayerStreamOut") def on_stream_out(cls, playerid: int, forplayerid: int): + """Event that is called when a player streams out. + + :param Player player: The player that streamed out. + :param Player forplayer: The player that streamed out. + """ return (cls(playerid), cls(forplayerid)) @event("OnPlayerTakeDamage") @@ -2552,6 +2725,14 @@ def on_take_damage( weaponid: int, bodypart: int, ): + """Event that is called when a player takes damage. + + :param Player player: The player that took damage. + :param Player issuer: The player that caused the damage. + :param float amount: The amount of damage that was taken. + :param int weaponid: The ID of the weapon that was used. + :param int bodypart: The body part that was damaged. + """ return ( cls(playerid), issuerid if issuerid == INVALID_PLAYER_ID else cls(issuerid), @@ -2569,6 +2750,14 @@ def on_give_damage( weaponid: int, bodypart: int, ): + """Event that is called when a player gives damage to another player. + + :param Player player: The player that gave damage. + :param Player damaged: The player that was damaged. + :param float amount: The amount of damage that was given. + :param int weaponid: The ID of the weapon that was used. + :param int bodypart: The body part that was damaged. + """ return ( cls(playerid), damagedid if damagedid == INVALID_PLAYER_ID else cls(damagedid), @@ -2586,6 +2775,14 @@ def on_give_damage_actor( weaponid: int, bodypart: int, ): + """Event that is called when a player gives damage to an actor. + + :param Player player: The player that gave damage. + :param Actor damaged: The actor that was damaged. + :param float amount: The amount of damage that was given. + :param int weaponid: The ID of the weapon that was used. + :param int bodypart: The body part that was damaged. + """ return ( cls(playerid), Actor(damaged_actorid), @@ -2596,18 +2793,41 @@ def on_give_damage_actor( @event("OnPlayerClickMap") def on_click_map(cls, playerid: int, x: float, y: float, z: float): + """Event that is called when a player clicks on the map. + + :param Player player: The player that clicked on the map. + :param float x: The X coordinate of the click. + :param float y: The Y coordinate of the click. + :param float z: The Z coordinate of the click. + """ return (cls(playerid), x, y, z) @event("OnPlayerClickTextDraw") def on_click_textdraw(cls, playerid: int, clickedid: int): + """Event that is called when a player clicks on a textdraw. + + :param Player player: The player that clicked on the textdraw. + :param TextDraw textdraw: The textdraw that was clicked on. + """ return (cls(playerid), TextDraw(clickedid)) @event("OnPlayerClickPlayerTextDraw") def on_click_playertextdraw(cls, playerid: int, playertextid: int): + """Event that is called when a player clicks on a player textdraw. + + :param Player player: The player that clicked on the textdraw. + :param TextDraw textdraw: The textdraw that was clicked on. + """ return (cls(playerid), PlayerTextDraw(playertextid, cls(playerid))) @event("OnPlayerClickPlayer") def on_click_player(cls, playerid: int, clickedplayerid: int, source: int): + """Event that is called when a player clicks on another player. + + :param Player player: The player that clicked on the player. + :param Player clickedplayer: The player that was clicked on. + :param int source: The source of the click. + """ return (cls(playerid), cls(clickedplayerid), source) @event("OnPlayerEditObject") @@ -2624,6 +2844,18 @@ def on_edit_object( rot_y: float, rot_z: float, ): + """Event that is called when a player edits an object. + + :param Player player: The player that edited the object. + :param Object object: The object that was edited. + :param int response: The response of the edit. + :param float x: The X coordinate of the edit. + :param float y: The Y coordinate of the edit. + :param float z: The Z coordinate of the edit. + :param float rot_x: The X rotation of the edit. + :param float rot_y: The Y rotation of the edit. + :param float rot_z: The Z rotation of the edit. + """ return ( cls(playerid), PlayerObject(objectid) if is_playerobject else Object(objectid), @@ -2654,6 +2886,23 @@ def on_edit_attached_object( scale_y: float, scale_z: float, ): + """Event that is called when a player edits an attached object. + + :param Player player: The player that edited the object. + :param int response: The response of the edit. + :param int index: The index (slot) to assign the object to (0-9). + :param int modelid: The model to attach. + :param int boneid: The bone to attach the object to. (0-18) + :param float offset_x: X axis offset for the object position. + :param float offset_y: Y axis offset for the object position. + :param float offset_z: Z axis offset for the object position. + :param float rot_x: X axis rotation of the object. + :param float rot_y: Y axis rotation of the object. + :param float rot_z: Z axis rotation of the object. + :param float scale_x: X axis scale of the object. + :param float scale_y: Y axis scale of the object. + :param float scale_z: Z axis scale of the object. + """ return ( cls(playerid), response, @@ -2682,6 +2931,15 @@ def on_select_object( y: float, z: float, ): + """Event that is called when a player selects an object. + + :param Player player: The player that selected the object. + :param Object object: The object that was selected. + :param int modelid: The model of the object. + :param float x: The X coordinate of the object. + :param float y: The Y coordinate of the object. + :param float z: The Z coordinate of the object. + """ object_cls = { SELECT_OBJECT_GLOBAL_OBJECT: Object, SELECT_OBJECT_PLAYER_OBJECT: PlayerObject, @@ -2706,6 +2964,19 @@ def on_weapon_shot( y: float, z: float, ): + """Event that is called when a player fires a weapon. + + Depending on the hittype, the hitid will be different. + You will need to check the hit_cls for the type of hit. + + :param Player player: The player that fired the weapon. + :param int weaponid: The id of the weapon that was fired. + :param (Vehicle|Object|PlayerObject|None) hit: The object that was hit. + :param int hitid: The id of the hit. + :param float x: The X coordinate of the hit. + :param float y: The Y coordinate of the hit. + :param float z: The Z coordinate of the hit. + """ hit_cls = { BULLET_HIT_TYPE_NONE: lambda _: None, BULLET_HIT_TYPE_PLAYER: cls, @@ -2724,6 +2995,12 @@ def on_weapon_shot( @classmethod def command(cls, function=_NO_FUNCTION, **kwargs): + """Decorate a command handler to register it with the given options. + + :param function: The command handler to register. + Useful when there is no need for other arguments, one can use the + bare decorator without calling it. + """ if function is _NO_FUNCTION: return functools.partial(cls.command, **kwargs) diff --git a/pysamp/playerobject.py b/pysamp/playerobject.py index c06d5fc..c99e1ce 100644 --- a/pysamp/playerobject.py +++ b/pysamp/playerobject.py @@ -1,8 +1,6 @@ -from typing import Tuple - -from pysamp.event import event +"""Player Object module, to handle and create player objects.""" -from samp import OBJECT_MATERIAL_SIZE_256x128 +from typing import Tuple from pysamp import ( attach_player_object_to_vehicle, @@ -22,6 +20,8 @@ set_player_object_rot, stop_player_object, ) +from pysamp.event import event +from samp import OBJECT_MATERIAL_SIZE_256x128 class PlayerObject: @@ -45,7 +45,7 @@ class PlayerObject: objects. """ - def __init__(self, id: int, player_id: int): + def __init__(self, id: int, player_id: int): # noqa: D107 self.id = id self._player_id = player_id @@ -218,7 +218,7 @@ def set_material_text( ) def set_position(self, x: float, y: float, z: float) -> bool: - """Set the world coordinates of the player object + """Set the world coordinates of the player object. :param float x: The world x coordinate to set. :param float y: The world y coordinate to set. @@ -391,7 +391,13 @@ def set_material( @event("OnPlayerObjectMoved") def on_moved(cls, playerid: int, objectid: int): + """Event that is called when a player moves an object. + + :param Player player: The player that moved the object. + :param Object object: The object that was moved. + """ return (cls(objectid, playerid), Player(playerid)) + from pysamp.player import Player # noqa from pysamp.vehicle import Vehicle # noqa diff --git a/pysamp/playertextdraw.py b/pysamp/playertextdraw.py index f020702..9455627 100644 --- a/pysamp/playertextdraw.py +++ b/pysamp/playertextdraw.py @@ -1,4 +1,7 @@ -from pysamp.player import Player +"""Textdraws that are per-player. For global textdraws that are shown for +all players, check out :class:`TextDraw`. +""" + from pysamp import ( create_player_text_draw, player_text_draw_alignment, @@ -19,8 +22,9 @@ player_text_draw_set_string, player_text_draw_show, player_text_draw_text_size, - player_text_draw_use_box + player_text_draw_use_box, ) +from pysamp.player import Player class PlayerTextDraw: @@ -296,7 +300,7 @@ def set_preview_rotation( rotation_x: float, rotation_y: float, rotation_z: float, - zoom: float = 1.0 + zoom: float = 1.0, ) -> bool: """Sets the rotation and zoom of a 3D model preview player-textdraw. diff --git a/pysamp/textdraw.py b/pysamp/textdraw.py index cb1e470..74e6ad8 100644 --- a/pysamp/textdraw.py +++ b/pysamp/textdraw.py @@ -1,4 +1,10 @@ +"""Textdraws that are global. For that are separate for +individual players, check out :class:`PlayerTextDraw`. +""" + from pysamp import ( + cancel_select_text_draw, + select_text_draw, text_draw_alignment, text_draw_background_color, text_draw_box_color, @@ -8,7 +14,6 @@ text_draw_font, text_draw_hide_for_all, text_draw_hide_for_player, - text_draw_show_for_player, text_draw_letter_size, text_draw_set_outline, text_draw_set_preview_model, @@ -19,10 +24,9 @@ text_draw_set_shadow, text_draw_set_string, text_draw_show_for_all, + text_draw_show_for_player, text_draw_text_size, text_draw_use_box, - select_text_draw, - cancel_select_text_draw ) @@ -36,6 +40,7 @@ class TextDraw: To create a new textdraw, use :meth:`TextDraw.create`. """ + def __init__(self, id: int) -> None: self.id = id @@ -75,9 +80,7 @@ def create(cls, x: float, y: float, text: str) -> "TextDraw": - If part of the text is off-screen, the color of the text will\ not show, only the shadow (if enabled) will. """ - return cls( - text_draw_create(x, y, text) - ) + return cls(text_draw_create(x, y, text)) def destroy(self) -> bool: """Destroy the textdraw. @@ -87,7 +90,7 @@ def destroy(self) -> bool: return text_draw_destroy(self.id) def letter_size(self, x: float, y: float) -> bool: - """Sets the width and height of the letters. + """Set the width and height of the letters. :param float x: Width of a character. :param float y: Height of a character. @@ -149,7 +152,7 @@ def alignment(self, alignment: int) -> bool: return text_draw_alignment(self.id, alignment) def color(self, color: int) -> bool: - """Sets the text color of the textdraw. + """Set the text color of the textdraw. :param int color: The color you want to give the textdraw, in a ``0xRRGGBBAA`` format. @@ -172,7 +175,7 @@ def use_box(self, use: bool) -> bool: return text_draw_use_box(self.id, use) def box_color(self, color: int) -> bool: - """Sets the text color of a textdraw box. + """Set the text color of a textdraw box. :param int color: Color in ``0xRRGGBBAA`` format. :return: This method does not return anything. @@ -180,7 +183,7 @@ def box_color(self, color: int) -> bool: return text_draw_box_color(self.id, color) def set_shadow(self, size: int) -> bool: - """Adds a shadow to the bottom-right side of the text in a + """Add a shadow to the bottom-right side of the text in a textdraw. The shadow font matches the text font. :param int size: The size of the shadow. 0 will hide the shadow. @@ -278,7 +281,7 @@ def set_string(self, string: str) -> bool: return text_draw_set_string(self.id, string) def set_preview_model(self, model_index: int) -> bool: - """Sets the textdraw 2D preview sprite of a specified model ID. + """Set the textdraw 2D preview sprite of a specified model ID. :param int model_index: The model to show. :return: This method does not return anything. @@ -290,9 +293,9 @@ def set_preview_rotation( rotation_x: float, rotation_y: float, rotation_z: float, - zoom: float = 1.0 + zoom: float = 1.0, ) -> bool: - """Sets the rotation and zoom of a 3D model preview textdraw. + """Set the rotation and zoom of a 3D model preview textdraw. :param float rotation_x: The X rotation value. :param float rotation_y: The Y rotation value. @@ -320,7 +323,7 @@ def set_preview_vehicle_color(self, color1: int, color2: int) -> bool: return text_draw_set_preview_veh_col(self.id, color1, color2) def hide_for_player(self, player: "Player") -> bool: - """This method hides a global textdraw for the player. + """Hide a global textdraw for the player. :param Player player: The player to hide the textdraw for. :return: This method does not return anything. @@ -328,7 +331,7 @@ def hide_for_player(self, player: "Player") -> bool: return text_draw_hide_for_player(player.id, self.id) def show_for_player(self, player: "Player") -> bool: - """This method shows a global textdraw for the selected player. + """Show a global textdraw for the selected player. :param Player player: The player to show the textdraw for. :return: This method does not return anything. diff --git a/pysamp/textlabel.py b/pysamp/textlabel.py index f4e85b3..59f77d6 100644 --- a/pysamp/textlabel.py +++ b/pysamp/textlabel.py @@ -8,12 +8,11 @@ class TextLabel: - """ - Create and adjust 3D-Textlabels that can be attached to + """Create and adjust 3D-Textlabels that can be attached to vehicles, players or world coordinates. """ - def __init__(self, id: int) -> None: + def __init__(self, id: int) -> None: # noqa: D107 self.id: int = id @classmethod @@ -28,20 +27,36 @@ def create( virtual_world: int, testLOS: bool = False, ) -> "TextLabel": + """Create a new 3D Textlabel. - return cls(create_3d_text_label( - text, - color, - x, - y, - z, - draw_distance, - virtual_world, - testLOS, - )) + :param str text: The text you want to show. + :param int color: The color you would like the text to have. + :param float x: The X coordinate of the 3D Textlabel. + :param float y: The Y coordinate of the 3D Textlabel. + :param float z: The Z coordinate of the 3D Textlabel. + :param float draw_distance: The maximum distance at which the 3D + Textlabel can be drawn. + :param int virtual_world: The virtual world in which the 3D Textlabel + should be shown. + :param optional bool testLOS: Set if the 3D Textlabel should test + for line of sight. Defaults to False. + :return: An instance of :class:`TextLabel`. + """ + return cls( + create_3d_text_label( + text, + color, + x, + y, + z, + draw_distance, + virtual_world, + testLOS, + ), + ) def delete(self) -> bool: - """Deletes a 3D text label. + """Remove/Delete a 3D text label. :return: This method does not return any value. """ @@ -52,7 +67,7 @@ def attach_to_player( player: "Player", offset_x: float, offset_y: float, - offset_z: float + offset_z: float, ) -> bool: """Attach a 3D Textlabel to a player. @@ -63,7 +78,11 @@ def attach_to_player( :return: This method does not return anything. """ return attach_3d_text_label_to_player( - self.id, player.id, offset_x, offset_y, offset_z + self.id, + player.id, + offset_x, + offset_y, + offset_z, ) def attach_to_vehicle( @@ -71,7 +90,7 @@ def attach_to_vehicle( vehicle: "Vehicle", offset_x: float, offset_y: float, - offset_z: float + offset_z: float, ) -> bool: """Attach a 3D Textlabel to a vehicle. @@ -82,7 +101,11 @@ def attach_to_vehicle( :return: This method does not return anything. """ return attach_3d_text_label_to_vehicle( - self.id, vehicle.id, offset_x, offset_y, offset_z + self.id, + vehicle.id, + offset_x, + offset_y, + offset_z, ) def update_text(self, color: int, text: str) -> bool: @@ -94,5 +117,6 @@ def update_text(self, color: int, text: str) -> bool: """ return update_3d_text_label_text(self.id, color, text) + from pysamp.vehicle import Vehicle # noqa from pysamp.player import Player # noqa diff --git a/pysamp/timer.py b/pysamp/timer.py deleted file mode 100644 index e84aa2c..0000000 --- a/pysamp/timer.py +++ /dev/null @@ -1,4 +0,0 @@ -from pysamp import ( - set_timer, - kill_timer -) diff --git a/pysamp/vehicle.py b/pysamp/vehicle.py index 1b14ddd..ffe3b2f 100644 --- a/pysamp/vehicle.py +++ b/pysamp/vehicle.py @@ -1,3 +1,7 @@ +"""A module that wraps vehicle related functions.""" + +from typing import Optional, Tuple + from pysamp import ( add_vehicle_component, change_vehicle_color, @@ -40,8 +44,6 @@ set_vehicle_z_angle, update_vehicle_damage_status, ) - -from typing import Optional, Tuple from pysamp.event import event from samp import INVALID_PLAYER_ID @@ -76,8 +78,7 @@ def create( respawn_delay: int, add_siren: bool = False, ) -> "Vehicle": - """Create a new vehicle with the given model, position, colors and - settings. + """Create a new vehicle with the given arguments. :param model: The model of the car (400-622). :param float x: The x coordinate to spawn the vehicle. @@ -90,6 +91,7 @@ def create( automatically respawn. :param optional bool add_siren: Set if the car should have a siren. Defaults to False. + :return: An instance of :class:`Vehicle`. """ return cls( @@ -103,11 +105,11 @@ def create( color2, respawn_delay, add_siren, - ) + ), ) def is_valid(self) -> bool: - """Check if the vehicle is valid""" + """Check if the vehicle is valid.""" return is_valid_vehicle(self.id) def get_distance_from_point(self, x: float, y: float, z: float) -> float: @@ -115,7 +117,7 @@ def get_distance_from_point(self, x: float, y: float, z: float) -> float: return get_vehicle_distance_from_point(self.id, x, y, z) def destroy(self) -> bool: - """Removes the vehicle from the server.""" + """Remove the vehicle from the server.""" return destroy_vehicle(self.id) def is_streamed_in(self, for_player: "Player") -> bool: @@ -127,27 +129,33 @@ def get_position(self) -> Tuple[float, float, float]: return get_vehicle_pos(self.id) def set_position(self, x: float, y: float, z: float) -> bool: - """Sets the vehicle position directly on the passed position.""" + """Set the vehicle position directly to the passed position.""" return set_vehicle_pos(self.id, x, y, z) def get_z_angle(self) -> float: - """Returns the heading the vehicle has. Can be >= 0.0 and < 360.""" + """Get the heading the vehicle has. Can be >= 0.0 and < 360.""" return get_vehicle_z_angle(self.id) def set_z_angle(self, z_angle: float) -> bool: - """Set the vehicle's heading hangle. 0.0 => z_angle < 360.0""" + """Set the vehicle's heading hangle. 0.0 => z_angle < 360.0.""" return set_vehicle_z_angle(self.id, z_angle) def get_rotation_quat(self) -> Tuple[float, float, float, float]: - """Returns a vehicle's rotation on all axes as a quaternion""" + """Get the vehicle's rotation on all axes as a quaternion.""" return get_vehicle_rotation_quat(self.id) def set_params_for_player( - self, player: "Player", objective: int, doors_locked: int + self, + player: "Player", + objective: int, + doors_locked: int, ) -> bool: """Set the parameters on the vehicle.""" return set_vehicle_params_for_player( - self.id, player.id, objective, doors_locked + self.id, + player.id, + objective, + doors_locked, ) def get_params_ex(self) -> Tuple[int, int, int, int, int, int, int]: @@ -155,11 +163,25 @@ def get_params_ex(self) -> Tuple[int, int, int, int, int, int, int]: return get_vehicle_params_ex(self.id) def set_params_ex( - self, engine: int, lights: int, alarm: int, doors: int, bonnet: int, boot: int, objective: int + self, + engine: int, + lights: int, + alarm: int, + doors: int, + bonnet: int, + boot: int, + objective: int, ) -> bool: """Set additional parameters on the vehicle.""" return set_vehicle_params_ex( - self.id, engine, lights, alarm, doors, bonnet, boot, objective + self.id, + engine, + lights, + alarm, + doors, + bonnet, + boot, + objective, ) def get_params_siren_state(self) -> int: @@ -171,7 +193,7 @@ def get_params_siren_state(self) -> int: return get_vehicle_params_siren_state(self.id) def get_params_car_doors(self) -> Tuple[int, int, int, int]: - """Allows you to retrieve the current state of a vehicle's doors + """Get and retrieve the current state of a vehicle's doors. Returns -1 if the door state is not set, like on a bike or a 2-door. Otherwise, it will return 0 (closed) or 1 (open). @@ -181,7 +203,13 @@ def get_params_car_doors(self) -> Tuple[int, int, int, int]: """ return get_vehicle_params_car_doors(self.id) - def set_params_car_doors(self, driver: int, passenger: int, backleft: int, backright: int) -> bool: + def set_params_car_doors( + self, + driver: int, + passenger: int, + backleft: int, + backright: int, + ) -> bool: """Open and close vehicle doors. The doors tuple should be in this order: @@ -190,7 +218,11 @@ def set_params_car_doors(self, driver: int, passenger: int, backleft: int, backr Setting an unavailable door to 0 or 1, has no effect. """ return set_vehicle_params_car_doors( - self.id, driver, passenger, backleft, backright + self.id, + driver, + passenger, + backleft, + backright, ) def get_params_car_windows(self) -> Tuple[int, int, int, int]: @@ -198,11 +230,19 @@ def get_params_car_windows(self) -> Tuple[int, int, int, int]: return get_vehicle_params_car_windows(self.id) def set_params_car_windows( - self, driver: int, passenger: int, backleft: int, backright: int + self, + driver: int, + passenger: int, + backleft: int, + backright: int, ) -> bool: - """Allows you to open and close the windows of a vehicle.""" + """Open and close the windows of a vehicle.""" return set_vehicle_params_car_windows( - self.id, driver, passenger, backleft, backright + self.id, + driver, + passenger, + backleft, + backright, ) def set_to_respawn(self) -> bool: @@ -218,7 +258,7 @@ def link_to_interior(self, interior_id: int) -> bool: return link_vehicle_to_interior(self.id, interior_id) def add_component(self, component_id: int) -> bool: - """Adds a component (often referred to as a modification) + """Add a component (often referred to as a modification) to a vehicle. Valid components can be found here: @@ -304,15 +344,15 @@ def get_model(self) -> int: return get_vehicle_model(self.id) def get_component_in_slot(self, slot: int) -> int: - """Retrieves the installed component ID in the specific slot.""" + """Get the installed component ID in the specific slot.""" return get_vehicle_component_in_slot(self.id, slot) def repair(self) -> bool: - """Fully repairs the vehicle - including health""" + """Fully repair the vehicle and restore health to 1000.0.""" return repair_vehicle(self.id) def get_velocity(self) -> Tuple[float, float, float]: - """Get the vehicle velocity. Vector is relative to the car axis""" + """Get the car velocity. Relative to the car axis.""" return get_vehicle_velocity(self.id) def set_velocity(self, x: float, y: float, z: float) -> bool: @@ -327,8 +367,8 @@ def set_angular_velocity(self, x: float, y: float, z: float) -> bool: return set_vehicle_angular_velocity(self.id, x, y, z) def get_damage_status(self) -> Tuple[int, int, int, int]: - """This method returns information to you about if parts of the - car has been damaged, or tires has been deflated. + """Get information about if parts of the + car has been damaged or if tires has been deflated. Please refer to: https://open.mp/docs/scripting/resources/damagestatus @@ -339,14 +379,24 @@ def get_damage_status(self) -> Tuple[int, int, int, int]: """ return get_vehicle_damage_status(self.id) - def set_damage_status(self, panels: int, doors: int, lights: int, tires: int) -> bool: + def set_damage_status( + self, + panels: int, + doors: int, + lights: int, + tires: int, + ) -> bool: """Set vehicle damage status. Please refer to: https://open.mp/docs/scripting/resources/damagestatus """ return update_vehicle_damage_status( - self.id, panels, doors, lights, tires + self.id, + panels, + doors, + lights, + tires, ) def get_virtual_world(self) -> int: @@ -359,14 +409,17 @@ def set_virtual_world(self, world_id: int) -> bool: @event("OnTrailerUpdate") def on_trailer_update(cls, playerid: int, trailerid: int): + """Event that is triggered when a trailer is attached to a vehicle.""" return (Player(playerid), cls(trailerid)) @event("OnVehicleDamageStatusUpdate") def on_damage_status_update(cls, vehicleid: int, playerid: int): + """Event that is triggered when vehicle damage status changes.""" return (cls(vehicleid), Player(playerid)) @event("OnVehicleDeath") def on_death(cls, vehicleid: int, killerid: int): + """Event that is triggered when a vehicle dies.""" return ( cls(vehicleid), Player(killerid) if killerid != INVALID_PLAYER_ID else killerid, @@ -374,35 +427,52 @@ def on_death(cls, vehicleid: int, killerid: int): @event("OnVehicleMod") def on_mod(cls, playerid: int, vehicleid: int, componentid: int): + """Event that is triggered when a vehicle component is modified.""" return (Player(playerid), cls(vehicleid), componentid) @event("OnVehiclePaintjob") def on_paintjob(cls, playerid: int, vehicleid: int, paintjobid: int): + """Event that is triggered when a vehicle paintjob is changed.""" return (Player(playerid), cls(vehicleid), paintjobid) @event("OnVehicleRespray") def on_respray( - cls, playerid: int, vehicleid: int, color1: int, color2: int + cls, + playerid: int, + vehicleid: int, + color1: int, + color2: int, ): + """Event that is triggered when a vehicle is resprayed in + a respray shop, native to GTA San Andreas. + """ return (Player(playerid), cls(vehicleid), color1, color2) @event("OnVehicleSirenStateChange") def on_siren_state_change( - cls, playerid: int, vehicleid: int, newstate: int + cls, + playerid: int, + vehicleid: int, + newstate: int, ): + """Event that is triggered when a vehicle's siren state changes, + for example when a police vehicle is stopping its siren. + """ return (Player(playerid), cls(vehicleid), newstate) @event("OnVehicleSpawn") def on_spawn(cls, vehicleid: int): - """When a vehicle is respawning only.""" + """Event that is triggered when a vehicle is spawned.""" return (cls(vehicleid),) @event("OnVehicleStreamIn") def on_stream_in(cls, vehicleid: int, forplayerid: int): + """Event that is triggered when a vehicle is streamed in for a player.""" return (cls(vehicleid), Player(forplayerid)) @event("OnVehicleStreamOut") def on_stream_out(cls, vehicleid: int, forplayerid: int): + """Event that is triggered when a vehicle is streamed out for a player.""" return (cls(vehicleid), Player(forplayerid)) @event("OnUnoccupiedVehicleUpdate") @@ -418,6 +488,11 @@ def on_unoccupied_update( vel_y: float, vel_z: float, ): + """Event that is called whenever an unoccupied vehicle is updated. + + Please refer to: + https://www.open.mp/docs/scripting/callbacks/OnUnoccupiedVehicleUpdate + """ return ( cls(vehicleid), Player(playerid),