doomsday: Multicore pathfinding for Cogs.
This commit is contained in:
parent
1a80ead191
commit
8f29e76d12
3 changed files with 117 additions and 17 deletions
|
@ -1,7 +1,7 @@
|
|||
import random
|
||||
from pandac.PandaModules import *
|
||||
from direct.fsm.FSM import FSM
|
||||
from InvasionPathDataAI import pathfinder
|
||||
from PathPlannerPoolAI import pool
|
||||
|
||||
# Individual suit behaviors...
|
||||
|
||||
|
@ -45,7 +45,8 @@ class AttackBehavior(FSM):
|
|||
|
||||
# We can only update our walk-to if we're walking to begin with:
|
||||
if self.state == 'Walk':
|
||||
nav = self.brain.navigateTo(toonPos.getX(), toonPos.getY(), attackPrefer)
|
||||
nav = True
|
||||
self.brain.navigateTo(toonPos.getX(), toonPos.getY(), attackPrefer)
|
||||
else:
|
||||
nav = False
|
||||
|
||||
|
@ -58,6 +59,16 @@ class AttackBehavior(FSM):
|
|||
else:
|
||||
self.demand('Walk', toonPos.getX(), toonPos.getY())
|
||||
|
||||
def onNavFailed(self):
|
||||
if self.state == 'Walk':
|
||||
self.demand('Attack')
|
||||
else:
|
||||
# Can't get there, Captain!
|
||||
self.brain.master.toonUnreachable(self.toonId)
|
||||
self.brain.demand('Idle')
|
||||
return
|
||||
|
||||
|
||||
def enterAttack(self):
|
||||
# Attack the Toon.
|
||||
self.brain.suit.attack(self.toonId)
|
||||
|
@ -66,11 +77,7 @@ class AttackBehavior(FSM):
|
|||
# Walk state -- we try to get closer to the Toon. When we're
|
||||
# close enough, we switch to 'Attack'
|
||||
attackPrefer, attackMax = self.brain.getAttackRange()
|
||||
if not self.brain.navigateTo(x, y, attackMax):
|
||||
# Can't get there, Captain!
|
||||
self.brain.master.toonUnreachable(self.toonId)
|
||||
self.brain.demand('Idle')
|
||||
return
|
||||
self.brain.navigateTo(x, y, attackMax)
|
||||
|
||||
if self._walkTask:
|
||||
self._walkTask.remove()
|
||||
|
@ -157,12 +164,13 @@ class UnclumpBehavior(FSM):
|
|||
moveVector.normalize()
|
||||
x, y = ourPos + (moveVector * self.UNCLUMP_MOVE_DISTANCE)
|
||||
|
||||
if self.brain.navigateTo(x, y):
|
||||
# And we're walking!
|
||||
self.demand('Walking')
|
||||
else:
|
||||
# Hmm... Can't walk there. Let's just idle for a bit instead.
|
||||
self.demand('Wait')
|
||||
self.brain.navigateTo(x, y)
|
||||
# And we're walking!
|
||||
self.demand('Walking')
|
||||
|
||||
def onNavFailed(self):
|
||||
# Hmm... Can't walk there. Let's just idle for a bit instead.
|
||||
self.demand('Wait')
|
||||
|
||||
def enterWalking(self):
|
||||
pass # Do nothing, we just wait for onArrive and exit the behavior.
|
||||
|
@ -312,15 +320,18 @@ class InvasionSuitBrainAI(FSM):
|
|||
|
||||
# Navigation:
|
||||
def navigateTo(self, x, y, closeEnough=0):
|
||||
self.__waypoints = pathfinder.planPath(self.suit.getCurrentPos(),
|
||||
(x, y), closeEnough)
|
||||
pool.plan(self.__navCallback, self.suit.getCurrentPos(), (x, y),
|
||||
closeEnough)
|
||||
|
||||
def __navCallback(self, result):
|
||||
self.__waypoints = result
|
||||
if self.__waypoints:
|
||||
self.finalWaypoint = Point2(self.__waypoints[-1])
|
||||
self.__walkToNextWaypoint()
|
||||
return True
|
||||
else:
|
||||
self.finalWaypoint = None
|
||||
return False
|
||||
if hasattr(self.behavior, 'onNavFailed'):
|
||||
self.behavior.onNavFailed()
|
||||
|
||||
def suitFinishedWalking(self):
|
||||
# The suit finished walking. If there's another waypoint, go to it.
|
||||
|
|
78
toontown/election/PathPlannerPoolAI.py
Normal file
78
toontown/election/PathPlannerPoolAI.py
Normal file
|
@ -0,0 +1,78 @@
|
|||
import subprocess
|
||||
import os
|
||||
import atexit
|
||||
import thread
|
||||
from panda3d.core import *
|
||||
|
||||
class PlanD:
|
||||
def __init__(self, pool):
|
||||
self.pool = pool
|
||||
|
||||
# I couldn't resist the name. :)
|
||||
pathPath = os.path.join(os.path.dirname(__file__), 'pathd.py')
|
||||
|
||||
self.sp = subprocess.Popen(pathPath, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
||||
atexit.register(self.sp.kill)
|
||||
self.callback = None
|
||||
|
||||
self.pool.addWorker(self)
|
||||
|
||||
def plan(self, callback, navFrom, navTo, radius):
|
||||
self.callback = callback
|
||||
|
||||
params = (tuple(navFrom), tuple(navTo), radius)
|
||||
self.sp.stdin.write('%r\n' % (params,))
|
||||
self.sp.stdin.flush()
|
||||
|
||||
thread.start_new_thread(self.__read, ())
|
||||
|
||||
def __read(self):
|
||||
line = self.sp.stdout.readline()
|
||||
taskMgr.doMethodLater(0.1, self.__handle, 'inject-%d' % id(self),
|
||||
extraArgs=[line])
|
||||
|
||||
def __handle(self, line):
|
||||
x = eval(line)
|
||||
if self.callback:
|
||||
self.callback(x)
|
||||
self.callback = None
|
||||
|
||||
self.pool.addWorker(self)
|
||||
|
||||
class PlanJob:
|
||||
def __init__(self, callback, navFrom, navTo, radius):
|
||||
self.callback = callback
|
||||
self.navFrom = navFrom
|
||||
self.navTo = navTo
|
||||
self.radius = radius
|
||||
|
||||
def assign(self, pland):
|
||||
pland.plan(self.callback, self.navFrom, self.navTo, self.radius)
|
||||
|
||||
class PlannerPool:
|
||||
def __init__(self, workerCount):
|
||||
self.workers = []
|
||||
self.jobs = []
|
||||
|
||||
for x in xrange(workerCount):
|
||||
PlanD(self) # Registration is its responsibility
|
||||
|
||||
def addWorker(self, worker):
|
||||
self.workers.append(worker)
|
||||
self.__flushQueues()
|
||||
|
||||
def addJob(self, job):
|
||||
self.jobs.append(job)
|
||||
self.__flushQueues()
|
||||
|
||||
def __flushQueues(self):
|
||||
while self.workers and self.jobs:
|
||||
worker = self.workers.pop(0)
|
||||
job = self.jobs.pop(0)
|
||||
job.assign(worker)
|
||||
|
||||
def plan(self, callback, navFrom, navTo, radius):
|
||||
job = PlanJob(callback, navFrom, navTo, radius)
|
||||
self.addJob(job)
|
||||
|
||||
pool = PlannerPool(8)
|
11
toontown/election/pathd.py
Executable file
11
toontown/election/pathd.py
Executable file
|
@ -0,0 +1,11 @@
|
|||
#!/usr/bin/env python2
|
||||
|
||||
# This is a "pathfinding daemon" for parallelism in the invasion.
|
||||
import sys
|
||||
from InvasionPathDataAI import pathfinder
|
||||
|
||||
while True:
|
||||
navFrom, navTo, radius = input()
|
||||
path = pathfinder.planPath(navFrom, navTo, radius)
|
||||
print path
|
||||
sys.stdout.flush()
|
Loading…
Reference in a new issue