Commit ec35fa6c authored by talljosh's avatar talljosh
Browse files

Created AgentPlayerController class and refactored various message sending...

Created AgentPlayerController class and refactored various message sending calls to use the player controller instead. This is in preparation for making the agent send tick updates to the server in its own timing rather than following the server's timing.
parent b2360f545b4d
......@@ -67,7 +67,8 @@
<option value="trosnoth.model.universe.UIOptions.frontLine" />
<option value="trosnoth.model.universe.UIOptions.winning_player_ids" />
<option value="trosnoth.model.universe.UIOptions.winning_team_ids" />
<option value="dataclasses" />
<option value="dataclasses.*" />
<option value="trosnoth.utils.message.MessageBase.*" />
</list>
</option>
</inspection_tool>
......@@ -78,4 +79,4 @@
<option name="processComments" value="true" />
</inspection_tool>
</profile>
</component>
</component>
\ No newline at end of file
......@@ -22,9 +22,7 @@ from trosnoth.const import (
LEFT_STATE, RIGHT_STATE, JUMP_STATE, DOWN_STATE, DEFAULT_BOT_DIFFICULTY, BOT_DIFFICULTIES,
)
from trosnoth.messages import (
ShootMsg, TickMsg, ResyncPlayerMsg, WorldResetMsg,
CannotJoinMsg, UpdatePlayerStateMsg,
AimPlayerAtMsg, BuyUpgradeMsg, GrapplingHookMsg,
TickMsg, ResyncPlayerMsg, WorldResetMsg, CannotJoinMsg,
)
from trosnoth.model.agent import ConcreteAgent
from trosnoth.model.universe_base import NEUTRAL_TEAM_ID
......@@ -246,6 +244,10 @@ class Bot(MessageConsumer):
self.__class__.__name__,
repr(self.player.nick) if self.player else '-')
@property
def player_controller(self):
return self.agent.player_controller
@property
def difficulty(self):
return self.agent.bot_difficulty
......@@ -261,8 +263,7 @@ class Bot(MessageConsumer):
interfere with bot motion and pathfinding.
'''
for key, value in changes:
self.sendRequest(UpdatePlayerStateMsg(
value, stateKey=key, tickId=self.world.lastTickId))
self.player_controller.req_update_keystate(key, value)
def applyInputState(self, inputState):
directions = [
......@@ -273,14 +274,11 @@ class Bot(MessageConsumer):
]
for key, value in directions:
if self.player.getState(key) != value:
self.sendRequest(UpdatePlayerStateMsg(
value, stateKey=key, tickId=self.world.lastTickId))
self.player_controller.req_update_keystate(key, value)
self.sendRequest(AimPlayerAtMsg(
inputState.angle, inputState.thrust, tickId=self.world.lastTickId))
self.player_controller.req_aim_at(inputState.angle, inputState.thrust)
self._angleRequestedThisTick = (inputState.angle, inputState.thrust)
self.sendRequest(
GrapplingHookMsg(inputState.hook, tickId=self.world.lastTickId))
self.player_controller.req_grappling_hook(inputState.hook)
def releaseMovementKeys(self):
'''
......@@ -491,7 +489,7 @@ class Bot(MessageConsumer):
def _playerDied(self, killer, deathType):
self.currentRoute = None
self.sendRequest(AimPlayerAtMsg(0, 0, self.world.lastTickId))
self.player_controller.req_aim_at(0, 0)
self.currentOrder.playerDied()
def _playerRespawned(self):
......@@ -580,13 +578,11 @@ class Bot(MessageConsumer):
x2, y2 = pos
angle = atan2(x2 - x1, -(y2 - y1))
angle += error * (2 * random.random() - 1)
self.sendRequest(AimPlayerAtMsg(angle, thrust, self.world.lastTickId))
self.sendRequest(ShootMsg(self.world.lastTickId))
self.player_controller.req_shoot(angle=angle)
if self._angleRequestedThisTick is not None:
angle, thrust = self._angleRequestedThisTick
self.sendRequest(
AimPlayerAtMsg(angle, thrust, self.world.lastTickId))
self.player_controller.req_aim_at(angle, thrust)
def _check_upgrade_callback(self):
if self.player.coins < self.upgrade_callback_cost:
......@@ -599,7 +595,7 @@ class Bot(MessageConsumer):
def buy_upgrade(self, upgrade_class):
if upgrade_class.pre_buy_check(self.player):
self.sendRequest(BuyUpgradeMsg(upgrade_class.upgradeType, self.world.lastTickId))
self.player_controller.req_buy_upgrade(upgrade_class)
def setRoute(self, route):
self.currentRoute = route
......@@ -620,4 +616,3 @@ class Bot(MessageConsumer):
def hasUnfinishedRoute(self):
return self.currentRoute and not self.currentRoute.isFinished()
......@@ -7,7 +7,6 @@ import logging
from math import atan2
from trosnoth.const import ZONE_CAP_DISTANCE
from trosnoth.messages import AimPlayerAtMsg, RespawnRequestMsg, BuyUpgradeMsg
from trosnoth.model.upgrades import Bomber
from trosnoth.utils.math import distance, isNear
......@@ -74,8 +73,7 @@ class MoveGhostToPoint(BotOrder):
dy = self.pos[1] - playerPos[1]
theta = atan2(dx, -dy)
self.bot.sendRequest(
AimPlayerAtMsg(theta, 1.0, self.bot.world.lastTickId))
self.bot.player_controller.req_aim_at(theta, 1.0)
self.recheckIn = 20
def tick(self):
......@@ -225,8 +223,7 @@ class RespawnInZone(BotOrder):
if dist < 100:
if self.bot.player.ghostThrust:
self.bot.sendRequest(
AimPlayerAtMsg(0, 0, self.bot.world.lastTickId))
self.bot.player_controller.req_aim_at(0, 0)
elif dist < 300 or self.nextCheckTime < now:
playerPos = self.bot.player.pos
zonePos = self.zone.defn.pos
......@@ -235,8 +232,7 @@ class RespawnInZone(BotOrder):
theta = atan2(dx, -dy)
thrust = min(1, distance(playerPos, zonePos) / 300.)
self.bot.sendRequest(
AimPlayerAtMsg(theta, thrust, self.bot.world.lastTickId))
self.bot.player_controller.req_aim_at(theta, thrust)
now = self.bot.world.getMonotonicTime()
self.nextCheckTime = now + 0.5
......@@ -264,8 +260,7 @@ class RespawnInZone(BotOrder):
return
if playerZone.frozen:
return
self.bot.sendRequest(
RespawnRequestMsg(self.bot.world.lastTickId))
self.bot.player_controller.req_respawn()
def playerRespawned(self):
self.bot.orderFinished()
......
......@@ -10,7 +10,6 @@ from trosnoth.const import (
BOT_GOAL_HUNT_RABBITS, BOT_GOAL_SCORE_TROSBALL_POINT, BOT_GOAL_CAPTURE_MAP,
BOT_GOAL_KILL_THINGS,
)
from trosnoth.messages import BuyUpgradeMsg
from trosnoth.model import upgrades
from trosnoth.utils.math import distance
......
......@@ -20,7 +20,6 @@ from trosnoth.const import (
BOT_GOAL_CAPTURE_MAP, BOT_GOAL_SCORE_TROSBALL_POINT, BOT_GOAL_HUNT_RABBITS,
BOT_GOAL_KILL_THINGS,
)
from trosnoth.messages import AimPlayerAtMsg
from trosnoth.model import upgrades
from trosnoth.model.shot import PredictedGrenadeTrajectory, GRENADE_BLAST_RADIUS
from trosnoth.utils.math import distance
......@@ -117,7 +116,7 @@ class UpgradeSelector:
max_enemies_hit = 0
for i in range(5):
angle = random.random() * 2 * math.pi
self.bot.sendRequest(AimPlayerAtMsg(angle, 1, self.bot.world.lastTickId))
self.bot.req_aim_at(angle, 1)
final_pos = list(trajectory.predictedTrajectoryPoints())[-1]
enemies_hit = len([
p for p in self.bot.world.players
......@@ -128,7 +127,7 @@ class UpgradeSelector:
best_angle = angle
if best_angle is not None:
self.bot.sendRequest(AimPlayerAtMsg(best_angle, 1, self.bot.world.lastTickId))
self.bot.req_aim_at(best_angle, 1)
self.use_upgrade()
......
......@@ -9,7 +9,7 @@ from trosnoth.messages import (
JoinRequestMsg, TickMsg, ResyncPlayerMsg, UpdatePlayerStateMsg,
AimPlayerAtMsg, UpgradeApprovedMsg, PlayerHasUpgradeMsg, ShootMsg,
CheckSyncMsg, WorldResetMsg, BuyUpgradeMsg, GrapplingHookMsg,
PlayerAllDeadMsg,
PlayerAllDeadMsg, RespawnRequestMsg, EmoteRequestMsg, ThrowTrosballMsg,
)
from trosnoth.model.shot import LocalShot, LocalGrenade
from trosnoth.model.trosball import LocalTrosball
......@@ -34,6 +34,7 @@ class Agent(object):
self.game = game
self.user = None
self.player = None
self.player_controller = AgentPlayerController(self)
self.onPlayerSet = Event([])
self.stopped = False
self.botPlayerAllowed = False
......@@ -414,3 +415,44 @@ class LocalState(object):
if self.unverifiedItems:
return self.unverifiedItems.pop(0)
return None
class AgentPlayerController:
'''
This class represents a player that is owned by an agent. It can be
used to send player commands such as moving, shooting, buying items.
'''
def __init__(self, agent):
self.agent = agent
@property
def world(self):
return self.agent.world
def req_respawn(self):
self.agent.sendRequest(RespawnRequestMsg(tickId=self.world.lastTickId))
def req_shoot(self, angle=None):
if angle is not None:
self.req_aim_at(angle, 1.0)
self.agent.sendRequest(ShootMsg(tickId=self.world.lastTickId))
def req_emote(self, emote_id):
self.agent.sendRequest(EmoteRequestMsg(tickId=self.world.lastTickId, emoteId=emote_id))
def req_throw_trosball(self):
self.agent.sendRequest(ThrowTrosballMsg(tickId=self.world.lastTickId))
def req_buy_upgrade(self, upgrade_class):
self.agent.sendRequest(BuyUpgradeMsg(upgrade_class.upgradeType, self.world.lastTickId))
def req_update_keystate(self, key, value):
self.agent.sendRequest(
UpdatePlayerStateMsg(value, stateKey=key, tickId=self.world.lastTickId))
def req_grappling_hook(self, on):
self.agent.sendRequest(GrapplingHookMsg(on, tickId=self.world.lastTickId))
def req_aim_at(self, angle, thrust):
self.agent.sendRequest(AimPlayerAtMsg(angle, thrust, self.world.lastTickId))
......@@ -20,10 +20,7 @@ from trosnoth.gui.common import (
Location, FullScreenAttachedPoint, ScaledSize, Area, CanvasX, Screen,
RelativePoint, Region, Abs,
)
from trosnoth.messages import (
BuyUpgradeMsg, RespawnRequestMsg, EmoteRequestMsg,
PlayerIsReadyMsg, ThrowTrosballMsg,
)
from trosnoth.messages import PlayerIsReadyMsg
from trosnoth.model.player import Player
from trosnoth.model.shot import (
PredictedGrenadeTrajectory, PredictedGhostShotTrajectory,
......@@ -100,6 +97,10 @@ class DetailsInterface(framework.CompoundElement):
self.upgradeMap = dict((upgradeClass.action, upgradeClass) for
upgradeClass in allUpgrades)
@property
def player_controller(self):
return self.gameInterface.player_controller
def stop(self):
if self.achievementBox:
self.achievementBox.stop()
......@@ -198,13 +199,9 @@ class DetailsInterface(framework.CompoundElement):
def _requestUpgrade(self):
if self.player.hasTrosball():
self.sendRequest(ThrowTrosballMsg(self.getTickId()))
self.player_controller.req_throw_trosball()
elif self.currentUpgrade is not None and self.currentUpgrade.pre_buy_check(self.player):
self.sendRequest(BuyUpgradeMsg(
self.currentUpgrade.upgradeType, self.getTickId()))
def getTickId(self):
return self.world.lastTickId
self.player_controller.req_buy_upgrade(self.currentUpgrade)
def doAction(self, action):
'''
......@@ -249,8 +246,7 @@ class DetailsInterface(framework.CompoundElement):
paused = self.world.uiOptions.showPauseMessage
if action == ACTION_RESPAWN:
if not paused:
self.sendRequest(
RespawnRequestMsg(tickId=self.getTickId()))
self.player_controller.req_respawn()
elif action == ACTION_READY:
if self.player.readyToStart:
self._castGameVote(PlayerIsReadyMsg(self.player.id, False))
......@@ -268,10 +264,7 @@ class DetailsInterface(framework.CompoundElement):
if not paused:
self._requestUpgrade()
elif action == ACTION_EMOTE:
self.sendRequest(
EmoteRequestMsg(
tickId=self.getTickId(),
emoteId=random.randrange(MAX_EMOTE + 1)))
self.player_controller.req_emote(random.randrange(MAX_EMOTE + 1))
elif action == ACTION_RADIAL_UPGRADE_MENU:
self.radialUpgradeMenu.toggle()
elif action not in (
......@@ -528,6 +521,8 @@ class TrajectoryOverlay(framework.Element):
lastPoint = point
# Ignore 'colour might be referenced before assignment' PyCharm error
# noinspection PyUnboundLocalVariable
pygame.draw.circle(surface, colour, adjustedPoint, 2)
radius = int(trajectory.explosionRadius() * MAP_TO_SCREEN_SCALE)
......
......@@ -11,12 +11,9 @@ from trosnoth.const import (
)
from trosnoth.gui.framework import framework
from trosnoth.gui.keyboard import mouseButton
from trosnoth.messages import (
UpdatePlayerStateMsg, AimPlayerAtMsg, ShootMsg, GrapplingHookMsg,
)
from trosnoth.model.shot import PredictedRicochetTrajectory
from trosnoth.utils import globaldebug
from trosnoth.utils.math import distance, isNear
from trosnoth.utils.math import distance
log = logging.getLogger(__name__)
......@@ -85,6 +82,10 @@ class PlayerInterface(framework.Element):
# Make sure the viewer is focusing on this player.
self.gameInterface.gameViewer.setTarget(self.playerSprite)
@property
def player_controller(self):
return self.gameInterface.player_controller
def keyMappingUpdated(self):
self.keyMapping = self.gameInterface.keyMapping
self._stateKeys = {
......@@ -93,9 +94,6 @@ class PlayerInterface(framework.Element):
}
self._hookKey = self.keyMapping.getkey(ACTION_HOOK)
def getTickId(self):
return self.world.lastTickId
def stop(self):
pass
......@@ -129,14 +127,11 @@ class PlayerInterface(framework.Element):
if key >= 0}
changes = self.player.buildStateChanges(desiredState)
for code, value in changes:
self.gameInterface.sendRequest(UpdatePlayerStateMsg(
value, stateKey=code, tickId=self.getTickId()))
log.critical('Sent missing player state update: %r / %r',
code, value)
self.player_controller.req_update_keystate(code, value)
log.critical('Sent missing player state update: %r / %r', code, value)
if self._hookKey >= 0 and not keys[self._hookKey] and \
self.player.getGrapplingHook().isActive():
self.gameInterface.sendRequest(
GrapplingHookMsg(False, self.getTickId()))
self.player_controller.req_grappling_hook(False)
def updateMouse(self):
if self.playerSprite is None:
......@@ -190,8 +185,7 @@ class PlayerInterface(framework.Element):
thrust = (dist - self.NO_GHOST_THRUST_MOUSE_RADIUS) / span
thrust **= 2
self.gameInterface.sendRequest(
AimPlayerAtMsg(theta, thrust, tickId=self.getTickId()))
self.player_controller.req_aim_at(theta, thrust)
def processEvent(self, event):
'''Event processing works in the following way:
......@@ -219,8 +213,7 @@ class PlayerInterface(framework.Element):
angle = di.trajectoryOverlay \
.getTrajectory().getAngle()
di.doAction(ACTION_RESPAWN)
self.gameInterface.sendRequest(AimPlayerAtMsg(
angle, 1.0, tickId=self.getTickId()))
self.player_controller.req_aim_at(angle, 1.0)
self._fireShot()
else:
di.doAction(ACTION_RESPAWN)
......@@ -253,8 +246,7 @@ class PlayerInterface(framework.Element):
return
if action == ACTION_HOOK:
self.gameInterface.sendRequest(
GrapplingHookMsg(keyDown, self.getTickId()))
self.player_controller.req_grappling_hook(keyDown)
return
if action == ACTION_SHOW_TRAJECTORY:
......@@ -269,13 +261,10 @@ class PlayerInterface(framework.Element):
if action not in self.state_vkeys:
return
self.gameInterface.sendRequest(UpdatePlayerStateMsg(
keyDown, stateKey=self.state_vkeys[action],
tickId=self.getTickId()))
return
self.player_controller.req_update_keystate(self.state_vkeys[action], keyDown)
def _fireShot(self):
'''Fires a shot in the direction the player's currently looking.'''
if self.world.uiOptions.showPauseMessage:
return
self.gameInterface.sendRequest(ShootMsg(self.getTickId()))
self.player_controller.req_shoot()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment