187 lines
7.8 KiB
Python
187 lines
7.8 KiB
Python
##########################################################################
|
|
# Module: DistributedLeaderBoardAI.py
|
|
# Purpose: -determines what to display on the client side leaderboard
|
|
# -handles subscriptions to lists
|
|
# -handles timer to revolve leader board
|
|
# -handles updating lists that that leaderboardmanagaer indicates have changed
|
|
# Date: 6/24/05
|
|
# Author: sabrina (sabrina@schellgames.com)
|
|
##########################################################################
|
|
|
|
from direct.distributed import DistributedObjectAI
|
|
from direct.directnotify import DirectNotifyGlobal
|
|
from toontown.racing.RaceGlobals import *
|
|
from toontown.toonbase.TTLocalizer import *
|
|
import pickle
|
|
|
|
class DistributedLeaderBoardAI(DistributedObjectAI.DistributedObjectAI):
|
|
"""
|
|
The leader board class handles the display of player rankings.
|
|
|
|
Leader Board class was created to showcase race records in Toontown Kart racing
|
|
|
|
|
|
Inside the Toontown race code, when a race is done someone has to check race scores
|
|
decide if any of the latest scores is a new record for any of the types of leader lists.
|
|
|
|
If the answer is yes, the pickled race list is updated and a message is sent which notifies any
|
|
distributed leader boards as to which leader list has been updated. The dict of leader lists
|
|
and the titles describing them is defined in TTLocalizer file.
|
|
|
|
The distributed leader board then flags that id as needing actual update from the pickled leader
|
|
list file. When the distributed leader board needs to display that list it loads up the
|
|
new list and sends an updated message with the new list via sendupdate to the local leaderboard.
|
|
|
|
This avoids a single leader board from loading from the pickle unnecessarily often as it waits
|
|
till the information is actually needed to update it. Could result in double access to pickle
|
|
files if more than one leader board is listening for it... perhaps when reading in an updated
|
|
pickle list could also sned message with new list so that other server side leader boards
|
|
can benefit from one leader board's work? not sure which would be more taxing.
|
|
|
|
"""
|
|
|
|
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedLeaderBoardAI')
|
|
|
|
def __init__(self, air, pName, zoneId, pSubscribeList=[], pos=(0, 0, 0), hpr=(0, 0, 0)):
|
|
"""
|
|
Setup the Leader Board.
|
|
"""
|
|
self.notify.debug("__init__: initialization of leaderboard AI: name=%s, Subscriptions=%s, pos=%s, hpr=%s"%(pName, pSubscribeList, pos, hpr))
|
|
DistributedObjectAI.DistributedObjectAI.__init__(self, air)
|
|
self.name = pName
|
|
|
|
#each subscription icludes: id : track title, period title, list of (time, name)
|
|
self.subscriptionDict = {}
|
|
#an ordered list to cycle through
|
|
self.subscriptionList = []
|
|
self.changedList = [] #list to store id's of updated lists
|
|
#subscribe to all passed ids
|
|
#an id consits of a tuple (TrackID, PeriodID)
|
|
for id in pSubscribeList:
|
|
self.subscribeTo(id)
|
|
|
|
self.posHpr = (pos[0], pos[1], pos[2], hpr[0], hpr[1], hpr[2])
|
|
self.zoneId = zoneId
|
|
|
|
self.curIndex = 0 #the index into the subscriptionsDict indicating which list we're on
|
|
self.start()
|
|
|
|
def getName(self):
|
|
return self.name
|
|
|
|
def getPosHpr(self):
|
|
"""
|
|
"""
|
|
return self.posHpr
|
|
|
|
def getDisplay(self):
|
|
'''
|
|
'''
|
|
return pickle.dumps(self.subscriptionDict[self.curIndex], 1)
|
|
|
|
|
|
def sendNewDisplay(self):
|
|
self.notify.debug("sendNewDisplay: sending updated lb info to client")
|
|
self.sendUpdate("setDisplay", [pickle.dumps(self.subscriptionDict[self.subscriptionList[self.curIndex]], 1)])
|
|
|
|
def start(self):
|
|
'''
|
|
Starts listen for message to cycle through the boards subscribed lists.
|
|
Could make the listened for keyword a parameter if leaderboards on a different swap cycle
|
|
|
|
params: pSeconds - how many seconds between cycling
|
|
'''
|
|
self.notify.debug("start: leaderboard cycling started on leaderboard %s"%(self.name))
|
|
self.accept("GS_LeaderBoardSwap" + str(self.zoneId), self.__switchDisplayData)
|
|
|
|
def stop(self):
|
|
self.notify.debug("stop: leaderboard cycling stopped on leaderboard %s"%(self.name))
|
|
self.ignore("GS_LeaderBoardSwap" + str(self.zoneId))
|
|
|
|
def unsubscribeTo(self, pID):
|
|
self.notify.debug("unsubscribeTo: removing subscription %s for LB %s"%(pID, self.name))
|
|
#if this subscription exists, remove it
|
|
self.subscriptionDict.pop(pID)
|
|
self.subscriptionList.remove(pID)
|
|
#self.ignore("UpdateRaceRecord_"+str(pID))
|
|
self.ignore("UpdateRaceRecord")
|
|
|
|
def subscribeTo(self, pID):
|
|
'''
|
|
Adds this score ID to the list of ones this leader board cycles through and follows updates of
|
|
|
|
params: pID - the id to listen for
|
|
'''
|
|
self.notify.debug("subscribeTo: adding subscription %s for LB %s"%(pID, self.name))
|
|
#first check if we're already subscribed
|
|
if pID in self.subscriptionList:
|
|
return
|
|
|
|
|
|
i = str(len(self.subscriptionList))
|
|
self.subscriptionList.append(pID)
|
|
self.flagForUpdate(pID)
|
|
|
|
self.subscriptionDict[pID] = [KartRace_TrackNames[pID[0]], RecordPeriodStrings[pID[1]], []]
|
|
# [(3.12, "Mizzenberry"), (3.12, "Princess Precious Flutterwink"), (3.12, "Mr. Loony Snapblooper"), (3.12, "Miss Pumpkin Floo"),
|
|
# (3.12, "Frizzle"), (3.12, "King Quibble"), (3.12, "Left Loopwinger"), (3.12, "Super Silly Susan "),
|
|
# (3.12, "Bingo Buffworks"), (3.12, "Mickey Mouse")])
|
|
self.flagForUpdate(pID)
|
|
|
|
self.accept("UpdateRaceRecord", self.flagForUpdate)
|
|
|
|
def flagForUpdate(self, pID):
|
|
'''
|
|
Flag this score list to be updated if its not already.
|
|
'''
|
|
if pID not in self.changedList:
|
|
self.changedList.append(pID)
|
|
|
|
|
|
def __switchDisplayData(self):
|
|
'''
|
|
'''
|
|
#check that there's actually something in subscriptions list
|
|
if not self.subscriptionDict:
|
|
return
|
|
|
|
#figure out next list id
|
|
self.curIndex = (self.curIndex + 1) % len(self.subscriptionList)
|
|
|
|
curID = self.subscriptionList[self.curIndex]
|
|
#see if this list has been changed
|
|
if curID in self.changedList:
|
|
#if yes, query for updates
|
|
self.__updateScore(curID)
|
|
#remove from changed list
|
|
self.changedList.remove(curID)
|
|
|
|
#now work on displaying scores
|
|
#sendUpdate LeaderBoard display list of scores
|
|
self.sendNewDisplay()
|
|
|
|
def __updateScore(self, pID):
|
|
#update score list with ID pID by querying from server
|
|
#print str(self.subscriptionDict)
|
|
#print str(self.subscriptionDict[pID][2])
|
|
newRecords = self.air.raceMgr.getRecords(pID[0], pID[1])
|
|
|
|
#"edited": that is, we're not using raceType and racerNum at this moment... just forget those
|
|
editedRecords = []
|
|
|
|
for record in newRecords:
|
|
editedRecords.append((record[0], record[3]))
|
|
|
|
self.subscriptionDict[pID][2] = editedRecords
|
|
|
|
#for testing- junk filler for records
|
|
#[(3.12, "Mizzenberry"), (3.12, "Princess Precious Flutterwink"), (3.12, "Mr. Loony Snapblooper"), (3.12, "Miss Pumpkin Floo"),
|
|
#(3.12, "Frizzle"), (3.12, "King Quibble"), (3.12, "Left Loopwinger"), (3.12, "Super Silly Susan "),
|
|
#(3.12, "Bingo Buffworks"), (3.12, "Mickey Mouse")]
|
|
|
|
def delete(self):
|
|
self.notify.debug("delete: stopping distributedleaderboardAI %s" % (self.name))
|
|
self.ignore("UpdateRaceRecord")
|
|
self.stop()
|
|
DistributedObjectAI.DistributedObjectAI.delete(self)
|