From 7ecd804c1bc2539906b02c7be9bcd3d8acc42b04 Mon Sep 17 00:00:00 2001 From: Roman Trapeznikov Date: Fri, 11 Feb 2022 14:10:47 +0300 Subject: [PATCH] update examples --- assets/src/ba_data/python/._ba_sources_hash | 2 +- assets/src/ba_data/python/_ba.py | 411 ++++++++++-------- assets/src/ba_data/python/ba/_actor.py | 35 +- assets/src/ba_data/python/ba/_general.py | 54 +-- assets/src/ba_data/python/ba/_language.py | 35 +- .../python/class/python_class_context.cc | 30 +- .../python/class/python_class_context_call.cc | 24 +- .../python/class/python_class_material.cc | 222 +++++----- .../python/class/python_class_node.cc | 13 +- .../python/class/python_class_timer.cc | 23 +- .../python/methods/python_methods_app.cc | 65 +-- .../python/methods/python_methods_system.cc | 11 +- tools/batools/docs.py | 2 +- 13 files changed, 493 insertions(+), 434 deletions(-) diff --git a/assets/src/ba_data/python/._ba_sources_hash b/assets/src/ba_data/python/._ba_sources_hash index 29666224..44b0b236 100644 --- a/assets/src/ba_data/python/._ba_sources_hash +++ b/assets/src/ba_data/python/._ba_sources_hash @@ -1 +1 @@ -175217515325031448193730963697929841246 \ No newline at end of file +225891607870108897605481763130834194451 \ No newline at end of file diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index af61f73e..aff6e065 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -102,7 +102,7 @@ class Context: Category: General Utility Classes - Many operations such as ba.newnode() or ba.gettexture() operate + Many operations such as ba.newnode or ba.gettexture operate implicitly on the current context. Each ba.Activity has its own Context and objects within that activity (nodes, media, etc) can only interact with other objects from that context. @@ -114,17 +114,17 @@ class Context: the UI (there is a special 'ui' context for all user-interface-related functionality) - When instantiating a ba.Context instance, a single 'source' argument + When instantiating a ba.Context instance, a single ``'source'`` argument is passed, which can be one of the following strings/objects: - 'empty': + ``'empty'``: Gives an empty context; it can be handy to run code here to ensure it does no loading of media, creation of nodes, etc. - 'current': + ``'current'``: Sets the context object to the current context. - 'ui': + ``'ui'``: Sets to the UI context. UI functions as well as loading of media to be used in said functions must happen in the UI context. @@ -138,16 +138,18 @@ class Context: Usage: + Contexts are generally used with the python 'with' statement, which + sets the context as current on entry and resets it to the previous + value on exit. - Contexts are generally used with the python 'with' statement, which - sets the context as current on entry and resets it to the previous - value on exit. - - # Example: load a few textures into the UI context - # (for use in widgets, etc): - with ba.Context('ui'): - tex1 = ba.gettexture('foo_tex_1') - tex2 = ba.gettexture('foo_tex_2') + Example: + Load a few textures into the UI context + (for use in widgets, etc): + ```python + >>> with ba.Context('ui'): + ... tex1 = ba.gettexture('foo_tex_1') + ... tex2 = ba.gettexture('foo_tex_2') + ``` """ def __init__(self, source: Any): @@ -189,17 +191,21 @@ class ContextCall: shutdown, whereas ba.WeakCall simply looks at whether the target object still exists. - # Example A: code like this can inadvertently prevent our activity - # (self) from ending until the operation completes, since the bound - # method we're passing (self.dosomething) contains a strong-reference - # to self). - start_some_long_action(callback_when_done=self.dosomething) + Examples: + Example A: code like this can inadvertently prevent our activity + (self) from ending until the operation completes, since the bound + method we're passing (self.dosomething) contains a strong-reference + to self). + >>> start_some_long_action(callback_when_done=self.dosomething) - # Example B: in this case our activity (self) can still die - # properly; the callback will clear itself when the activity starts - # shutting down, becoming a harmless no-op and releasing the reference - # to our activity. - start_long_action(callback_when_done=ba.ContextCall(self.mycallback)) + Example B: in this case our activity (self) can still die + properly; the callback will clear itself when the activity starts + shutting down, becoming a harmless no-op and releasing the reference + to our activity. + ```python + >>> start_long_action( + ... callback_when_done=ba.ContextCall(self.mycallback)) + ``` """ def __init__(self, call: Callable): @@ -235,41 +241,41 @@ class InputDevice: Attributes: - allows_configuring + allows_configuring (bool): Whether the input-device can be configured. - has_meaningful_button_names + has_meaningful_button_names (bool): Whether button names returned by this instance match labels on the actual device. (Can be used to determine whether to show them in controls-overlays, etc.). - player + player (Optional[ba.SessionPlayer]): The player associated with this input device. - client_id + client_id (int): The numeric client-id this device is associated with. This is only meaningful for remote client inputs; for all local devices this will be -1. - name + name (str): The name of the device. - unique_identifier + unique_identifier (str): A string that can be used to persistently identify the device, even among other devices of the same type. Used for saving prefs, etc. - id + id (int): The unique numeric id of this device. - instance_number + instance_number (int): The number of this device among devices of the same type. - is_controller_app + is_controller_app (bool): Whether this input-device represents a locally-connected controller-app. - is_remote_client + is_remote_client (bool): Whether this input-device represents a remotely-connected client. @@ -362,20 +368,20 @@ class Material: A material can affect physical characteristics, generate sounds, or trigger callback functions when collisions occur. - Materials are applied to 'parts', which are groups of one or more - rigid bodies created as part of a ba.Node. Nodes can have any number + Materials are applied to ``'parts'``, which are groups of one or more + rigid bodies created as part of a ba.Node. Nodes can have any number of parts, each with its own set of materials. Generally materials are - specified as array attributes on the Node. The 'spaz' node, for - example, has various attributes such as 'materials', - 'roller_materials', and 'punch_materials', which correspond to the + specified as array attributes on the Node. The ``'spaz'`` node, for + example, has various attributes such as ``'materials'``, + ``'roller_materials'``, and ``'punch_materials'``, which correspond to the various parts it creates. - Use ba.Material() to instantiate a blank material, and then use its - add_actions() method to define what the material does. + Use ba.Material to instantiate a blank material, and then use its + ba.Material.add_actions method to define what the material does. Attributes: - label + label (str): A label for the material; only used for debugging. """ @@ -393,133 +399,139 @@ class Material: Add one or more actions to the material, optionally with conditions. Conditions: + Conditions are provided as tuples which can be combined to form boolean + logic. A single condition might look like ``('condition_name', cond_arg)``, + or a more complex nested one might look like ``(('some_condition', + cond_arg), 'or', ('another_condition', cond2_arg))``. - Conditions are provided as tuples which can be combined to form boolean - logic. A single condition might look like ('condition_name', cond_arg), - or a more complex nested one might look like (('some_condition', - cond_arg), 'or', ('another_condition', cond2_arg)). - - 'and', 'or', and 'xor' are available to chain together 2 conditions, as - seen above. + ``'and'``, ``'or'``, and ``'xor'`` are available to chain together 2 conditions, as + seen above. Available Conditions: + ``('they_have_material', material)`` - does the part we're hitting have a + given ba.Material? - ('they_have_material', material) - does the part we're hitting have a - given ba.Material? + ``('they_dont_have_material', material)`` - does the part we're hitting + not have a given ba.Material? - ('they_dont_have_material', material) - does the part we're hitting - not have a given ba.Material? + ``('eval_colliding')`` - is ``'collide'`` true at this point in material + evaluation? (see the modify_part_collision action) - ('eval_colliding') - is 'collide' true at this point in material - evaluation? (see the modify_part_collision action) + ``('eval_not_colliding')`` - is 'collide' false at this point in material + evaluation? (see the modify_part_collision action) - ('eval_not_colliding') - is 'collide' false at this point in material - evaluation? (see the modify_part_collision action) + ``('we_are_younger_than', age)`` - is our part younger than ``'age'`` + (in milliseconds)? - ('we_are_younger_than', age) - is our part younger than 'age' - (in milliseconds)? + ``('we_are_older_than', age)`` - is our part older than ``'age'`` + (in milliseconds)? - ('we_are_older_than', age) - is our part older than 'age' - (in milliseconds)? + ``('they_are_younger_than', age)`` - is the part we're hitting younger than + ``'age'`` (in milliseconds)? - ('they_are_younger_than', age) - is the part we're hitting younger than - 'age' (in milliseconds)? + ``('they_are_older_than', age)`` - is the part we're hitting older than + ``'age'`` (in milliseconds)? - ('they_are_older_than', age) - is the part we're hitting older than - 'age' (in milliseconds)? + ``('they_are_same_node_as_us')`` - does the part we're hitting belong to + the same ba.Node as us? - ('they_are_same_node_as_us') - does the part we're hitting belong to - the same ba.Node as us? - - ('they_are_different_node_than_us') - does the part we're hitting - belong to a different ba.Node than us? + ``('they_are_different_node_than_us')`` - does the part we're hitting + belong to a different ba.Node than us? Actions: - - In a similar manner, actions are specified as tuples. Multiple actions - can be specified by providing a tuple of tuples. + In a similar manner, actions are specified as tuples. Multiple actions + can be specified by providing a tuple of tuples. Available Actions: + ``('call', when, callable)`` - calls the provided callable; ``'when'`` can be + either ``'at_connect'`` or ``'at_disconnect'``. ``'at_connect'`` means to fire + when the two parts first come in contact; ``'at_disconnect'`` means to + fire once they cease being in contact. - ('call', when, callable) - calls the provided callable; 'when' can be - either 'at_connect' or 'at_disconnect'. 'at_connect' means to fire - when the two parts first come in contact; 'at_disconnect' means to - fire once they cease being in contact. + ``('message', who, when, message_obj)`` - sends a message object; ``'who'`` can + be either ``'our_node'`` or ``'their_node'``, ``'when'`` can be ``'at_connect'`` or + ``'at_disconnect'``, and message_obj is the message object to send. + This has the same effect as calling the node's ba.Node.handlemessage + method. - ('message', who, when, message_obj) - sends a message object; 'who' can - be either 'our_node' or 'their_node', 'when' can be 'at_connect' or - 'at_disconnect', and message_obj is the message object to send. - This has the same effect as calling the node's handlemessage() - method. + ``('modify_part_collision', attr, value)`` - changes some characteristic + of the physical collision that will occur between our part and their + part. This change will remain in effect as long as the two parts + remain overlapping. This means if you have a part with a material + that turns ``'collide'`` off against parts younger than 100ms, and it + touches another part that is 50ms old, it will continue to not + collide with that part until they separate, even if the 100ms + threshold is passed. Options for attr/value are: ``'physical'`` (boolean + value; whether a *physical* response will occur at all), ``'friction'`` + (float value; how friction-y the physical response will be), + ``'collide'`` (boolean value; whether *any* collision will occur at all, + including non-physical stuff like callbacks), ``'use_node_collide'`` + (boolean value; whether to honor modify_node_collision overrides for + this collision), ``'stiffness'`` (float value, how springy the physical + response is), ``'damping'`` (float value, how damped the physical + response is), ``'bounce'`` (float value; how bouncy the physical response + is). - ('modify_part_collision', attr, value) - changes some characteristic - of the physical collision that will occur between our part and their - part. This change will remain in effect as long as the two parts - remain overlapping. This means if you have a part with a material - that turns 'collide' off against parts younger than 100ms, and it - touches another part that is 50ms old, it will continue to not - collide with that part until they separate, even if the 100ms - threshold is passed. Options for attr/value are: 'physical' (boolean - value; whether a *physical* response will occur at all), 'friction' - (float value; how friction-y the physical response will be), - 'collide' (boolean value; whether *any* collision will occur at all, - including non-physical stuff like callbacks), 'use_node_collide' - (boolean value; whether to honor modify_node_collision overrides for - this collision), 'stiffness' (float value, how springy the physical - response is), 'damping' (float value, how damped the physical - response is), 'bounce' (float value; how bouncy the physical response - is). + ``('modify_node_collision', attr, value)`` - similar to + ``modify_part_collision``, but operates at a node-level. + collision attributes set here will remain in effect as long as + *anything* from our part's node and their part's node overlap. + A key use of this functionality is to prevent new nodes from + colliding with each other if they appear overlapped; + if ``modify_part_collision`` is used, only the individual parts that + were overlapping would avoid contact, but other parts could still + contact leaving the two nodes 'tangled up'. Using + ``modify_node_collision ensures`` that the nodes must completely + separate before they can start colliding. Currently the only attr + available here is ``'collide'`` (a boolean value). - ('modify_node_collision', attr, value) - similar to - modify_part_collision, but operates at a node-level. - collision attributes set here will remain in effect as long as - *anything* from our part's node and their part's node overlap. - A key use of this functionality is to prevent new nodes from - colliding with each other if they appear overlapped; - if modify_part_collision is used, only the individual parts that - were overlapping would avoid contact, but other parts could still - contact leaving the two nodes 'tangled up'. Using - modify_node_collision ensures that the nodes must completely - separate before they can start colliding. Currently the only attr - available here is 'collide' (a boolean value). + ``('sound', sound, volume)`` - plays a ba.Sound when a collision occurs, at + a given volume, regardless of the collision speed/etc. - ('sound', sound, volume) - plays a ba.Sound when a collision occurs, at - a given volume, regardless of the collision speed/etc. + ``('impact_sound', sound, targetImpulse, volume)`` - plays a sound when a + collision occurs, based on the speed of impact. Provide a ba.Sound, a + target-impulse, and a volume. - ('impact_sound', sound, targetImpulse, volume) - plays a sound when a - collision occurs, based on the speed of impact. Provide a ba.Sound, a - target-impulse, and a volume. + ``('skid_sound', sound, targetImpulse, volume)`` - plays a sound during a + collision when parts are 'scraping' against each other. Provide a + ba.Sound, a target-impulse, and a volume. - ('skid_sound', sound, targetImpulse, volume) - plays a sound during a - collision when parts are 'scraping' against each other. Provide a - ba.Sound, a target-impulse, and a volume. + ``('roll_sound', sound, targetImpulse, volume)`` - plays a sound during a + collision when parts are 'rolling' against each other. Provide a + ba.Sound, a target-impulse, and a volume. - ('roll_sound', sound, targetImpulse, volume) - plays a sound during a - collision when parts are 'rolling' against each other. Provide a - ba.Sound, a target-impulse, and a volume. + Examples: + example 1: create a material that lets us ignore + collisions against any nodes we touch in the first + 100 ms of our existence; handy for preventing us from + exploding outward if we spawn on top of another object: + ```python + >>> m = ba.Material() + ... m.add_actions( + ... conditions=(('we_are_younger_than', 100), + ... 'or', ('they_are_younger_than', 100)), + ... actions=('modify_node_collision', 'collide', False)) + ``` - # example 1: create a material that lets us ignore - # collisions against any nodes we touch in the first - # 100 ms of our existence; handy for preventing us from - # exploding outward if we spawn on top of another object: - m = ba.Material() - m.add_actions(conditions=(('we_are_younger_than', 100), - 'or',('they_are_younger_than', 100)), - actions=('modify_node_collision', 'collide', False)) + example 2: send a ba.DieMessage to anything we touch, but cause + no physical response. This should cause any ba.Actor to drop dead: + ```python + >>> m = ba.Material() + ... m.add_actions( + ... actions=(('modify_part_collision', 'physical', False), + ... ('message', 'their_node', 'at_connect', + ... ba.DieMessage()))) + ``` - # example 2: send a DieMessage to anything we touch, but cause - # no physical response. This should cause any ba.Actor to drop dead: - m = ba.Material() - m.add_actions(actions=(('modify_part_collision', 'physical', False), - ('message', 'their_node', 'at_connect', - ba.DieMessage()))) - - # example 3: play some sounds when we're contacting the ground: - m = ba.Material() - m.add_actions(conditions=('they_have_material', - shared.footing_material), - actions=(('impact_sound', ba.getsound('metalHit'), 2, 5), - ('skid_sound', ba.getsound('metalSkid'), 2, 5))) + example 3: play some sounds when we're contacting the ground: + ```python + >>> m = ba.Material() + ... m.add_actions( + ... conditions=('they_have_material', + shared.footing_material), + ... actions=(('impact_sound', ba.getsound('metalHit'), 2, 5), + ... ('skid_sound', ba.getsound('metalSkid'), 2, 5))) + ``` """ return None @@ -688,14 +700,17 @@ class Node: Connect one of this node's attributes to an attribute on another node. This will immediately set the target attribute's value to that of the source attribute, and will continue to do so once per step as long as - the two nodes exist. The connection can be severed by setting the + the two nodes exist. The connection can be severed by setting the target attribute to any value or connecting another node attribute to it. - # Example: create a locator and attach a light to it: - light = ba.newnode('light') - loc = ba.newnode('locator', attrs={'position': (0,10,0)}) - loc.connectattr('position', light, 'position') + Example: + Create a locator and attach a light to it: + ```python + >>> light = ba.newnode('light') + ... loc = ba.newnode('locator', attrs={'position': (0, 10, 0)}) + ... loc.connectattr('position', light, 'position') + ``` """ return None @@ -1005,16 +1020,19 @@ class Timer: timeformat: A ba.TimeFormat value determining how the passed time is interpreted. - # Example: use a Timer object to print repeatedly for a few seconds: - def say_it(): - ba.screenmessage('BADGER!') - def stop_saying_it(): - self.t = None - ba.screenmessage('MUSHROOM MUSHROOM!') - # Create our timer; it will run as long as we have the self.t ref. - self.t = ba.Timer(0.3, say_it, repeat=True) - # Now fire off a one-shot timer to kill it. - ba.timer(3.89, stop_saying_it) + Example: + Use a Timer object to print repeatedly for a few seconds: + ```python + >>> def say_it(): + ... ba.screenmessage('BADGER!') + ... def stop_saying_it(): + ... self.t = None + ... ba.screenmessage('MUSHROOM MUSHROOM!') + ... # Create our timer; it will run as long as we have the self.t ref. + ... self.t = ba.Timer(0.3, say_it, repeat=True) + ... # Now fire off a one-shot timer to kill it. + ... ba.timer(3.89, stop_saying_it) + ``` """ def __init__(self, @@ -1797,10 +1815,13 @@ def do_once() -> bool: The call is made from. Returns True if this location has not been registered already, and False if it has. - # Example: this print will only fire for the first loop iteration: - for i in range(10): - if ba.do_once(): - print('Hello once from loop!') + Example: + This print will only fire for the first loop iteration: + ```python + >>> for i in range(10): + ... if ba.do_once(): + ... print('Hello once from loop!') + ``` """ return bool() @@ -3572,8 +3593,8 @@ def set_have_mods(have_mods: bool) -> None: def set_internal_language_keys( - listobj: list[tuple[str, str]], - random_names_list: list[tuple[str, str]]) -> None: + listobj: list[tuple[str, str]], + random_names_list: list[tuple[str, str]]) -> None: """set_internal_language_keys(listobj: list[tuple[str, str]], random_names_list: list[tuple[str, str]]) -> None @@ -3591,7 +3612,7 @@ def set_low_level_config_value(key: str, value: int) -> None: def set_map_bounds( - bounds: tuple[float, float, float, float, float, float]) -> None: + bounds: tuple[float, float, float, float, float, float]) -> None: """set_map_bounds(bounds: tuple[float, float, float, float, float, float]) -> None @@ -3943,8 +3964,8 @@ def textwidget(edit: ba.Widget = None, @overload def time( - timetype: ba.TimeType = TimeType.SIM, - timeformat: Literal[TimeFormat.SECONDS] = TimeFormat.SECONDS) -> float: + timetype: ba.TimeType = TimeType.SIM, + timeformat: Literal[TimeFormat.SECONDS] = TimeFormat.SECONDS) -> float: ... @@ -4037,45 +4058,53 @@ def timer(time: float, This timer cannot be canceled or modified once created. If you require the ability to do so, use the ba.Timer class instead. - time: length of time (in seconds by default) that the timer will wait - before firing. Note that the actual delay experienced may vary - depending on the timetype. (see below) + Arguments: + time (float): + Length of time (in seconds by default) that the timer will wait + before firing. Note that the actual delay experienced may vary + depending on the timetype. (see below) - call: A callable Python object. Note that the timer will retain a - strong reference to the callable for as long as it exists, so you - may want to look into concepts such as ba.WeakCall if that is not - desired. + call (Callable[[], Any]): + A callable Python object. Note that the timer will retain a + strong reference to the callable for as long as it exists, so you + may want to look into concepts such as ba.WeakCall if that is not + desired. - repeat: if True, the timer will fire repeatedly, with each successive - firing having the same delay as the first. + repeat (bool): + If True, the timer will fire repeatedly, with each successive + firing having the same delay as the first. - timetype can be either 'sim', 'base', or 'real'. It defaults to - 'sim'. Types are explained below: - 'sim' time maps to local simulation time in ba.Activity or ba.Session + timetype (ba.TimeType): + Can be either ``SIM``, ``BASE``, or ``REAL``. It defaults to + ``SIM``. + + timeformat (ba.TimeFormat): + Defaults to seconds but can also be milliseconds. + + - SIM time maps to local simulation time in ba.Activity or ba.Session Contexts. This means that it may progress slower in slow-motion play modes, stop when the game is paused, etc. This time type is not available in UI contexts. - - 'base' time is also linked to gameplay in ba.Activity or ba.Session + - BASE time is also linked to gameplay in ba.Activity or ba.Session Contexts, but it progresses at a constant rate regardless of slow-motion states or pausing. It can, however, slow down or stop in certain cases such as network outages or game slowdowns due to cpu load. Like 'sim' time, this is unavailable in UI contexts. - - 'real' time always maps to actual clock time with a bit of filtering - added, regardless of Context. (the filtering prevents it from going + - REAL time always maps to actual clock time with a bit of filtering + added, regardless of Context. (The filtering prevents it from going backwards or jumping forward by large amounts due to the app being backgrounded, system time changing, etc.) Real time timers are currently only available in the UI context. - the 'timeformat' arg defaults to seconds but can also be milliseconds. - - # timer example: print some stuff through time: - ba.screenmessage('hello from now!') - ba.timer(1.0, ba.Call(ba.screenmessage, 'hello from the future!')) - ba.timer(2.0, ba.Call(ba.screenmessage, 'hello from the future 2!')) - """ + Examples: + Print some stuff through time: + ```python + >>> ba.screenmessage('hello from now!') + >>> ba.timer(1.0, ba.Call(ba.screenmessage, 'hello from the future!')) + >>> ba.timer(2.0, ba.Call(ba.screenmessage, + ... 'hello from the future 2!')) + ```""" return None diff --git a/assets/src/ba_data/python/ba/_actor.py b/assets/src/ba_data/python/ba/_actor.py index 53cdca2a..d5471679 100644 --- a/assets/src/ba_data/python/ba/_actor.py +++ b/assets/src/ba_data/python/ba/_actor.py @@ -33,15 +33,18 @@ class Actor: (killing off or transitioning out their nodes) when the last Python reference to them disappears, so you can use logic such as: - # Create a flag Actor in our game activity: - from bastd.actor.flag import Flag - self.flag = Flag(position=(0, 10, 0)) - - # Later, destroy the flag. - # (provided nothing else is holding a reference to it) - # We could also just assign a new flag to this value. - # Either way, the old flag disappears. - self.flag = None + Example: + ```python + >>> # Create a flag Actor in our game activity: + >>> from bastd.actor.flag import Flag + >>> self.flag = Flag(position=(0, 10, 0)) + >>> + >>> # Later, destroy the flag. + >>> # (provided nothing else is holding a reference to it) + >>> # We could also just assign a new flag to this value. + >>> # Either way, the old flag disappears. + >>> self.flag = None + ``` This is in contrast to the behavior of the more low level ba.Nodes, which are always explicitly created and destroyed and don't care @@ -51,18 +54,18 @@ class Actor: if you want an Actor to stick around until explicitly killed regardless of references. - Another key feature of ba.Actor is its handlemessage() method, which + Another key feature of ba.Actor is its ba.Actor.handlemessage method, which takes a single arbitrary object as an argument. This provides a safe way to communicate between ba.Actor, ba.Activity, ba.Session, and any other class providing a handlemessage() method. The most universally handled message type for Actors is the ba.DieMessage. - # Another way to kill the flag from the example above: - # We can safely call this on any type with a 'handlemessage' method - # (though its not guaranteed to always have a meaningful effect). - # In this case the Actor instance will still be around, but its exists() - # and is_alive() methods will both return False. - self.flag.handlemessage(ba.DieMessage()) + Another way to kill the flag from the example above: + We can safely call this on any type with a 'handlemessage' method + (though its not guaranteed to always have a meaningful effect). + In this case the Actor instance will still be around, but its exists() + and is_alive() methods will both return False. + >>> self.flag.handlemessage(ba.DieMessage()) """ def __init__(self) -> None: diff --git a/assets/src/ba_data/python/ba/_general.py b/assets/src/ba_data/python/ba/_general.py index a025c9f0..220b1ccd 100644 --- a/assets/src/ba_data/python/ba/_general.py +++ b/assets/src/ba_data/python/ba/_general.py @@ -166,6 +166,15 @@ class _WeakCall: ... ba.timer(5.0, ba.WeakCall(foo.bar)) ... foo = None + EXAMPLE C: Wrap a method call with some positional and keyword args: + >>> myweakcall = ba.WeakCall(self.dostuff, argval1, + ... namedarg=argval2) + ... # Now we have a single callable to run that whole mess. + ... # The same as calling myobj.dostuff(argval1, namedarg=argval2) + ... # (provided my_obj still exists; this will do nothing + ... # otherwise). + ... myweakcall() + Note: additional args and keywords you provide to the WeakCall() constructor are stored as regular strong-references; you'll need to wrap them in weakrefs manually if desired. @@ -176,17 +185,6 @@ class _WeakCall: Pass a callable as the first arg, followed by any number of arguments or keywords. - - Examples: - Example: wrap a method call with some positional and - keyword args: - >>> myweakcall = ba.WeakCall(myobj.dostuff, argval1, - ... namedarg=argval2) - ... # Now we have a single callable to run that whole mess. - ... # The same as calling myobj.dostuff(argval1, namedarg=argval2) - ... # (provided my_obj still exists; this will do nothing - ... # otherwise). - ... myweakcall() """ if hasattr(args[0], '__func__'): self._call = WeakMethod(args[0]) @@ -232,12 +230,12 @@ class _Call: Pass a callable as the first arg, followed by any number of arguments or keywords. - # Example: wrap a method call with 1 positional and 1 keyword arg: - mycall = ba.Call(myobj.dostuff, argval1, namedarg=argval2) - - # Now we have a single callable to run that whole mess. - # ..the same as calling myobj.dostuff(argval1, namedarg=argval2) - mycall() + Example: + Wrap a method call with 1 positional and 1 keyword arg: + >>> mycall = ba.Call(myobj.dostuff, argval, namedarg=argval2) + ... # Now we have a single callable to run that whole mess. + ... # ..the same as calling myobj.dostuff(argval, namedarg=argval2) + ... mycall() """ self._call = args[0] self._args = args[1:] @@ -251,7 +249,6 @@ class _Call: str(self._args) + ' _keywds=' + str(self._keywds) + '>') -# Hack: pdoc won't run this if TYPE_CHECKING: WeakCall = Call Call = Call @@ -375,15 +372,18 @@ def storagename(suffix: str = None) -> str: Note that this will function even if called in the class definition. - # Example: generate a unique name for storage purposes: - class MyThingie: - - # This will give something like '_mymodule_submodule_mythingie_data'. - _STORENAME = ba.storagename('data') - - # Use that name to store some data in the Activity we were passed. - def __init__(self, activity): - activity.customdata[self._STORENAME] = {} + Examples: + Generate a unique name for storage purposes: + ```python + >>> class MyThingie: + ... # This will give something like + ... # '_mymodule_submodule_mythingie_data'. + ... _STORENAME = ba.storagename('data') + ... + ... # Use that name to store some data in the Activity we were passed. + ... def __init__(self, activity): + ... activity.customdata[self._STORENAME] = {} + ``` """ frame = inspect.currentframe() if frame is None: diff --git a/assets/src/ba_data/python/ba/_language.py b/assets/src/ba_data/python/ba/_language.py index 6bf49f3e..a7fac030 100644 --- a/assets/src/ba_data/python/ba/_language.py +++ b/assets/src/ba_data/python/ba/_language.py @@ -376,24 +376,29 @@ class Lstr: To see available resource keys, look at any of the bs_language_*.py files in the game or the translations pages at bombsquadgame.com/translate. - # EXAMPLE 1: specify a string from a resource path - mynode.text = ba.Lstr(resource='audioSettingsWindow.titleText') + Examples: + EXAMPLE 1: specify a string from a resource path + >>> mynode.text = ba.Lstr(resource='audioSettingsWindow.titleText') - # EXAMPLE 2: specify a translated string via a category and english value; - # if a translated value is available, it will be used; otherwise the - # english value will be. To see available translation categories, look - # under the 'translations' resource section. - mynode.text = ba.Lstr(translate=('gameDescriptions', 'Defeat all enemies')) + EXAMPLE 2: specify a translated string via a category and english + value; if a translated value is available, it will be used; otherwise + the english value will be. To see available translation categories, + look under the 'translations' resource section. + >>> mynode.text = ba.Lstr(translate=('gameDescriptions', 'Defeat all enemies')) - # EXAMPLE 3: specify a raw value and some substitutions. Substitutions can - # be used with resource and translate modes as well. - mynode.text = ba.Lstr(value='${A} / ${B}', - subs=[('${A}', str(score)), ('${B}', str(total))]) + EXAMPLE 3: specify a raw value and some substitutions. Substitutions + can be used with resource and translate modes as well. + >>> mynode.text = ba.Lstr(value='${A} / ${B}', + ... subs=[('${A}', str(score)), ('${B}', str(total))]) - # EXAMPLE 4: Lstrs can be nested. This example would display the resource - # at res_a but replace ${NAME} with the value of the resource at res_b - mytextnode.text = ba.Lstr(resource='res_a', - subs=[('${NAME}', ba.Lstr(resource='res_b'))]) + EXAMPLE 4: ba.Lstr's can be nested. This example would display the + resource at res_a but replace ${NAME} with the value of the + resource at res_b + ```python + >>> mytextnode.text = ba.Lstr( + ... resource='res_a', + ... subs=[('${NAME}', ba.Lstr(resource='res_b'))]) + ``` """ # pylint: disable=dangerous-default-value diff --git a/src/ballistica/python/class/python_class_context.cc b/src/ballistica/python/class/python_class_context.cc index 4c65011f..6927f66d 100644 --- a/src/ballistica/python/class/python_class_context.cc +++ b/src/ballistica/python/class/python_class_context.cc @@ -21,7 +21,7 @@ void PythonClassContext::SetupType(PyTypeObject* obj) { "\n" "Category: General Utility Classes\n" "\n" - "Many operations such as ba.newnode() or ba.gettexture() operate\n" + "Many operations such as ba.newnode or ba.gettexture operate\n" "implicitly on the current context. Each ba.Activity has its own\n" "Context and objects within that activity (nodes, media, etc) can only\n" "interact with other objects from that context.\n" @@ -33,16 +33,16 @@ void PythonClassContext::SetupType(PyTypeObject* obj) { "the UI (there is a special 'ui' context for all user-interface-related\n" "functionality)\n" "\n" - "When instantiating a ba.Context instance, a single 'source' argument\n" + "When instantiating a ba.Context instance, a single ``'source'`` argument\n" "is passed, which can be one of the following strings/objects:\n\n" - "'empty':\n" + "``'empty'``:\n" " Gives an empty context; it can be handy to run code here to ensure\n" " it does no loading of media, creation of nodes, etc.\n" "\n" - "'current':\n" + "``'current'``:\n" " Sets the context object to the current context.\n" "\n" - "'ui':\n" + "``'ui'``:\n" " Sets to the UI context. UI functions as well as loading of media to\n" " be used in said functions must happen in the UI context.\n" "\n" @@ -56,16 +56,18 @@ void PythonClassContext::SetupType(PyTypeObject* obj) { "\n" "\n" "Usage:\n" + " Contexts are generally used with the python 'with' statement, which\n" + " sets the context as current on entry and resets it to the previous\n" + " value on exit.\n" "\n" - "Contexts are generally used with the python 'with' statement, which\n" - "sets the context as current on entry and resets it to the previous\n" - "value on exit.\n" - "\n" - "# Example: load a few textures into the UI context\n" - "# (for use in widgets, etc):\n" - "with ba.Context('ui'):\n" - " tex1 = ba.gettexture('foo_tex_1')\n" - " tex2 = ba.gettexture('foo_tex_2')\n"; + "Example:\n" + " Load a few textures into the UI context\n" + " (for use in widgets, etc):\n" + " ```python\n" + " >>> with ba.Context('ui'):\n" + " ... tex1 = ba.gettexture('foo_tex_1')\n" + " ... tex2 = ba.gettexture('foo_tex_2')\n" + " ```\n"; obj->tp_new = tp_new; obj->tp_dealloc = (destructor)tp_dealloc; diff --git a/src/ballistica/python/class/python_class_context_call.cc b/src/ballistica/python/class/python_class_context_call.cc index 10273e2d..d7f66941 100644 --- a/src/ballistica/python/class/python_class_context_call.cc +++ b/src/ballistica/python/class/python_class_context_call.cc @@ -38,17 +38,21 @@ void PythonClassContextCall::SetupType(PyTypeObject* obj) { "shutdown, whereas ba.WeakCall simply looks at whether the target\n" "object still exists.\n" "\n" - "# Example A: code like this can inadvertently prevent our activity\n" - "# (self) from ending until the operation completes, since the bound\n" - "# method we're passing (self.dosomething) contains a strong-reference\n" - "# to self).\n" - "start_some_long_action(callback_when_done=self.dosomething)\n" + "Examples:\n" + " Example A: code like this can inadvertently prevent our activity\n" + " (self) from ending until the operation completes, since the bound\n" + " method we're passing (self.dosomething) contains a strong-reference\n" + " to self).\n" + " >>> start_some_long_action(callback_when_done=self.dosomething)\n" "\n" - "# Example B: in this case our activity (self) can still die\n" - "# properly; the callback will clear itself when the activity starts\n" - "# shutting down, becoming a harmless no-op and releasing the reference\n" - "# to our activity.\n" - "start_long_action(callback_when_done=ba.ContextCall(self.mycallback))\n"; + " Example B: in this case our activity (self) can still die\n" + " properly; the callback will clear itself when the activity starts\n" + " shutting down, becoming a harmless no-op and releasing the reference\n" + " to our activity.\n" + " ```python\n" + " >>> start_long_action(\n" + " ... callback_when_done=ba.ContextCall(self.mycallback))\n" + " ```\n"; obj->tp_new = tp_new; obj->tp_dealloc = (destructor)tp_dealloc; diff --git a/src/ballistica/python/class/python_class_material.cc b/src/ballistica/python/class/python_class_material.cc index b5175919..4685dfdf 100644 --- a/src/ballistica/python/class/python_class_material.cc +++ b/src/ballistica/python/class/python_class_material.cc @@ -56,16 +56,16 @@ void PythonClassMaterial::SetupType(PyTypeObject* obj) { "A material can affect physical characteristics, generate sounds,\n" "or trigger callback functions when collisions occur.\n" "\n" - "Materials are applied to 'parts', which are groups of one or more\n" - "rigid bodies created as part of a ba.Node. Nodes can have any number\n" + "Materials are applied to ``'parts'``, which are groups of one or more\n" + "rigid bodies created as part of a ba.Node. Nodes can have any number\n" "of parts, each with its own set of materials. Generally materials are\n" - "specified as array attributes on the Node. The 'spaz' node, for\n" - "example, has various attributes such as 'materials',\n" - "'roller_materials', and 'punch_materials', which correspond to the\n" + "specified as array attributes on the Node. The ``'spaz'`` node, for\n" + "example, has various attributes such as ``'materials'``,\n" + "``'roller_materials'``, and ``'punch_materials'``, which correspond to the\n" "various parts it creates.\n" "\n" - "Use ba.Material() to instantiate a blank material, and then use its\n" - "add_actions() method to define what the material does.\n" + "Use ba.Material to instantiate a blank material, and then use its\n" + "ba.Material.add_actions method to define what the material does.\n" "\n" "Attributes:\n" "\n" @@ -281,133 +281,139 @@ PyMethodDef PythonClassMaterial::tp_methods[] = { "Add one or more actions to the material, optionally with conditions.\n" "\n" "Conditions:\n" + " Conditions are provided as tuples which can be combined to form boolean\n" + " logic. A single condition might look like ``('condition_name', cond_arg)``,\n" + " or a more complex nested one might look like ``(('some_condition',\n" + " cond_arg), 'or', ('another_condition', cond2_arg))``.\n" "\n" - "Conditions are provided as tuples which can be combined to form boolean\n" - "logic. A single condition might look like ('condition_name', cond_arg),\n" - "or a more complex nested one might look like (('some_condition',\n" - "cond_arg), 'or', ('another_condition', cond2_arg)).\n" - "\n" - "'and', 'or', and 'xor' are available to chain together 2 conditions, as\n" - " seen above.\n" + " ``'and'``, ``'or'``, and ``'xor'`` are available to chain together 2 conditions, as\n" + " seen above.\n" "\n" "Available Conditions:\n" + " ``('they_have_material', material)`` - does the part we\'re hitting have a\n" + " given ba.Material?\n" "\n" - "('they_have_material', material) - does the part we\'re hitting have a\n" - " given ba.Material?\n" + " ``('they_dont_have_material', material)`` - does the part we\'re hitting\n" + " not have a given ba.Material?\n" "\n" - "('they_dont_have_material', material) - does the part we\'re hitting\n" - " not have a given ba.Material?\n" + " ``('eval_colliding')`` - is ``'collide'`` true at this point in material\n" + " evaluation? (see the modify_part_collision action)\n" "\n" - "('eval_colliding') - is 'collide' true at this point in material\n" - " evaluation? (see the modify_part_collision action)\n" + " ``('eval_not_colliding')`` - is 'collide' false at this point in material\n" + " evaluation? (see the modify_part_collision action)\n" "\n" - "('eval_not_colliding') - is 'collide' false at this point in material\n" - " evaluation? (see the modify_part_collision action)\n" + " ``('we_are_younger_than', age)`` - is our part younger than ``'age'``\n" + " (in milliseconds)?\n" "\n" - "('we_are_younger_than', age) - is our part younger than 'age'\n" - " (in milliseconds)?\n" + " ``('we_are_older_than', age)`` - is our part older than ``'age'``\n" + " (in milliseconds)?\n" "\n" - "('we_are_older_than', age) - is our part older than 'age'\n" - " (in milliseconds)?\n" + " ``('they_are_younger_than', age)`` - is the part we're hitting younger than\n" + " ``'age'`` (in milliseconds)?\n" "\n" - "('they_are_younger_than', age) - is the part we're hitting younger than\n" - " 'age' (in milliseconds)?\n" + " ``('they_are_older_than', age)`` - is the part we're hitting older than\n" + " ``'age'`` (in milliseconds)?\n" "\n" - "('they_are_older_than', age) - is the part we're hitting older than\n" - " 'age' (in milliseconds)?\n" + " ``('they_are_same_node_as_us')`` - does the part we're hitting belong to\n" + " the same ba.Node as us?\n" "\n" - "('they_are_same_node_as_us') - does the part we're hitting belong to\n" - " the same ba.Node as us?\n" - "\n" - "('they_are_different_node_than_us') - does the part we're hitting\n" - " belong to a different ba.Node than us?\n" + " ``('they_are_different_node_than_us')`` - does the part we're hitting\n" + " belong to a different ba.Node than us?\n" "\n" "Actions:\n" - "\n" - "In a similar manner, actions are specified as tuples. Multiple actions\n" - "can be specified by providing a tuple of tuples.\n" + " In a similar manner, actions are specified as tuples. Multiple actions\n" + " can be specified by providing a tuple of tuples.\n" "\n" "Available Actions:\n" + " ``('call', when, callable)`` - calls the provided callable; ``'when'`` can be\n" + " either ``'at_connect'`` or ``'at_disconnect'``. ``'at_connect'`` means to fire\n" + " when the two parts first come in contact; ``'at_disconnect'`` means to\n" + " fire once they cease being in contact.\n" "\n" - "('call', when, callable) - calls the provided callable; 'when' can be\n" - " either 'at_connect' or 'at_disconnect'. 'at_connect' means to fire\n" - " when the two parts first come in contact; 'at_disconnect' means to\n" - " fire once they cease being in contact.\n" + " ``('message', who, when, message_obj)`` - sends a message object; ``'who'`` can\n" + " be either ``'our_node'`` or ``'their_node'``, ``'when'`` can be ``'at_connect'`` or\n" + " ``'at_disconnect'``, and message_obj is the message object to send.\n" + " This has the same effect as calling the node's ba.Node.handlemessage\n" + " method.\n" "\n" - "('message', who, when, message_obj) - sends a message object; 'who' can\n" - " be either 'our_node' or 'their_node', 'when' can be 'at_connect' or\n" - " 'at_disconnect', and message_obj is the message object to send.\n" - " This has the same effect as calling the node's handlemessage()\n" - " method.\n" + " ``('modify_part_collision', attr, value)`` - changes some characteristic\n" + " of the physical collision that will occur between our part and their\n" + " part. This change will remain in effect as long as the two parts\n" + " remain overlapping. This means if you have a part with a material\n" + " that turns ``'collide'`` off against parts younger than 100ms, and it\n" + " touches another part that is 50ms old, it will continue to not\n" + " collide with that part until they separate, even if the 100ms\n" + " threshold is passed. Options for attr/value are: ``'physical'`` (boolean\n" + " value; whether a *physical* response will occur at all), ``'friction'``\n" + " (float value; how friction-y the physical response will be),\n" + " ``'collide'`` (boolean value; whether *any* collision will occur at all,\n" + " including non-physical stuff like callbacks), ``'use_node_collide'``\n" + " (boolean value; whether to honor modify_node_collision overrides for\n" + " this collision), ``'stiffness'`` (float value, how springy the physical\n" + " response is), ``'damping'`` (float value, how damped the physical\n" + " response is), ``'bounce'`` (float value; how bouncy the physical response\n" + " is).\n" "\n" - "('modify_part_collision', attr, value) - changes some characteristic\n" - " of the physical collision that will occur between our part and their\n" - " part. This change will remain in effect as long as the two parts\n" - " remain overlapping. This means if you have a part with a material\n" - " that turns 'collide' off against parts younger than 100ms, and it\n" - " touches another part that is 50ms old, it will continue to not\n" - " collide with that part until they separate, even if the 100ms\n" - " threshold is passed. Options for attr/value are: 'physical' (boolean\n" - " value; whether a *physical* response will occur at all), 'friction'\n" - " (float value; how friction-y the physical response will be),\n" - " 'collide' (boolean value; whether *any* collision will occur at all,\n" - " including non-physical stuff like callbacks), 'use_node_collide'\n" - " (boolean value; whether to honor modify_node_collision overrides for\n" - " this collision), 'stiffness' (float value, how springy the physical\n" - " response is), 'damping' (float value, how damped the physical\n" - " response is), 'bounce' (float value; how bouncy the physical response\n" - " is).\n" + " ``('modify_node_collision', attr, value)`` - similar to\n" + " ``modify_part_collision``, but operates at a node-level.\n" + " collision attributes set here will remain in effect as long as\n" + " *anything* from our part's node and their part's node overlap.\n" + " A key use of this functionality is to prevent new nodes from\n" + " colliding with each other if they appear overlapped;\n" + " if ``modify_part_collision`` is used, only the individual parts that\n" + " were overlapping would avoid contact, but other parts could still\n" + " contact leaving the two nodes 'tangled up'. Using\n" + " ``modify_node_collision ensures`` that the nodes must completely\n" + " separate before they can start colliding. Currently the only attr\n" + " available here is ``'collide'`` (a boolean value).\n" "\n" - "('modify_node_collision', attr, value) - similar to\n" - " modify_part_collision, but operates at a node-level.\n" - " collision attributes set here will remain in effect as long as\n" - " *anything* from our part's node and their part's node overlap.\n" - " A key use of this functionality is to prevent new nodes from\n" - " colliding with each other if they appear overlapped;\n" - " if modify_part_collision is used, only the individual parts that\n" - " were overlapping would avoid contact, but other parts could still\n" - " contact leaving the two nodes 'tangled up'. Using\n" - " modify_node_collision ensures that the nodes must completely\n" - " separate before they can start colliding. Currently the only attr\n" - " available here is 'collide' (a boolean value).\n" + " ``('sound', sound, volume)`` - plays a ba.Sound when a collision occurs, at\n" + " a given volume, regardless of the collision speed/etc.\n" "\n" - "('sound', sound, volume) - plays a ba.Sound when a collision occurs, at\n" - " a given volume, regardless of the collision speed/etc.\n" + " ``('impact_sound', sound, targetImpulse, volume)`` - plays a sound when a\n" + " collision occurs, based on the speed of impact. Provide a ba.Sound, a\n" + " target-impulse, and a volume.\n" "\n" - "('impact_sound', sound, targetImpulse, volume) - plays a sound when a\n" - " collision occurs, based on the speed of impact. Provide a ba.Sound, a\n" - " target-impulse, and a volume.\n" + " ``('skid_sound', sound, targetImpulse, volume)`` - plays a sound during a\n" + " collision when parts are 'scraping' against each other. Provide a\n" + " ba.Sound, a target-impulse, and a volume.\n" "\n" - "('skid_sound', sound, targetImpulse, volume) - plays a sound during a\n" - " collision when parts are 'scraping' against each other. Provide a\n" - " ba.Sound, a target-impulse, and a volume.\n" + " ``('roll_sound', sound, targetImpulse, volume)`` - plays a sound during a\n" + " collision when parts are 'rolling' against each other. Provide a\n" + " ba.Sound, a target-impulse, and a volume.\n" "\n" - "('roll_sound', sound, targetImpulse, volume) - plays a sound during a\n" - " collision when parts are 'rolling' against each other. Provide a\n" - " ba.Sound, a target-impulse, and a volume.\n" + "Examples:\n" + " example 1: create a material that lets us ignore\n" + " collisions against any nodes we touch in the first\n" + " 100 ms of our existence; handy for preventing us from\n" + " exploding outward if we spawn on top of another object:\n" + " ```python\n" + " >>> m = ba.Material()\n" + " ... m.add_actions(\n" + " ... conditions=(('we_are_younger_than', 100),\n" + " ... 'or', ('they_are_younger_than', 100)),\n" + " ... actions=('modify_node_collision', 'collide', False))\n" + " ```\n" "\n" - "# example 1: create a material that lets us ignore\n" - "# collisions against any nodes we touch in the first\n" - "# 100 ms of our existence; handy for preventing us from\n" - "# exploding outward if we spawn on top of another object:\n" - "m = ba.Material()\n" - "m.add_actions(conditions=(('we_are_younger_than', 100),\n" - " 'or',('they_are_younger_than', 100)),\n" - " actions=('modify_node_collision', 'collide', False))\n" + " example 2: send a ba.DieMessage to anything we touch, but cause\n" + " no physical response. This should cause any ba.Actor to drop dead:\n" + " ```python\n" + " >>> m = ba.Material()\n" + " ... m.add_actions(\n" + " ... actions=(('modify_part_collision', 'physical', False),\n" + " ... ('message', 'their_node', 'at_connect',\n" + " ... ba.DieMessage())))\n" + " ```\n" "\n" - "# example 2: send a DieMessage to anything we touch, but cause\n" - "# no physical response. This should cause any ba.Actor to drop dead:\n" - "m = ba.Material()\n" - "m.add_actions(actions=(('modify_part_collision', 'physical', False),\n" - " ('message', 'their_node', 'at_connect',\n" - " ba.DieMessage())))\n" - "\n" - "# example 3: play some sounds when we're contacting the ground:\n" - "m = ba.Material()\n" - "m.add_actions(conditions=('they_have_material',\n" - " shared.footing_material),\n" - " actions=(('impact_sound', ba.getsound('metalHit'), 2, 5),\n" - " ('skid_sound', ba.getsound('metalSkid'), 2, 5)))\n" + " example 3: play some sounds when we're contacting the ground:\n" + " ```python\n" + " >>> m = ba.Material()\n" + " ... m.add_actions(\n" + " ... conditions=('they_have_material',\n" + " shared.footing_material),\n" + " ... actions=(('impact_sound', ba.getsound('metalHit'), 2, 5),\n" + " ... ('skid_sound', ba.getsound('metalSkid'), 2, 5)))\n" + " ```\n" "\n"}, {"__dir__", (PyCFunction)Dir, METH_NOARGS, "allows inclusion of our custom attrs in standard python dir()"}, diff --git a/src/ballistica/python/class/python_class_node.cc b/src/ballistica/python/class/python_class_node.cc index 2b0d74df..a1f69cbf 100644 --- a/src/ballistica/python/class/python_class_node.cc +++ b/src/ballistica/python/class/python_class_node.cc @@ -440,14 +440,17 @@ PyMethodDef PythonClassNode::tp_methods[] = { "Connect one of this node's attributes to an attribute on another node.\n" "This will immediately set the target attribute's value to that of the\n" "source attribute, and will continue to do so once per step as long as\n" - "the two nodes exist. The connection can be severed by setting the\n" + "the two nodes exist. The connection can be severed by setting the\n" "target attribute to any value or connecting another node attribute\n" "to it.\n" "\n" - "# Example: create a locator and attach a light to it:\n" - "light = ba.newnode('light')\n" - "loc = ba.newnode('locator', attrs={'position': (0,10,0)})\n" - "loc.connectattr('position', light, 'position')"}, + "Example:\n" + " Create a locator and attach a light to it:\n" + " ```python\n" + " >>> light = ba.newnode('light')\n" + " ... loc = ba.newnode('locator', attrs={'position': (0, 10, 0)})\n" + " ... loc.connectattr('position', light, 'position')\n" + " ```\n"}, {"__dir__", (PyCFunction)Dir, METH_NOARGS, "allows inclusion of our custom attrs in standard python dir()"}, {nullptr}}; diff --git a/src/ballistica/python/class/python_class_timer.cc b/src/ballistica/python/class/python_class_timer.cc index 81ea7537..61884dd8 100644 --- a/src/ballistica/python/class/python_class_timer.cc +++ b/src/ballistica/python/class/python_class_timer.cc @@ -45,16 +45,19 @@ void PythonClassTimer::SetupType(PyTypeObject* obj) { "timeformat: A ba.TimeFormat value determining how the passed time is\n" "interpreted.\n" "\n" - "# Example: use a Timer object to print repeatedly for a few seconds:\n" - "def say_it():\n" - " ba.screenmessage('BADGER!')\n" - "def stop_saying_it():\n" - " self.t = None\n" - " ba.screenmessage('MUSHROOM MUSHROOM!')\n" - "# Create our timer; it will run as long as we have the self.t ref.\n" - "self.t = ba.Timer(0.3, say_it, repeat=True)\n" - "# Now fire off a one-shot timer to kill it.\n" - "ba.timer(3.89, stop_saying_it)"; + "Example:\n" + " Use a Timer object to print repeatedly for a few seconds:\n" + " ```python\n" + " >>> def say_it():\n" + " ... ba.screenmessage('BADGER!')\n" + " ... def stop_saying_it():\n" + " ... self.t = None\n" + " ... ba.screenmessage('MUSHROOM MUSHROOM!')\n" + " ... # Create our timer; it will run as long as we have the self.t ref.\n" + " ... self.t = ba.Timer(0.3, say_it, repeat=True)\n" + " ... # Now fire off a one-shot timer to kill it.\n" + " ... ba.timer(3.89, stop_saying_it)\n" + " ```\n"; obj->tp_new = tp_new; obj->tp_dealloc = (destructor)tp_dealloc; } diff --git a/src/ballistica/python/methods/python_methods_app.cc b/src/ballistica/python/methods/python_methods_app.cc index a2ae06a0..b1f07bcb 100644 --- a/src/ballistica/python/methods/python_methods_app.cc +++ b/src/ballistica/python/methods/python_methods_app.cc @@ -1033,52 +1033,53 @@ auto PythonMethodsApp::GetMethods() -> std::vector { "This timer cannot be canceled or modified once created. If you\n" " require the ability to do so, use the ba.Timer class instead.\n" "\n" - "time: length of time (in seconds by default) that the timer will " - "wait\n" - "before firing. Note that the actual delay experienced may vary\n " - "depending on the timetype. (see below)\n" + "Arguments:\n" + " time (float):\n" + " Length of time (in seconds by default) that the timer will wait\n" + " before firing. Note that the actual delay experienced may vary\n " + " depending on the timetype. (see below)\n" "\n" - "call: A callable Python object. Note that the timer will retain a\n" - "strong reference to the callable for as long as it exists, so you\n" - "may want to look into concepts such as ba.WeakCall if that is not\n" - "desired.\n" + " call (Callable[[], Any]):\n" + " A callable Python object. Note that the timer will retain a\n" + " strong reference to the callable for as long as it exists, so you\n" + " may want to look into concepts such as ba.WeakCall if that is not\n" + " desired.\n" "\n" - "repeat: if True, the timer will fire repeatedly, with each " - "successive\n" - "firing having the same delay as the first.\n" + " repeat (bool):\n" + " If True, the timer will fire repeatedly, with each successive\n" + " firing having the same delay as the first.\n" "\n" - "timetype can be either 'sim', 'base', or 'real'. It defaults to\n" - "'sim'. Types are explained below:\n" + "\n" + " timetype (ba.TimeType):\n" + " Can be either ``SIM``, ``BASE``, or ``REAL``. It defaults to\n" + " ``SIM``. \n" + "\n" + " timeformat (ba.TimeFormat):\n" + " Defaults to seconds but can also be milliseconds.\n" "\n" - "'sim' time maps to local simulation time in ba.Activity or " - "ba.Session\n" - "Contexts. This means that it may progress slower in slow-motion " - "play\n" + "- SIM time maps to local simulation time in ba.Activity or ba.Session\n" + "Contexts. This means that it may progress slower in slow-motion play\n" "modes, stop when the game is paused, etc. This time type is not\n" "available in UI contexts.\n" - "\n" - "'base' time is also linked to gameplay in ba.Activity or ba.Session\n" + "- BASE time is also linked to gameplay in ba.Activity or ba.Session\n" "Contexts, but it progresses at a constant rate regardless of\n " "slow-motion states or pausing. It can, however, slow down or stop\n" "in certain cases such as network outages or game slowdowns due to\n" "cpu load. Like 'sim' time, this is unavailable in UI contexts.\n" - "\n" - "'real' time always maps to actual clock time with a bit of " - "filtering\n" - "added, regardless of Context. (the filtering prevents it from " - "going\n" + "- REAL time always maps to actual clock time with a bit of filtering\n" + "added, regardless of Context. (The filtering prevents it from going\n" "backwards or jumping forward by large amounts due to the app being\n" "backgrounded, system time changing, etc.)\n" "Real time timers are currently only available in the UI context.\n" "\n" - "the 'timeformat' arg defaults to seconds but can also be " - "milliseconds.\n" - "\n" - "# timer example: print some stuff through time:\n" - "ba.screenmessage('hello from now!')\n" - "ba.timer(1.0, ba.Call(ba.screenmessage, 'hello from the future!'))\n" - "ba.timer(2.0, ba.Call(ba.screenmessage, 'hello from the future " - "2!'))\n"}, + "Examples:\n" + " Print some stuff through time:\n" + " ```python\n" + " >>> ba.screenmessage('hello from now!')\n" + " >>> ba.timer(1.0, ba.Call(ba.screenmessage, 'hello from the future!'))\n" + " >>> ba.timer(2.0, ba.Call(ba.screenmessage,\n" + " ... 'hello from the future 2!'))\n" + " ```\n"}, {"time", (PyCFunction)PyTime, METH_VARARGS | METH_KEYWORDS, "time(timetype: ba.TimeType = TimeType.SIM,\n" diff --git a/src/ballistica/python/methods/python_methods_system.cc b/src/ballistica/python/methods/python_methods_system.cc index 0a64f147..46d2e627 100644 --- a/src/ballistica/python/methods/python_methods_system.cc +++ b/src/ballistica/python/methods/python_methods_system.cc @@ -846,10 +846,13 @@ auto PythonMethodsSystem::GetMethods() -> std::vector { "The call is made from. Returns True if this location has not been\n" "registered already, and False if it has.\n" "\n" - "# Example: this print will only fire for the first loop iteration:\n" - "for i in range(10):\n" - " if ba.do_once():\n" - " print('Hello once from loop!')"}, + "Example:\n" + " This print will only fire for the first loop iteration:\n" + " ```python\n" + " >>> for i in range(10):\n" + " ... if ba.do_once():\n" + " ... print('Hello once from loop!')\n" + " ```\n"}, {"_app", (PyCFunction)PyApp, METH_VARARGS | METH_KEYWORDS, "_app() -> ba.App\n" diff --git a/tools/batools/docs.py b/tools/batools/docs.py index 08dcfa2d..c4d8e46f 100755 --- a/tools/batools/docs.py +++ b/tools/batools/docs.py @@ -89,7 +89,7 @@ def generate(projroot: str) -> None: pdoc.render.configure(docformat='google', search=True, show_source=True) - pdoc.pdoc('ba', 'bastd', output_directory=outdirname) + pdoc.pdoc('ba', output_directory=outdirname) except Exception as exc: import traceback traceback.print_exc()