ai: Use Disney's ToontownAIRepository
This commit is contained in:
parent
f3ecc30c3d
commit
aaafd22c6d
|
|
@ -0,0 +1,482 @@
|
|||
from pandac.PandaModules import *
|
||||
from otp.otpbase import OTPGlobals
|
||||
from .AIMsgTypes import *
|
||||
from direct.directnotify import DirectNotifyGlobal
|
||||
from direct.fsm import ClassicFSM
|
||||
from direct.fsm import State
|
||||
from direct.task import Task
|
||||
from direct.distributed import ParentMgr
|
||||
from otp.ai.AIRepository import AIRepository
|
||||
from otp.ai.AIZoneData import AIZoneData, AIZoneDataStore
|
||||
import sys
|
||||
import os
|
||||
import copy
|
||||
from direct.distributed.PyDatagram import PyDatagram
|
||||
from direct.distributed.PyDatagramIterator import PyDatagramIterator
|
||||
|
||||
if __debug__:
|
||||
import pdb
|
||||
|
||||
class AIDistrict(AIRepository):
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory("AIDistrict")
|
||||
|
||||
def __init__(
|
||||
self, mdip, mdport, esip, esport, dcFileNames,
|
||||
districtId, districtName, districtType, serverId,
|
||||
minChannel, maxChannel, dcSuffix = 'AI'):
|
||||
assert self.notify.debugStateCall(self)
|
||||
|
||||
# Save the district Id (needed for calculations in AIRepository code)
|
||||
self.districtId = districtId
|
||||
self.districtName = districtName
|
||||
self.districtType = districtType
|
||||
|
||||
AIRepository.__init__(
|
||||
self, mdip, mdport, esip, esport, dcFileNames,
|
||||
serverId,
|
||||
minChannel, maxChannel, dcSuffix)
|
||||
self.setClientDatagram(0)
|
||||
assert minChannel > districtId
|
||||
if hasattr(self, 'setVerbose'):
|
||||
if self.config.GetBool('verbose-airepository'):
|
||||
self.setVerbose(1)
|
||||
|
||||
# Save the state server id
|
||||
self.serverId = serverId
|
||||
|
||||
# Record the reason each client leaves the shard, according to
|
||||
# the client.
|
||||
self._avatarDisconnectReasons = {}
|
||||
|
||||
# A list of avIds to pretend to disconnect at the next poll
|
||||
# cycle, for debugging purposes only.
|
||||
self._debugDisconnectIds = []
|
||||
|
||||
# player avatars will increment and decrement this count
|
||||
self._population = 0
|
||||
|
||||
# The AI State machine
|
||||
self.fsm = ClassicFSM.ClassicFSM('AIDistrict',
|
||||
[State.State('off',
|
||||
self.enterOff,
|
||||
self.exitOff,
|
||||
['connect']),
|
||||
State.State('connect',
|
||||
self.enterConnect,
|
||||
self.exitConnect,
|
||||
['districtReset', 'noConnection',
|
||||
# I added this because Skyler removed the transition to
|
||||
# districtReset -- Joe
|
||||
'playGame',
|
||||
]),
|
||||
State.State('districtReset',
|
||||
self.enterDistrictReset,
|
||||
self.exitDistrictReset,
|
||||
['playGame','noConnection']),
|
||||
State.State('playGame',
|
||||
self.enterPlayGame,
|
||||
self.exitPlayGame,
|
||||
['noConnection']),
|
||||
State.State('noConnection',
|
||||
self.enterNoConnection,
|
||||
self.exitNoConnection,
|
||||
['connect'])],
|
||||
# initial state
|
||||
'off',
|
||||
# final state
|
||||
'off',
|
||||
)
|
||||
|
||||
self.fsm.enterInitialState()
|
||||
|
||||
self.fsm.request("connect")
|
||||
|
||||
def uniqueName(self, desc):
|
||||
return desc+"-"+str(self.districtId)
|
||||
|
||||
def getGameDoId(self):
|
||||
self.notify.error('derived must override')
|
||||
|
||||
def incrementPopulation(self):
|
||||
self._population += 1
|
||||
def decrementPopulation(self):
|
||||
if __dev__:
|
||||
assert self._population > 0
|
||||
self._population = max(0, self._population - 1)
|
||||
|
||||
def getPopulation(self):
|
||||
if simbase.fakeDistrictPopulations:
|
||||
if not hasattr(self, '_fakePopulation'):
|
||||
import random
|
||||
self._fakePopulation = random.randrange(1000)
|
||||
return self._fakePopulation
|
||||
return self._population
|
||||
|
||||
def printPopulationToLog(self, task):
|
||||
self.notify.info("district-name %s | district-id %s | population %s" % (self.districtName, self.districtId, self._population))
|
||||
return Task.again
|
||||
|
||||
# check if this is a player avatar in a location where they should not be
|
||||
def _isValidPlayerLocation(self, parentId, zoneId):
|
||||
return True
|
||||
|
||||
#### Init ####
|
||||
|
||||
def writeServerEvent(self, eventType, who, description):
|
||||
AIRepository.writeServerEvent(self, eventType, who, description,
|
||||
serverId=self.districtId)
|
||||
|
||||
#### DistrictReset ####
|
||||
def enterDistrictReset(self):
|
||||
self.handler = self.handleDistrictReset
|
||||
self.deleteDistrict(self.districtId)
|
||||
|
||||
def exitDistrictReset(self):
|
||||
self.handler = None
|
||||
|
||||
def handleDistrictReset(self, msgType, di):
|
||||
if msgType == STATESERVER_OBJECT_DELETE_RAM:
|
||||
doId = di.getUint32()
|
||||
self.notify.info("Got request to delete doId: " +str(doId))
|
||||
if(doId == self.districtId):
|
||||
self.fsm.request("playGame")
|
||||
elif msgType == STATESERVER_OBJECT_NOTFOUND:
|
||||
doId = di.getUint32()
|
||||
self.notify.info("Got Not Found For doId: " +str(doId))
|
||||
if(doId == self.districtId):
|
||||
self.fsm.request("playGame")
|
||||
else:
|
||||
self.handleMessageType(msgType, di)
|
||||
|
||||
#### DistrictReset ####
|
||||
def enterPlayGame(self):
|
||||
self._zoneDataStore = AIZoneDataStore()
|
||||
AIRepository.enterPlayGame(self)
|
||||
if simbase.config.GetBool('game-server-tests', 0):
|
||||
from otp.distributed import DistributedTestObjectAI
|
||||
self.testObject = DistributedTestObjectAI.DistributedTestObjectAI(self)
|
||||
self.testObject.generateOtpObject(self.getGameDoId(), 3)
|
||||
|
||||
taskMgr.doMethodLater(300, self.printPopulationToLog, self.uniqueName("printPopulationTask"))
|
||||
|
||||
|
||||
def getZoneDataStore(self):
|
||||
"""This will crash (as designed) if called outside of the PlayGame state."""
|
||||
return self._zoneDataStore
|
||||
|
||||
def getRender(self, parentId, zoneId):
|
||||
# distributed objects should call getRender on themselves rather than
|
||||
# call this function. Only call this for zones that are actively being
|
||||
# used, otherwise the zone data will be destroyed before this function
|
||||
# returns
|
||||
zd = AIZoneData(self, parentId, zoneId)
|
||||
render = zd.getRender()
|
||||
zd.destroy()
|
||||
return render
|
||||
|
||||
def getNonCollidableParent(self, parentId, zoneId):
|
||||
# distributed objects should call getNonCollidableParent on themselves rather than
|
||||
# call this function. Only call this for zones that are actively being
|
||||
# used, otherwise the zone data will be destroyed before this function
|
||||
# returns
|
||||
zd = AIZoneData(self, parentId, zoneId)
|
||||
ncParent = zd.getNonCollidableParent()
|
||||
zd.destroy()
|
||||
return ncParent
|
||||
|
||||
def getCollTrav(self, parentId, zoneId, *args, **kArgs):
|
||||
# see comment in getRender
|
||||
zd = AIZoneData(self, parentId, zoneId)
|
||||
collTrav = zd.getCollTrav(*args, **kArgs)
|
||||
zd.destroy()
|
||||
return collTrav
|
||||
|
||||
def getParentMgr(self, parentId, zoneId):
|
||||
# see comment in getRender
|
||||
zd = AIZoneData(self, parentId, zoneId)
|
||||
parentMgr = zd.getParentMgr()
|
||||
zd.destroy()
|
||||
return parentMgr
|
||||
|
||||
def exitPlayGame(self):
|
||||
if simbase.config.GetBool('game-server-tests', 0):
|
||||
self.testObject.requestDelete()
|
||||
del self.testObject
|
||||
self._zoneDataStore.destroy()
|
||||
del self._zoneDataStore
|
||||
taskMgr.remove(self.uniqueName("printPopulationTask"))
|
||||
AIRepository.exitPlayGame(self)
|
||||
|
||||
#### connect #####
|
||||
def enterConnect(self):
|
||||
self.handler = self.handleConnect
|
||||
self.lastMessageTime = 0
|
||||
|
||||
self.connect([self.mdurl],
|
||||
successCallback = self._connected,
|
||||
failureCallback = self._failedToConnect)
|
||||
|
||||
def _failedToConnect(self, statusCode, statusString):
|
||||
self.fsm.request("noConnection")
|
||||
|
||||
def _connected(self):
|
||||
# Register our channel
|
||||
self.setConnectionName(self.districtName)
|
||||
AIRepository._connected(self)
|
||||
self.registerShardDownMessage(self.serverId)
|
||||
if self.districtType is not None:
|
||||
self.fsm.request("districtReset")
|
||||
|
||||
def _handleValidDistrictDown(self, msgType, di):
|
||||
downDistrictId = di.getUint32()
|
||||
if (downDistrictId != self.districtId):
|
||||
self.notify.error("Tried to bring down " +
|
||||
str(self.districtId) +
|
||||
" but " +
|
||||
str(downDistrictId) +
|
||||
" came down instead!")
|
||||
else:
|
||||
# We don't really need to do anything here.
|
||||
pass
|
||||
|
||||
def _handleIgnorableObjectDelete(self, msgType, di):
|
||||
doId = di.getUint32()
|
||||
self.notify.debug("Ignoring request to delete doId: " +
|
||||
str(doId))
|
||||
|
||||
def _handleValidDistrictUp(self, msgType, di):
|
||||
if msgType == STATESERVER_DISTRICT_UP:
|
||||
upDistrictId = di.getUint32()
|
||||
if (upDistrictId != self.districtId):
|
||||
self.notify.error("Tried to bring up " +
|
||||
str(self.districtId) +
|
||||
" but " +
|
||||
str(downDistrictId) +
|
||||
" came up instead!")
|
||||
else:
|
||||
self.notify.info("District %s %s is up. Creating objects..." %
|
||||
(self.districtId, self.districtName))
|
||||
self.fsm.request("playGame")
|
||||
|
||||
def exitConnect(self):
|
||||
self.handler = None
|
||||
# Clean up the create district tasks
|
||||
taskMgr.remove(self.uniqueName("newDistrictWait"))
|
||||
del self.lastMessageTime
|
||||
|
||||
def readerPollUntilEmpty(self, task):
|
||||
# This overrides AIRepository.readerPollUntilEmpty()
|
||||
# to provide an additional debugging hook.
|
||||
|
||||
while self._debugDisconnectIds:
|
||||
avId = self._debugDisconnectIds.pop()
|
||||
self._doDebugDisconnectAvatar(avId)
|
||||
|
||||
try:
|
||||
return AIRepository.readerPollUntilEmpty(self, task)
|
||||
except Exception as e:
|
||||
appendStr(e, '\nSENDER ID: %s' % self.getAvatarIdFromSender())
|
||||
raise
|
||||
|
||||
def handleReaderOverflow(self):
|
||||
# may as well delete the shard at this point
|
||||
self.deleteDistrict(self.districtId)
|
||||
raise StandardError("incoming-datagram buffer overflowed, "
|
||||
"aborting AI process")
|
||||
|
||||
##### General Purpose functions #####
|
||||
|
||||
def getAvatarExitEvent(self, avId):
|
||||
return ("districtExit-" + str(avId))
|
||||
|
||||
def debugDisconnectAvatar(self, avId):
|
||||
# This function will pretend to disconnect the indicated
|
||||
# avatar at the next poll cycle, as if the avatar suddenly
|
||||
# disconnected. This is for the purposes of debugging only.
|
||||
# It makes the AI totally forget who this avatar is, but the
|
||||
# avatar is still connected to the server.
|
||||
self._debugDisconnectIds.append(avId)
|
||||
|
||||
def _doDebugDisconnectAvatar(self, avId):
|
||||
obj = self.doId2do.get(avId)
|
||||
if obj:
|
||||
self.deleteDistObject(obj)
|
||||
self._announceDistObjExit(avId)
|
||||
|
||||
def _announceDistObjExit(self, avId):
|
||||
# This announces the exiting of this particular avatar
|
||||
messenger.send(self.getAvatarExitEvent(avId))
|
||||
|
||||
# This announces generally that an avatar has left.
|
||||
#messenger.send("avatarExited")
|
||||
|
||||
# Now we don't need to store the disconnect reason any more.
|
||||
try:
|
||||
del self._avatarDisconnectReasons[avId]
|
||||
except:
|
||||
pass
|
||||
|
||||
def setAvatarDisconnectReason(self, avId, disconnectReason):
|
||||
# This is told us by the client just before he disconnects.
|
||||
self._avatarDisconnectReasons[avId] = disconnectReason
|
||||
|
||||
def getAvatarDisconnectReason(self, avId):
|
||||
# Returns the reason (as reported by the client) for an
|
||||
# avatar's unexpected exit, or 0 if the reason is unknown. It
|
||||
# is only valid to query this during the handler for the
|
||||
# avatar's unexpected-exit event.
|
||||
return self._avatarDisconnectReasons.get(avId, 0)
|
||||
|
||||
def _handleUnexpectedDistrictDown(self, di):
|
||||
# Get the district Id
|
||||
downDistrict = di.getUint32()
|
||||
if downDistrict == self.districtId:
|
||||
self.notify.warning("Somebody brought my district(" +
|
||||
str(self.districtId) +
|
||||
") down! I'm shutting down!")
|
||||
sys.exit()
|
||||
else:
|
||||
self.notify.warning("Weird... My district is " +
|
||||
str(self.districtId) +
|
||||
" and I just got a message that district " +
|
||||
str(downDistrict) +
|
||||
" is going down. I'm ignoring it."
|
||||
)
|
||||
|
||||
def _handleUnexpectedDistrictUp(self, di):
|
||||
# Get the district Id
|
||||
upDistrict = di.getUint32()
|
||||
if upDistrict == self.districtId:
|
||||
self.notify.warning("Somebody brought my district(" +
|
||||
str(self.districtId) +
|
||||
") up! I'm shutting down!")
|
||||
sys.exit()
|
||||
else:
|
||||
self.notify.warning("Weird... My district is " +
|
||||
str(self.districtId) +
|
||||
" and I just got a message that district " +
|
||||
str(upDistrict) +
|
||||
" is coming up. I'm ignoring it."
|
||||
)
|
||||
|
||||
def _handleMakeFriendsReply(self, di):
|
||||
result = di.getUint8()
|
||||
context = di.getUint32()
|
||||
messenger.send("makeFriendsReply", [result, context])
|
||||
|
||||
def _handleRequestSecretReply(self, di):
|
||||
result = di.getUint8()
|
||||
secret = di.getString()
|
||||
requesterId = di.getUint32()
|
||||
messenger.send("requestSecretReply", [result, secret, requesterId])
|
||||
|
||||
def _handleSubmitSecretReply(self, di):
|
||||
result = di.getUint8()
|
||||
secret = di.getString()
|
||||
requesterId = di.getUint32()
|
||||
avId = di.getUint32()
|
||||
self.writeServerEvent('entered-secret', requesterId, '%s|%s|%s' % (result, secret, avId))
|
||||
messenger.send("submitSecretReply", [result, secret, requesterId, avId])
|
||||
|
||||
def registerShardDownMessage(self, stateserverid):
|
||||
datagram = PyDatagram()
|
||||
datagram.addServerHeader(
|
||||
stateserverid, self.ourChannel, STATESERVER_SHARD_REST)
|
||||
datagram.addChannel(self.ourChannel)
|
||||
# schedule for execution on socket close
|
||||
self.addPostSocketClose(datagram)
|
||||
|
||||
def sendSetZone(self, distobj, zoneId):
|
||||
datagram = PyDatagram()
|
||||
datagram.addServerHeader(
|
||||
distobj.doId, self.ourChannel, STATESERVER_OBJECT_SET_ZONE)
|
||||
# Add the zone parent id
|
||||
# HACK:
|
||||
parentId = oldParentId = self.districtId
|
||||
datagram.addUint32(parentId)
|
||||
# Put in the zone id
|
||||
datagram.addUint32(zoneId)
|
||||
# Send it
|
||||
self.send(datagram)
|
||||
# The servers don't inform us of this zone change, because we're the
|
||||
# one that requested it. Update immediately.
|
||||
# TODO: pass in the old parent and old zone
|
||||
distobj.setLocation(parentId, zoneId) #, oldParentId, distobj.zoneId)
|
||||
|
||||
def deleteDistrict(self, districtId):
|
||||
# Create a message
|
||||
datagram = PyDatagram()
|
||||
datagram.addServerHeader(
|
||||
self.serverId, self.ourChannel, STATESERVER_OBJECT_DELETE_RAM)
|
||||
# The Id of the object in question
|
||||
datagram.addUint32(districtId)
|
||||
# Send the message
|
||||
self.send(datagram)
|
||||
# Make sure the message gets there.
|
||||
self.flush()
|
||||
|
||||
def makeFriends(self, avatarAId, avatarBId, flags, context):
|
||||
"""
|
||||
Requests to make a friendship between avatarA and avatarB with
|
||||
the indicated flags (or upgrade an existing friendship with
|
||||
the indicated flags). The context is any arbitrary 32-bit
|
||||
integer. When the friendship is made, or the operation fails,
|
||||
the "makeFriendsReply" event is generated, with two
|
||||
parameters: an integer result code, and the supplied context.
|
||||
"""
|
||||
datagram = PyDatagram()
|
||||
datagram.addServerHeader(
|
||||
DBSERVER_ID, self.ourChannel, DBSERVER_MAKE_FRIENDS)
|
||||
|
||||
# Indicate the two avatars who are making friends
|
||||
datagram.addUint32(avatarAId)
|
||||
datagram.addUint32(avatarBId)
|
||||
datagram.addUint8(flags)
|
||||
datagram.addUint32(context)
|
||||
self.send(datagram)
|
||||
|
||||
def requestSecret(self, requesterId):
|
||||
"""
|
||||
Requests a "secret" from the database server. This is a
|
||||
unique string that will be associated with the indicated
|
||||
requesterId, for the purposes of authenticating true-life
|
||||
friends.
|
||||
|
||||
When the secret is ready, a "requestSecretReply" message will
|
||||
be thrown with three parameters: the result code (0 or 1,
|
||||
indicating failure or success), the generated secret, and the
|
||||
requesterId again.
|
||||
"""
|
||||
datagram = PyDatagram()
|
||||
datagram.addServerHeader(
|
||||
DBSERVER_ID,self.ourChannel,DBSERVER_REQUEST_SECRET)
|
||||
|
||||
# Indicate the number we want to associate with the new secret.
|
||||
datagram.addUint32(requesterId)
|
||||
# Send it off!
|
||||
self.send(datagram)
|
||||
|
||||
def submitSecret(self, requesterId, secret):
|
||||
"""
|
||||
Submits a "secret" back to the database server for validation.
|
||||
This attempts to match the indicated string, entered by the
|
||||
user, to a string returned by a previous call to
|
||||
requestSecret().
|
||||
|
||||
When the response comes back from the server, a
|
||||
"submitSecretReply" message will be thrown with four
|
||||
parameters: the result code (0 or 1, indicating failure or
|
||||
success), the secret again, the requesterId again, and the
|
||||
number associated with the original secret (that is, the
|
||||
original requesterId).
|
||||
"""
|
||||
datagram = PyDatagram()
|
||||
datagram.addServerHeader(
|
||||
DBSERVER_ID, self.ourChannel, DBSERVER_SUBMIT_SECRET)
|
||||
# Pass in our identifying number, and the string.
|
||||
datagram.addUint32(requesterId)
|
||||
datagram.addString(secret)
|
||||
self.send(datagram)
|
||||
|
||||
def replaceMethod(self, oldMethod, newFunction):
|
||||
return 0
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,89 @@
|
|||
from direct.showbase.DirectObject import DirectObject
|
||||
from direct.showbase import GarbageReport
|
||||
|
||||
class GarbageLeakServerEventAggregatorAI(DirectObject):
|
||||
ClientLeakEvent = 'LeakAggregator-ClientGarbageLeakReceived'
|
||||
def __init__(self, air):
|
||||
self.air = air
|
||||
self._eventFreq = config.GetFloat('garbage-leak-server-event-frequency', 60 * 60.)
|
||||
self._doLaterName = None
|
||||
self._sentLeakDesc2num = {}
|
||||
self._curLeakDesc2num = {}
|
||||
self.accept(GarbageReport.GarbageCycleCountAnnounceEvent,
|
||||
self._handleCycleCounts)
|
||||
self._clientStartFDC = None
|
||||
self._doLaterNameClient = None
|
||||
self._sentClientDesc2num = {}
|
||||
self._curClientDesc2num = {}
|
||||
self.accept(self.ClientLeakEvent, self._handleClientCycleCount)
|
||||
|
||||
def destroy(self):
|
||||
self.ignoreAll()
|
||||
self._clientStartFDC.destroy()
|
||||
self._stopSending()
|
||||
self._stopSendingClientLeaks()
|
||||
del self.air
|
||||
|
||||
def _handleCycleCounts(self, desc2num):
|
||||
self._curLeakDesc2num = desc2num
|
||||
self._startSending()
|
||||
|
||||
def _handleClientCycleCount(self, num, description):
|
||||
self._curClientDesc2num.setdefault(description, 0)
|
||||
self._curClientDesc2num[description] += num
|
||||
if not self._clientStartFDC:
|
||||
# do an FDC to allow other concurrent client events to make it in, for dev/testing
|
||||
self._clientStartFDC = FrameDelayedCall(
|
||||
uniqueName('%s-startClientSend' % self.__class__.__name__),
|
||||
self._startSendingClientLeaks)
|
||||
|
||||
def _startSending(self):
|
||||
if not self._doLaterName:
|
||||
self._sendLeaks()
|
||||
self._doLaterName = uniqueName('%s-sendGarbageServerEvents' % self.__class__.__name__)
|
||||
self.doMethodLater(self._eventFreq, self._sendLeaks, self._doLaterName)
|
||||
|
||||
def _stopSending(self):
|
||||
self.removeTask(self._doLaterName)
|
||||
self._doLaterName = None
|
||||
|
||||
def _sendLeaks(self, task=None):
|
||||
# only send the number of occurences of each leak that
|
||||
# we haven't already sent
|
||||
for desc, curNum in self._curLeakDesc2num.iteritems():
|
||||
self._sentLeakDesc2num.setdefault(desc, 0)
|
||||
num = curNum - self._sentLeakDesc2num[desc]
|
||||
if num > 0:
|
||||
if hasattr(self.air, 'districtId'):
|
||||
who = self.air.districtId
|
||||
eventName = 'ai-garbage'
|
||||
else:
|
||||
who = self.air.ourChannel
|
||||
eventName = 'ud-garbage'
|
||||
self.air.writeServerEvent(eventName, who, '%s|%s' % (num, desc))
|
||||
self._sentLeakDesc2num[desc] = curNum
|
||||
if task:
|
||||
return task.again
|
||||
|
||||
def _startSendingClientLeaks(self):
|
||||
if not self._doLaterNameClient:
|
||||
self._sendClientLeaks()
|
||||
self._doLaterNameClient = uniqueName(
|
||||
'%s-sendClientGarbageServerEvents' % self.__class__.__name__)
|
||||
self.doMethodLater(self._eventFreq, self._sendClientLeaks, self._doLaterNameClient)
|
||||
|
||||
def _stopSendingClientLeaks(self):
|
||||
self.removeTask(self._doLaterNameClient)
|
||||
self._doLaterNameClient = None
|
||||
|
||||
def _sendClientLeaks(self, task=None):
|
||||
# only send the number of occurences of each leak that
|
||||
# we haven't already sent
|
||||
for desc, curNum in self._curClientDesc2num.iteritems():
|
||||
self._sentClientDesc2num.setdefault(desc, 0)
|
||||
num = curNum - self._sentClientDesc2num[desc]
|
||||
if num > 0:
|
||||
self.air.writeServerEvent('client-garbage', self.air.districtId, '%s|%s' % (num, desc))
|
||||
self._sentClientDesc2num[desc] = curNum
|
||||
if task:
|
||||
return task.again
|
||||
|
|
@ -1,3 +1,10 @@
|
|||
from panda3d.core import loadPrcFile
|
||||
|
||||
# TODO: use argparse for this?
|
||||
configs = ('etc/Configrc.prc',)
|
||||
for prc in configs:
|
||||
loadPrcFile(prc)
|
||||
|
||||
import builtins
|
||||
|
||||
class game:
|
||||
|
|
@ -7,7 +14,6 @@ builtins.game = game()
|
|||
|
||||
# NOTE: this file is not used in production. See AIServiceStart.py
|
||||
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
|
@ -19,7 +25,7 @@ from direct.showbase import PythonUtil
|
|||
|
||||
# Clear the default model extension for AI developers, so they'll know
|
||||
# when they screw up and omit it.
|
||||
from pandac.PandaModules import loadPrcFileData
|
||||
from panda3d.core import loadPrcFileData
|
||||
loadPrcFileData("AIStart.py", "default-model-extension")
|
||||
|
||||
simbase.mdip = simbase.config.GetString("msg-director-ip", "localhost")
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue