Fixed a bug with player positions being incorrect

This commit is contained in:
Eric Froemling 2020-05-21 15:43:10 -07:00
parent 90b028da18
commit d6ccf2b12d
5 changed files with 73 additions and 41 deletions

View File

@ -367,13 +367,8 @@ class Map(Actor):
# Get positions for existing players. # Get positions for existing players.
player_pts = [] player_pts = []
for player in players: for player in players:
try: if player.is_alive():
if player and player.node: player_pts.append(player.position)
pnt = _ba.Vec3(player.node.position)
player_pts.append(pnt)
except Exception:
from ba import _error
_error.print_exception()
def _getpt() -> Sequence[float]: def _getpt() -> Sequence[float]:
point = self.ffa_spawn_points[self._next_ffa_start_index] point = self.ffa_spawn_points[self._next_ffa_start_index]

View File

@ -24,6 +24,8 @@ from __future__ import annotations
from typing import TYPE_CHECKING, TypeVar, Generic from typing import TYPE_CHECKING, TypeVar, Generic
import _ba
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import (Type, Optional, Sequence, Dict, Any, Union, Tuple, from typing import (Type, Optional, Sequence, Dict, Any, Union, Tuple,
Callable) Callable)
@ -66,7 +68,6 @@ class Player(Generic[TeamType]):
(internal) (internal)
""" """
from ba._nodeactor import NodeActor from ba._nodeactor import NodeActor
import _ba
# Sanity check; if a dataclass is created that inherits from us, # Sanity check; if a dataclass is created that inherits from us,
# it will define an equality operator by default which will break # it will define an equality operator by default which will break
@ -92,6 +93,8 @@ class Player(Generic[TeamType]):
self.gamedata = sessionplayer.gamedata self.gamedata = sessionplayer.gamedata
# Create our player node in the current activity. # Create our player node in the current activity.
# Note: do we want to save a few cycles here by managing our player
# node manually instead of wrapping it in a NodeActor?
node = _ba.newnode('player', attrs={'playerID': sessionplayer.id}) node = _ba.newnode('player', attrs={'playerID': sessionplayer.id})
self._nodeactor = NodeActor(node) self._nodeactor = NodeActor(node)
sessionplayer.set_node(node) sessionplayer.set_node(node)
@ -118,6 +121,15 @@ class Player(Generic[TeamType]):
raise _error.NodeNotFoundError raise _error.NodeNotFoundError
return self._nodeactor.node return self._nodeactor.node
@property
def position(self) -> ba.Vec3:
"""The position of the player, as defined by its current Actor.
This value should not be used when the player has no Actor, as
it is undefined in that case.
"""
return _ba.Vec3(self.node.position)
def exists(self) -> bool: def exists(self) -> bool:
"""Whether the underlying player still exists. """Whether the underlying player still exists.

View File

@ -87,14 +87,7 @@ class PlayerSpaz(Spaz, Generic[PlayerType]):
self.held_count = 0 self.held_count = 0
self.last_player_held_by: Optional[PlayerType] = None self.last_player_held_by: Optional[PlayerType] = None
self._player = player self._player = player
self.playertype = type(player) self._drive_player_position()
# Grab the node for this player and wire it to follow our spaz
# (so players' controllers know where to draw their guides, etc).
if player:
assert self.node
assert player.node
self.node.connectattr('torso_position', player.node, 'position')
@property @property
def player(self) -> PlayerType: def player(self) -> PlayerType:
@ -200,7 +193,7 @@ class PlayerSpaz(Spaz, Generic[PlayerType]):
if isinstance(msg, ba.PickedUpMessage): if isinstance(msg, ba.PickedUpMessage):
super().handlemessage(msg) # Augment standard behavior. super().handlemessage(msg) # Augment standard behavior.
self.held_count += 1 self.held_count += 1
picked_up_by = ba.playercast_o(self.playertype, picked_up_by = ba.playercast_o(type(self._player),
msg.node.source_player) msg.node.source_player)
if picked_up_by: if picked_up_by:
self.last_player_held_by = picked_up_by self.last_player_held_by = picked_up_by
@ -212,7 +205,7 @@ class PlayerSpaz(Spaz, Generic[PlayerType]):
# Let's count someone dropping us as an attack. # Let's count someone dropping us as an attack.
try: try:
picked_up_by_2 = ba.playercast_o(self.playertype, picked_up_by_2 = ba.playercast_o(type(self._player),
msg.node.source_player) msg.node.source_player)
except Exception: except Exception:
picked_up_by_2 = None picked_up_by_2 = None
@ -220,6 +213,14 @@ class PlayerSpaz(Spaz, Generic[PlayerType]):
self.last_player_attacked_by = picked_up_by_2 self.last_player_attacked_by = picked_up_by_2
self.last_attacked_time = ba.time() self.last_attacked_time = ba.time()
self.last_attacked_type = ('picked_up', 'default') self.last_attacked_type = ('picked_up', 'default')
elif isinstance(msg, ba.StandMessage):
super().handlemessage(msg) # Augment standard behavior.
# Our Spaz was just moved somewhere. Explicitly update
# our associated player's position in case it is being used
# for logic (otherwise it will be out of date until next step)
self._drive_player_position()
elif isinstance(msg, ba.DieMessage): elif isinstance(msg, ba.DieMessage):
# Report player deaths to the game. # Report player deaths to the game.
@ -271,7 +272,7 @@ class PlayerSpaz(Spaz, Generic[PlayerType]):
# Keep track of the player who last hit us for point rewarding. # Keep track of the player who last hit us for point rewarding.
elif isinstance(msg, ba.HitMessage): elif isinstance(msg, ba.HitMessage):
source_player = msg.get_source_player(self.playertype) source_player = msg.get_source_player(type(self._player))
if source_player: if source_player:
self.last_player_attacked_by = source_player self.last_player_attacked_by = source_player
self.last_attacked_time = ba.time() self.last_attacked_time = ba.time()
@ -282,3 +283,16 @@ class PlayerSpaz(Spaz, Generic[PlayerType]):
activity.handlemessage(PlayerSpazHurtMessage(self)) activity.handlemessage(PlayerSpazHurtMessage(self))
else: else:
super().handlemessage(msg) super().handlemessage(msg)
def _drive_player_position(self) -> None:
"""Drive our ba.Player's official position
If our position is changed explicitly, this should be called again
to instantly update the player position (otherwise it would be out
of date until the next sim step)
"""
player = self._player
if player:
assert self.node
assert player.node
self.node.connectattr('torso_position', player.node, 'position')

View File

@ -1070,9 +1070,9 @@ class Spaz(ba.Actor):
if self.hitpoints > 0: if self.hitpoints > 0:
# It's kinda crappy to die from impacts, so lets reduce # It's kinda crappy to die from impacts, so lets reduce
# impact damage by a reasonable amount if it'll keep us alive # impact damage by a reasonable amount *if* it'll keep us alive
if msg.hit_type == 'impact' and damage > self.hitpoints: if msg.hit_type == 'impact' and damage > self.hitpoints:
# drop damage to whatever puts us at 10 hit points, # Drop damage to whatever puts us at 10 hit points,
# or 200 less than it used to be whichever is greater # or 200 less than it used to be whichever is greater
# (so it *can* still kill us if its high enough) # (so it *can* still kill us if its high enough)
newdamage = max(damage - 200, self.hitpoints - 10) newdamage = max(damage - 200, self.hitpoints - 10)
@ -1081,27 +1081,28 @@ class Spaz(ba.Actor):
# If we're holding something, drop it. # If we're holding something, drop it.
if damage > 0.0 and self.node.hold_node: if damage > 0.0 and self.node.hold_node:
# self.node.hold_node = ba.Node(None)
self.node.hold_node = None self.node.hold_node = None
self.hitpoints -= damage self.hitpoints -= damage
self.node.hurt = 1.0 - float( self.node.hurt = 1.0 - float(
self.hitpoints) / self.hitpoints_max self.hitpoints) / self.hitpoints_max
# If we're cursed, *any* damage blows us up. # If we're cursed, *any* damage blows us up.
if self._cursed and damage > 0: if self._cursed and damage > 0:
ba.timer( ba.timer(
0.05, 0.05,
ba.WeakCall(self.curse_explode, ba.WeakCall(self.curse_explode,
msg.get_source_player(ba.Player))) msg.get_source_player(ba.Player)))
# if we're frozen, shatter.. otherwise die if we hit zero
# If we're frozen, shatter.. otherwise die if we hit zero
if self.frozen and (damage > 200 or self.hitpoints <= 0): if self.frozen and (damage > 200 or self.hitpoints <= 0):
self.shatter() self.shatter()
elif self.hitpoints <= 0: elif self.hitpoints <= 0:
self.node.handlemessage( self.node.handlemessage(
ba.DieMessage(how=ba.DeathType.IMPACT)) ba.DieMessage(how=ba.DeathType.IMPACT))
# if we're dead, take a look at the smoothed damage val # If we're dead, take a look at the smoothed damage value
# (which gives us a smoothed average of recent damage) and shatter # (which gives us a smoothed average of recent damage) and shatter
# us if its grown high enough # us if its grown high enough.
if self.hitpoints <= 0: if self.hitpoints <= 0:
damage_avg = self.node.damage_smoothed * damage_scale damage_avg = self.node.damage_smoothed * damage_scale
if damage_avg > 1000: if damage_avg > 1000:
@ -1144,23 +1145,23 @@ class Spaz(ba.Actor):
return None return None
node = ba.get_collision_info('opposing_node') node = ba.get_collision_info('opposing_node')
# only allow one hit per node per punch # Only allow one hit per node per punch.
if node and (node not in self._punched_nodes): if node and (node not in self._punched_nodes):
punch_momentum_angular = (self.node.punch_momentum_angular * punch_momentum_angular = (self.node.punch_momentum_angular *
self._punch_power_scale) self._punch_power_scale)
punch_power = self.node.punch_power * self._punch_power_scale punch_power = self.node.punch_power * self._punch_power_scale
# ok here's the deal: we pass along our base velocity for use # Ok here's the deal: we pass along our base velocity for use
# in the impulse damage calculations since that is a more # in the impulse damage calculations since that is a more
# predictable value than our fist velocity, which is rather # predictable value than our fist velocity, which is rather
# erratic. ...however we want to actually apply force in the # erratic. However, we want to actually apply force in the
# direction our fist is moving so it looks better.. so we still # direction our fist is moving so it looks better. So we still
# pass that along as a direction ..perhaps a time-averaged # pass that along as a direction. Perhaps a time-averaged
# fist-velocity would work too?.. should try that. # fist-velocity would work too?.. perhaps should try that.
# if its something besides another spaz, just do a muffled # If its something besides another spaz, just do a muffled
# punch sound # punch sound.
if node.getnodetype() != 'spaz': if node.getnodetype() != 'spaz':
sounds = get_factory().impact_sounds_medium sounds = get_factory().impact_sounds_medium
sound = sounds[random.randrange(len(sounds))] sound = sounds[random.randrange(len(sounds))]
@ -1226,7 +1227,7 @@ class Spaz(ba.Actor):
if held and held.getnodetype() == 'flag': if held and held.getnodetype() == 'flag':
return True return True
# hold_body needs to be set before hold_node. # Note: hold_body needs to be set before hold_node.
self.node.hold_body = opposing_body self.node.hold_body = opposing_body
self.node.hold_node = opposing_node self.node.hold_node = opposing_node
elif isinstance(msg, ba.CelebrateMessage): elif isinstance(msg, ba.CelebrateMessage):
@ -1280,7 +1281,8 @@ class Spaz(ba.Actor):
def _pick_up(self, node: ba.Node) -> None: def _pick_up(self, node: ba.Node) -> None:
if self.node: if self.node:
self.node.hold_body = 0 # needs to be set before hold_node # Note: hold_body needs to be set before hold_node.
self.node.hold_body = 0
self.node.hold_node = node self.node.hold_node = node
def set_land_mine_count(self, count: int) -> None: def set_land_mine_count(self, count: int) -> None:
@ -1317,7 +1319,7 @@ class Spaz(ba.Actor):
self.shattered = True self.shattered = True
assert self.node assert self.node
if self.frozen: if self.frozen:
# momentary flash of light # Momentary flash of light.
light = ba.newnode('light', light = ba.newnode('light',
attrs={ attrs={
'position': self.node.position, 'position': self.node.position,
@ -1333,7 +1335,8 @@ class Spaz(ba.Actor):
0.3: 0 0.3: 0
}) })
ba.timer(0.3, light.delete) ba.timer(0.3, light.delete)
# emit ice chunks..
# Emit ice chunks.
ba.emitfx(position=self.node.position, ba.emitfx(position=self.node.position,
velocity=self.node.velocity, velocity=self.node.velocity,
count=int(random.random() * 10.0 + 10.0), count=int(random.random() * 10.0 + 10.0),
@ -1399,8 +1402,8 @@ class Spaz(ba.Actor):
def set_bomb_count(self, count: int) -> None: def set_bomb_count(self, count: int) -> None:
"""Sets the number of bombs this Spaz has.""" """Sets the number of bombs this Spaz has."""
# we cant just set bomb_count cuz some bombs may be laid currently # We can't just set bomb_count because some bombs may be laid currently
# so we have to do a relative diff based on max # so we have to do a relative diff based on max.
diff = count - self._max_bomb_count diff = count - self._max_bomb_count
self._max_bomb_count += diff self._max_bomb_count += diff
self.bomb_count += diff self.bomb_count += diff
@ -1413,7 +1416,7 @@ class Spaz(ba.Actor):
self.node.billboard_cross_out = True self.node.billboard_cross_out = True
def _gloves_wear_off(self) -> None: def _gloves_wear_off(self) -> None:
if self._demo_mode: # preserve old behavior if self._demo_mode: # Preserve old behavior.
self._punch_power_scale = 1.2 self._punch_power_scale = 1.2
self._punch_cooldown = BASE_PUNCH_COOLDOWN self._punch_cooldown = BASE_PUNCH_COOLDOWN
else: else:

View File

@ -3730,7 +3730,7 @@ even if myactor is set to None.</p>
</p> </p>
<h3>Attributes:</h3> <h3>Attributes:</h3>
<h5><a href="#attr_ba_Player__node">node</a>, <a href="#attr_ba_Player__sessionplayer">sessionplayer</a></h5> <h5><a href="#attr_ba_Player__node">node</a>, <a href="#attr_ba_Player__position">position</a>, <a href="#attr_ba_Player__sessionplayer">sessionplayer</a></h5>
<dl> <dl>
<dt><h4><a name="attr_ba_Player__node">node</a></h4></dt><dd> <dt><h4><a name="attr_ba_Player__node">node</a></h4></dt><dd>
<p><span><a href="#class_ba_Node">ba.Node</a></span></p> <p><span><a href="#class_ba_Node">ba.Node</a></span></p>
@ -3738,6 +3738,14 @@ even if myactor is set to None.</p>
<p> This node can be used to get a generic player position/etc.</p> <p> This node can be used to get a generic player position/etc.</p>
</dd>
<dt><h4><a name="attr_ba_Player__position">position</a></h4></dt><dd>
<p><span><a href="#class_ba_Vec3">ba.Vec3</a></span></p>
<p>The position of the player, as defined by its current Actor.</p>
<p> This value should not be used when the player has no Actor, as
it is undefined in that case.</p>
</dd> </dd>
<dt><h4><a name="attr_ba_Player__sessionplayer">sessionplayer</a></h4></dt><dd> <dt><h4><a name="attr_ba_Player__sessionplayer">sessionplayer</a></h4></dt><dd>
<p><span><a href="#class_ba_SessionPlayer">ba.SessionPlayer</a></span></p> <p><span><a href="#class_ba_SessionPlayer">ba.SessionPlayer</a></span></p>