Poodletooth-iLand/toontown/toonbase/ContentPacksManager.py
2015-03-03 17:10:12 -05:00

142 lines
4.3 KiB
Python

from direct.directnotify.DirectNotifyGlobal import directNotify
import fnmatch
import os
from panda3d.core import Multifile, Filename, VirtualFileSystem
import yaml
APPLICABLE_FILE_PATTERNS = ('*.mf', 'ambience.yaml')
CONTENT_EXT_WHITELIST = ('.jpg', '.jpeg', '.rgb', '.png', '.ogg', '.ttf')
class ContentPackError(Exception):
pass
class ContentPacksManager:
notify = directNotify.newCategory('ContentPacksManager')
notify.setInfo(True)
def __init__(self, filepath='contentpacks/', sortFilename='sort.yaml'):
self.filepath = filepath
self.sortFilename = os.path.join(self.filepath, sortFilename)
if __debug__:
self.mountPoint = '../resources'
else:
self.mountPoint = '/'
self.vfs = VirtualFileSystem.getGlobalPtr()
self.sort = []
self.ambience = {}
def isApplicable(self, filename):
"""
Returns whether or not the specified file is applicable.
"""
# Does this file exist?
if not os.path.exists(os.path.join(self.filepath, filename)):
return False
# Does this file match one of the applicable file patterns?
basename = os.path.basename(filename)
for pattern in APPLICABLE_FILE_PATTERNS:
if fnmatch.fnmatch(basename, pattern):
return True
return False
def applyMultifile(self, filename):
"""
Apply the specified multifile.
"""
mf = Multifile()
mf.openReadWrite(Filename(os.path.join(self.filepath, filename)))
# Discard content with non-whitelisted extensions:
for subfileName in mf.getSubfileNames():
ext = os.path.splitext(subfileName)[1]
if ext not in CONTENT_EXT_WHITELIST:
mf.removeSubfile(subfileName)
self.vfs.mount(mf, self.mountPoint, 0)
def applyAmbience(self, filename):
"""
Apply the specified ambience configuration file.
"""
with open(os.path.join(self.filepath, filename), 'r') as f:
self.ambience.update(yaml.load(f) or {})
def apply(self, filename):
"""
Apply the specified content pack file.
"""
self.notify.info('Applying %s...' % filename)
basename = os.path.basename(filename)
if basename.endswith('.mf'):
self.applyMultifile(filename)
elif basename == 'ambience.yaml':
self.applyAmbience(filename)
def applyAll(self):
"""
Using the sort configuration, recursively apply all applicable content
pack files under the configured content packs directory.
"""
# First, read the sort configuration:
self.readSortConfig()
# Next, apply the sorted files:
for filename in self.sort[:]:
if self.isApplicable(filename):
self.apply(filename)
else:
self.notify.warning('Invalidating %s...' % filename)
self.sort.remove(filename)
# Apply the non-sorted files:
for root, _, filenames in os.walk(self.filepath):
root = root[len(self.filepath):]
for filename in filenames:
filename = os.path.join(root, filename).replace('\\', '/')
# Ensure this file isn't sorted:
if filename in self.sort:
continue
# Ensure this file is applicable:
if not self.isApplicable(filename):
continue
# Apply this file, and add it to the sort configuration:
self.apply(filename)
self.sort.append(filename)
# Finally, write the new sort configuration:
self.writeSortConfig()
def readSortConfig(self):
"""
Read the sort configuration.
"""
if not os.path.exists(self.sortFilename):
return
with open(self.sortFilename, 'r') as f:
self.sort = yaml.load(f) or []
def writeSortConfig(self):
"""
Write the sort configuration to disk.
"""
with open(self.sortFilename, 'w') as f:
for filename in self.sort:
f.write('- %s\n' % filename)
def getAmbience(self, group):
"""
Returns the ambience configurations for the specified group.
"""
return self.ambience.get(group, {})