Simplified handlemessage sanity checks

This commit is contained in:
Eric Froemling 2020-05-29 15:51:36 -07:00
parent 89d50df4aa
commit 6d861f4088
16 changed files with 34 additions and 61 deletions

View File

@ -26,7 +26,7 @@ import weakref
from typing import TYPE_CHECKING, TypeVar, overload from typing import TYPE_CHECKING, TypeVar, overload
from ba._messages import DieMessage, DeathType, OutOfBoundsMessage, UNHANDLED from ba._messages import DieMessage, DeathType, OutOfBoundsMessage, UNHANDLED
from ba._error import print_error, print_exception, ActivityNotFoundError from ba._error import print_exception, ActivityNotFoundError
import _ba import _ba
if TYPE_CHECKING: if TYPE_CHECKING:
@ -106,8 +106,7 @@ class Actor:
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
"""General message handling; can be passed any message object.""" """General message handling; can be passed any message object."""
if __debug__: assert not self.expired
self._handlemessage_sanity_check()
# By default, actors going out-of-bounds simply kill themselves. # By default, actors going out-of-bounds simply kill themselves.
if isinstance(msg, OutOfBoundsMessage): if isinstance(msg, OutOfBoundsMessage):
@ -135,9 +134,9 @@ class Actor:
def on_expire(self) -> None: def on_expire(self) -> None:
"""Called for remaining ba.Actors when their ba.Activity shuts down. """Called for remaining ba.Actors when their ba.Activity shuts down.
Actors can use this opportunity to clear callbacks Actors can use this opportunity to clear callbacks or other
or other references which have the potential of keeping the references which have the potential of keeping the ba.Activity
ba.Activity alive inadvertently (Activities can not exit cleanly while alive inadvertently (Activities can not exit cleanly while
any Python references to them remain.) any Python references to them remain.)
Once an actor is expired (see ba.Actor.is_expired()) it should no Once an actor is expired (see ba.Actor.is_expired()) it should no
@ -189,22 +188,6 @@ class Actor:
""" """
return True return True
def _handlemessage_sanity_check(self) -> None:
"""Make sure things are kosher in handlemessage().
Place this in an 'if __debug__:' clause at the top of handlemessage()
overrides. This will will complain if anything is sending the Actor
messages after the activity has ended, which should be explicitly
avoided.
"""
if not __debug__:
print_error('This should only be called in __debug__ mode.',
once=True)
if not getattr(self, '_root_actor_init_called', False):
print_error('Root Actor __init__() not called.')
if self.expired:
print_error(f'handlemessage() called on expired actor: {self}')
@property @property
def activity(self) -> ba.Activity: def activity(self) -> ba.Activity:
"""The Activity this Actor was created in. """The Activity this Actor was created in.

View File

@ -150,8 +150,7 @@ class Background(ba.Actor):
ba.timer(self.fade_time + 0.1, self.node.delete) ba.timer(self.fade_time + 0.1, self.node.delete)
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if __debug__: assert not self.expired
self._handlemessage_sanity_check()
if isinstance(msg, ba.DieMessage): if isinstance(msg, ba.DieMessage):
self._die(msg.immediate) self._die(msg.immediate)
else: else:

View File

@ -626,8 +626,7 @@ class Blast(ba.Actor):
ba.timer(0.4, _extra_debris_sound) ba.timer(0.4, _extra_debris_sound)
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if __debug__: assert not self.expired
self._handlemessage_sanity_check()
if isinstance(msg, ba.DieMessage): if isinstance(msg, ba.DieMessage):
if self.node: if self.node:

View File

@ -468,8 +468,7 @@ class ControlsGuide(ba.Actor):
return not self._dead return not self._dead
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if __debug__: assert not self.expired
self._handlemessage_sanity_check()
if isinstance(msg, ba.DieMessage): if isinstance(msg, ba.DieMessage):
if msg.immediate: if msg.immediate:
self._die() self._die()

View File

@ -343,8 +343,7 @@ class Flag(ba.Actor):
1.0, ba.WeakCall(self._hide_score_text)) 1.0, ba.WeakCall(self._hide_score_text))
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if __debug__: assert not self.expired
self._handlemessage_sanity_check()
if isinstance(msg, ba.DieMessage): if isinstance(msg, ba.DieMessage):
if self.node: if self.node:
self.node.delete() self.node.delete()

View File

@ -181,8 +181,7 @@ class Image(ba.Actor):
ba.WeakCall(self.handlemessage, ba.DieMessage())) ba.WeakCall(self.handlemessage, ba.DieMessage()))
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if __debug__: assert not self.expired
self._handlemessage_sanity_check()
if isinstance(msg, ba.DieMessage): if isinstance(msg, ba.DieMessage):
if self.node: if self.node:
self.node.delete() self.node.delete()

View File

@ -90,6 +90,8 @@ class PlayerSpaz(Spaz):
self._player = player self._player = player
self._drive_player_position() self._drive_player_position()
# Overloads to tell the type system our return type based on doraise val.
@overload @overload
def getplayer(self, def getplayer(self,
playertype: Type[PlayerType], playertype: Type[PlayerType],
@ -144,9 +146,9 @@ class PlayerSpaz(Spaz):
player.assign_input_call('upDown', self.on_move_up_down) player.assign_input_call('upDown', self.on_move_up_down)
player.assign_input_call('leftRight', self.on_move_left_right) player.assign_input_call('leftRight', self.on_move_left_right)
player.assign_input_call('holdPositionPress', player.assign_input_call('holdPositionPress',
self._on_hold_position_press) self.on_hold_position_press)
player.assign_input_call('holdPositionRelease', player.assign_input_call('holdPositionRelease',
self._on_hold_position_release) self.on_hold_position_release)
if enable_jump: if enable_jump:
player.assign_input_call('jumpPress', self.on_jump_press) player.assign_input_call('jumpPress', self.on_jump_press)
player.assign_input_call('jumpRelease', self.on_jump_release) player.assign_input_call('jumpRelease', self.on_jump_release)
@ -179,7 +181,7 @@ class PlayerSpaz(Spaz):
# Send releases for anything in case its held. # Send releases for anything in case its held.
self.on_move_up_down(0) self.on_move_up_down(0)
self.on_move_left_right(0) self.on_move_left_right(0)
self._on_hold_position_release() self.on_hold_position_release()
self.on_jump_release() self.on_jump_release()
self.on_pickup_release() self.on_pickup_release()
self.on_punch_release() self.on_punch_release()
@ -195,8 +197,7 @@ class PlayerSpaz(Spaz):
# pylint: disable=too-many-branches # pylint: disable=too-many-branches
# pylint: disable=too-many-statements # pylint: disable=too-many-statements
# pylint: disable=too-many-nested-blocks # pylint: disable=too-many-nested-blocks
if __debug__: assert not self.expired
self._handlemessage_sanity_check()
# Keep track of if we're being held and by who most recently. # Keep track of if we're being held and by who most recently.
if isinstance(msg, ba.PickedUpMessage): if isinstance(msg, ba.PickedUpMessage):
@ -292,7 +293,8 @@ class PlayerSpaz(Spaz):
if activity is not None and self._player.exists(): if activity is not None and self._player.exists():
activity.handlemessage(PlayerSpazHurtMessage(self)) activity.handlemessage(PlayerSpazHurtMessage(self))
else: else:
super().handlemessage(msg) return super().handlemessage(msg)
return None
def _drive_player_position(self) -> None: def _drive_player_position(self) -> None:
"""Drive our ba.Player's official position """Drive our ba.Player's official position

View File

@ -122,8 +122,7 @@ class PopupText(ba.Actor):
lifespan, ba.WeakCall(self.handlemessage, ba.DieMessage())) lifespan, ba.WeakCall(self.handlemessage, ba.DieMessage()))
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if __debug__: assert not self.expired
self._handlemessage_sanity_check()
if isinstance(msg, ba.DieMessage): if isinstance(msg, ba.DieMessage):
if self.node: if self.node:
self.node.delete() self.node.delete()

View File

@ -293,9 +293,7 @@ class PowerupBox(ba.Actor):
self.node.flashing = True self.node.flashing = True
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
# pylint: disable=too-many-branches assert not self.expired
if __debug__:
self._handlemessage_sanity_check()
if isinstance(msg, ba.PowerupAcceptMessage): if isinstance(msg, ba.PowerupAcceptMessage):
factory = PowerupBoxFactory.get() factory = PowerupBoxFactory.get()
@ -330,4 +328,5 @@ class PowerupBox(ba.Actor):
if msg.hit_type != 'punch': if msg.hit_type != 'punch':
self.handlemessage(ba.DieMessage()) self.handlemessage(ba.DieMessage())
else: else:
super().handlemessage(msg) return super().handlemessage(msg)
return None

View File

@ -428,7 +428,7 @@ class Spaz(ba.Actor):
return return
self.node.pickup_pressed = False self.node.pickup_pressed = False
def _on_hold_position_press(self) -> None: def on_hold_position_press(self) -> None:
""" """
Called to 'press hold-position' on this spaz; Called to 'press hold-position' on this spaz;
used for player or AI connections. used for player or AI connections.
@ -438,7 +438,7 @@ class Spaz(ba.Actor):
self.node.hold_position_pressed = True self.node.hold_position_pressed = True
self._turbo_filter_add_press('holdposition') self._turbo_filter_add_press('holdposition')
def _on_hold_position_release(self) -> None: def on_hold_position_release(self) -> None:
""" """
Called to 'release hold-position' on this spaz; Called to 'release hold-position' on this spaz;
used for player or AI connections. used for player or AI connections.
@ -695,8 +695,7 @@ class Spaz(ba.Actor):
# pylint: disable=too-many-return-statements # pylint: disable=too-many-return-statements
# pylint: disable=too-many-statements # pylint: disable=too-many-statements
# pylint: disable=too-many-branches # pylint: disable=too-many-branches
if __debug__: assert not self.expired
self._handlemessage_sanity_check()
if isinstance(msg, ba.PickedUpMessage): if isinstance(msg, ba.PickedUpMessage):
if self.node: if self.node:

View File

@ -510,8 +510,7 @@ class SpazBot(Spaz):
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
# pylint: disable=too-many-branches # pylint: disable=too-many-branches
if __debug__: assert not self.expired
self._handlemessage_sanity_check()
# Keep track of if we're being held and by who most recently. # Keep track of if we're being held and by who most recently.
if isinstance(msg, ba.PickedUpMessage): if isinstance(msg, ba.PickedUpMessage):

View File

@ -229,8 +229,7 @@ class Text(ba.Actor):
ba.WeakCall(self.handlemessage, ba.DieMessage())) ba.WeakCall(self.handlemessage, ba.DieMessage()))
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if __debug__: assert not self.expired
self._handlemessage_sanity_check()
if isinstance(msg, ba.DieMessage): if isinstance(msg, ba.DieMessage):
if self.node: if self.node:
self.node.delete() self.node.delete()

View File

@ -103,8 +103,7 @@ class TipsText(ba.Actor):
self.node.text = next_tip self.node.text = next_tip
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if __debug__: assert not self.expired
self._handlemessage_sanity_check()
if isinstance(msg, ba.DieMessage): if isinstance(msg, ba.DieMessage):
if self.node: if self.node:
self.node.delete() self.node.delete()

View File

@ -171,8 +171,7 @@ class ZoomText(ba.Actor):
ba.DieMessage())) ba.DieMessage()))
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if __debug__: assert not self.expired
self._handlemessage_sanity_check()
if isinstance(msg, ba.DieMessage): if isinstance(msg, ba.DieMessage):
if not self._dying and self.node: if not self._dying and self.node:
self._dying = True self._dying = True

View File

@ -1,5 +1,5 @@
<!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND --> <!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND -->
<h4><em>last updated on 2020-05-29 for Ballistica version 1.5.0 build 20033</em></h4> <h4><em>last updated on 2020-05-29 for Ballistica version 1.5.0 build 20034</em></h4>
<p>This page documents the Python classes and functions in the 'ba' module, <p>This page documents the Python classes and functions in the 'ba' module,
which are the ones most relevant to modding in Ballistica. If you come across something you feel should be included here or could be better explained, please <a href="mailto:support@froemling.net">let me know</a>. Happy modding!</p> which are the ones most relevant to modding in Ballistica. If you come across something you feel should be included here or could be better explained, please <a href="mailto:support@froemling.net">let me know</a>. Happy modding!</p>
<hr> <hr>
@ -741,9 +741,9 @@ they are Alive or not.</p>
<p>Called for remaining <a href="#class_ba_Actor">ba.Actors</a> when their <a href="#class_ba_Activity">ba.Activity</a> shuts down.</p> <p>Called for remaining <a href="#class_ba_Actor">ba.Actors</a> when their <a href="#class_ba_Activity">ba.Activity</a> shuts down.</p>
<p>Actors can use this opportunity to clear callbacks <p>Actors can use this opportunity to clear callbacks or other
or other references which have the potential of keeping the references which have the potential of keeping the <a href="#class_ba_Activity">ba.Activity</a>
<a href="#class_ba_Activity">ba.Activity</a> alive inadvertently (Activities can not exit cleanly while alive inadvertently (Activities can not exit cleanly while
any Python references to them remain.)</p> any Python references to them remain.)</p>
<p>Once an actor is expired (see <a href="#class_ba_Actor">ba.Actor</a>.is_expired()) it should no <p>Once an actor is expired (see <a href="#class_ba_Actor">ba.Actor</a>.is_expired()) it should no

View File

@ -105,7 +105,7 @@ class FileCache:
# if anything has been modified, don't write. # if anything has been modified, don't write.
for fname, mtime in self.mtimes.items(): for fname, mtime in self.mtimes.items():
if os.path.getmtime(fname) != mtime: if os.path.getmtime(fname) != mtime:
print(f'{Clr.YLW}File changed during run:' print(f'{Clr.MAG}File changed during run:'
f' "{fname}"; cache not updated.{Clr.RST}') f' "{fname}"; cache not updated.{Clr.RST}')
return return
out = json.dumps(self.entries) out = json.dumps(self.entries)