mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 10:54:24 -04:00
levelAI only sends spec if hash is different, spec is saved by AI
This commit is contained in:
parent
d3e6bb5041
commit
c27e85f890
@ -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)
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user