levelAI only sends spec if hash is different, spec is saved by AI

This commit is contained in:
Darren Ranalli 2003-10-07 02:26:54 +00:00
parent d3e6bb5041
commit c27e85f890
3 changed files with 98 additions and 23 deletions

View File

@ -98,24 +98,37 @@ class DistributedLevel(DistributedObject.DistributedObject,
# announceGenerate(). Note that we have to call # announceGenerate(). Note that we have to call
# gotAllRequired() in the last 'faux-required' DC update # gotAllRequired() in the last 'faux-required' DC update
# handler. If you add another field, move this to the last one. # handler. If you add another field, move this to the last one.
self.privGotAllRequired()
def privGotAllRequired(self):
self.levelAnnounceGenerate()
def levelAnnounceGenerate(self):
pass
def initializeLevel(self, levelSpec):
"""subclass should call this as soon as it's located its level spec.
Must be called after obj has been generated."""
if __debug__: if __debug__:
# if we're in debug, ask the server if it wants to send us # if we're in debug, give the server the opportunity to send us
# a full spec # a full spec
self.sendUpdate('requestCurrentLevelSpec', []) self.candidateSpec = levelSpec
self.sendUpdate('requestCurrentLevelSpec', [hash(levelSpec)])
else: else:
self.gotAllRequired() self.privGotSpec(levelSpec)
if __debug__: if __debug__:
def setSpecSenderDoId(self, doId): def setSpecSenderDoId(self, doId):
DistributedLevel.notify.debug( DistributedLevel.notify.debug('setSpecSenderDoId: %s' % doId)
'setSpecSenderDoId: %s' % doId)
blobSender = toonbase.tcr.doId2do[doId] blobSender = toonbase.tcr.doId2do[doId]
def setSpecBlob(specBlob, blobSender=blobSender, self=self): def setSpecBlob(specBlob, blobSender=blobSender, self=self):
blobSender.sendAck() blobSender.sendAck()
from LevelSpec import LevelSpec from LevelSpec import LevelSpec
self.curSpec = eval(specBlob) spec = eval(specBlob)
self.gotAllRequired() if spec is None:
spec = self.candidateSpec
del self.candidateSpec
self.privGotSpec(spec)
if blobSender.isComplete(): if blobSender.isComplete():
setSpecBlob(blobSender.getBlob()) setSpecBlob(blobSender.getBlob())
@ -124,17 +137,7 @@ class DistributedLevel(DistributedObject.DistributedObject,
blobSender.setDoneEvent(evtName) blobSender.setDoneEvent(evtName)
self.acceptOnce(evtName, setSpecBlob) self.acceptOnce(evtName, setSpecBlob)
def gotAllRequired(self): def privGotSpec(self, levelSpec):
self.levelAnnounceGenerate()
def levelAnnounceGenerate(self):
pass
def initializeLevel(self, levelSpec):
"""subclass should call this as soon as it's located its level spec.
Must be called after obj has been generated."""
# if the AI sent us a full spec, use it instead
if self.curSpec is not None:
levelSpec = self.curSpec
Level.Level.initializeLevel(self, self.doId, levelSpec, Level.Level.initializeLevel(self, self.doId, levelSpec,
self.scenarioIndex) self.scenarioIndex)

View File

@ -18,7 +18,7 @@ class DistributedLevelAI(DistributedObjectAI.DistributedObjectAI,
Level.Level.__init__(self) Level.Level.__init__(self)
# this is one of the required fields # this is one of the required fields
self.zoneId = zoneId self.zoneId = zoneId
self.hasBeenEdited = 0 self.modified = 0
def generate(self, levelSpec): def generate(self, levelSpec):
self.notify.debug('generate') self.notify.debug('generate')
@ -38,6 +38,8 @@ class DistributedLevelAI(DistributedObjectAI.DistributedObjectAI,
def delete(self): def delete(self):
self.notify.debug('delete') self.notify.debug('delete')
if __debug__:
self.saveSpec()
self.destroyLevel() self.destroyLevel()
DistributedObjectAI.DistributedObjectAI.delete(self) DistributedObjectAI.DistributedObjectAI.delete(self)
@ -91,11 +93,33 @@ class DistributedLevelAI(DistributedObjectAI.DistributedObjectAI,
# send a copy to the client-side level obj # send a copy to the client-side level obj
self.sendUpdate('setAttribChange', self.sendUpdate('setAttribChange',
[entId, attribName, valueStr]) [entId, attribName, valueStr])
self.hasBeenEdited = 1
def requestCurrentLevelSpec(self): self.modified = 1
self.scheduleSave()
SavePeriod = simbase.config.GetFloat('factory-save-period', 10)
def scheduleSave(self):
if hasattr(self, 'saveTask'):
return
self.saveTask = taskMgr.doMethodLater(
DistributedLevelAI.SavePeriod,
self.saveSpec,
self.uniqueName('saveSpec'))
def saveSpec(self, task=None):
DistributedLevelAI.notify.info('saving spec')
if hasattr(self, 'saveTask'):
del self.saveTask
if self.modified:
self.levelSpec.saveToDisk()
self.modified = 0
def requestCurrentLevelSpec(self, specHash):
senderId = self.air.msgSender senderId = self.air.msgSender
spec = self.levelSpec spec = None
if hash(self.levelSpec) != specHash:
spec = self.levelSpec
specStr = repr(spec) specStr = repr(spec)
import DistributedLargeBlobSenderAI import DistributedLargeBlobSenderAI

View File

@ -10,8 +10,9 @@ class LevelSpec:
saving out modified spec data""" saving out modified spec data"""
notify = DirectNotifyGlobal.directNotify.newCategory("LevelSpec") notify = DirectNotifyGlobal.directNotify.newCategory("LevelSpec")
def __init__(self, specDict, scenario=0, entTypeReg=None): def __init__(self, specDict, scenario=0, filename=None, entTypeReg=None):
self.specDict = specDict self.specDict = specDict
self.filename = filename
self.entTypeReg = entTypeReg self.entTypeReg = entTypeReg
# this maps an entId to the dict that holds its spec; # this maps an entId to the dict that holds its spec;
@ -141,6 +142,50 @@ class LevelSpec:
# name of module that should be imported by spec py file # name of module that should be imported by spec py file
return 'SpecImports' return 'SpecImports'
def saveToDisk(self, filename=None):
"""returns zero on failure"""
import os
if filename is None:
filename = self.filename
# create a backup
try:
# does the file exist?
exists = 0
try:
os.stat(filename)
exists = 1
except OSError:
pass
if exists:
def getBackupFilename(num, filename=filename):
return '%s.%03i' % (filename, num)
numBackups = 50
try:
os.unlink(getBackupFilename(numBackups-1))
except OSError:
pass
for i in range(numBackups-1,0,-1):
try:
os.rename(getBackupFilename(i-1),
getBackupFilename(i))
except OSError:
pass
os.rename(filename, getBackupFilename(0))
except OSError, e:
LevelSpec.notify.warning('error during backup: %s' % str(e))
retval = 1
# wb to create a UNIX-format file
f = file(filename, 'wb')
try:
f.write(self.getPrettyString())
except IOError:
retval = 0
f.close()
return retval
def getPrettyString(self): def getPrettyString(self):
"""Returns a string that contains the spec data, nicely formatted. """Returns a string that contains the spec data, nicely formatted.
This should be used when writing the spec out to file.""" This should be used when writing the spec out to file."""
@ -256,6 +301,9 @@ class LevelSpec:
(levelSpec, self.specDict) (levelSpec, self.specDict)
) )
def __hash__(self):
return hash(repr(self))
def __repr__(self): def __repr__(self):
return 'LevelSpec(%s, scenario=%s)' % (repr(self.specDict), return 'LevelSpec(%s, scenario=%s)' % (repr(self.specDict),
self.scenario) self.scenario)