def tgi(self, pattern='tgi', order='<'): pattern = pattern.lower() self.verify_tgi(pattern) key = ResourceKey() for f in pattern: if f == 't': key.t = self.u32(order) elif f == 'g': key.g = self.u32(order) elif f == 'i': key.i = self.u64(order) return key
def __init__(self, key): self.version = self.VERSION.DEFAULT self.rig = ExternalResource(ResourceKey()) self.unknown = 1.0 self.reserved = [0] * self.RESERVED_COUNT self.bone_weights = [] RCOL.__init__(self, key)
def __init__(self, key=None, stream=None): self.version = self.VERSION.DEFAULT self.bounds = BoundingBox() self.flags = 0x00000000 self.routing_footprint = ExternalResource(ResourceKey()) self.entries = [] RCOL.__init__(self, key, stream)
def __init__(self, package): """ """ self.offset = 0 self.file_size = 0 self.mem_size = 0 self.compressed = False self.unknown = 1 self.key = ResourceKey() self.delete_pending = False self.source = package self.name = ''
def __init__(self, key=None): RCOL.__init__(self, key) self.version = 0 self.indices = [] self.vertices = [] self.shader = None self.material = MaterialBlock() self.merge_group = 0 self.skin_controller = ExternalResource( ResourceKey(BodySkinController.ID)) self.sort_order = 0 self.vertex_format = self.VertexFormat() self.bones = []
def create_key(cls, name): assert len(name) > 4 s = name.split('_', 1) assert len(s[0]) >= 1 flags = { 'b': 0x01, 'p': 0x02, 'c': 0x03, 't': 0x04, 'h': 0x05, 'e': 0x06, 'ad': 0x08, 'cd': 0x09, 'al': 0x0A, 'ac': 0x0D, 'cc': 0x0E, 'ah': 0x10, 'ch': 0x11, 'ab': 0x12, 'ar': 0x13 } generic_name = name generic_actor_types = {'a', 'o'} def get_generic_actor_type(s): return 'o' if s == 'o' else 'a' actors = s[0].split('2', 1) mask = 0 xAge = 0 yAge = 0 if actors[0] in flags: xAge = flags[actors[0]] if len(actors) > 1: if not actors[0] in generic_actor_types or not actors[ 1] in generic_actor_types: if actors[1] in flags: yAge = flags[actors[1]] generic_name = '%s2%s_%s' % (get_generic_actor_type( actors[0]), get_generic_actor_type(actors[1]), s[1]) mask = 0x8000 | xAge << 8 | yAge elif not actors[0] in generic_actor_types: generic_name = 'a_' + s[1] mask = 0x8000 | xAge << 8 instance = FNV64.hash(generic_name) instance &= 0x7FFFFFFFFFFFFFFF instance ^= mask << 48 group = 0x48000000 if xAge > 0x06 or yAge > 0x06 else 0 return ResourceKey(cls.ID, group, instance)
def parse_value(value_string, resources): items = [] strings = value_string.split(',') for string in strings: if string[:4] == 'key:': keyVals = string[4:].split(':') key = ResourceKey(int(keyVals[0], 16), int(keyVals[1], 16), int(keyVals[2], 16)) items.append(key) elif string in ('true', 'false'): items.append(string == 'true') else: items.append(string) return items if len(items) > 1 else items[0]
def __init__(self, filename=None): """ """ self.stream = None self.filename = os.path.abspath(filename) if filename: self.stream = io.open(self.filename, 'rb') self.entries = [] self.header = self.Header() self.index_flags = 0 self.static_key = ResourceKey() self.__name_map = None self.__loaded_resources = {} self.__pending_deletes = {} self.cache = False self.load()
def load(self): if not self.stream: return s = StreamReader(self.stream) self.entries = [] self.header.read(self.stream) self.stream.seek(self.header.index_offset, SEEK_SET) self.index_flags = s.u32() if Flag.is_set(self.index_flags, self.INDEX_FLAG.TYPE): self.static_key.t = s.u32() if Flag.is_set(self.index_flags, self.INDEX_FLAG.GROUP): self.static_key.g = s.u32() if Flag.is_set(self.index_flags, self.INDEX_FLAG.INSTANCE_HI): self.static_key.i = s.u32() << 32 if Flag.is_set(self.index_flags, self.INDEX_FLAG.INSTANCE_LO): self.static_key.i |= s.u32() for i in range(self.header.index_entry_count): index = self.IndexEntry(self) index.key = ResourceKey() if Flag.is_set(self.index_flags, self.INDEX_FLAG.TYPE): index.key.t = self.static_key.t else: index.key.t = s.u32() if Flag.is_set(self.index_flags, self.INDEX_FLAG.GROUP): index.key.g = self.static_key.g else: index.key.g = s.u32() if Flag.is_set(self.index_flags, self.INDEX_FLAG.INSTANCE_HI): instance_hi = self.static_key.i >> 32 else: instance_hi = s.u32() if Flag.is_set(self.index_flags, self.INDEX_FLAG.INSTANCE_LO): instance_lo = self.static_key.i & 0xFFFFFFFF else: instance_lo = s.u32() index.key.i = (instance_hi << 32) + instance_lo index.offset = s.u32() index.file_size = s.u32() & 0x0FFFFFFF index.mem_size = s.u32() flag = s.u16() index.compressed = flag == 0xFFFF index.unknown = s.u16() self.entries.append(index) nmap = self.name_map for entry in self.entries: entry.name = nmap[entry.key.i] print("Done.")
def write_rcol(self, stream, rcol): self.write_tag(stream) s = StreamWriter(stream) s.u32(self.version) tgi = TGIList() tgi.begin_write(stream) s.u8(len(self.entries)) for entry in self.entries: s.u8(entry.TYPE) entry.write(stream, tgi) s.u8(2) self.bounds.write(stream) s.u32(self.flags) if self.routing_footprint.key != ResourceKey(): s.u8(1) s.tgi(self.routing_footprint.key, 'TGI') else: s.u8(0) tgi.end_write(stream)
def load_object(objd, package): print('Loading object!') assert isinstance(objd, BuildBuyProduct) vpxy = first(package.find_all_type(VisualProxy.ID)).fetch(VisualProxy) armature_rig = None rig = package.find_key( first( vpxy.entries, lambda e: isinstance(e, VisualProxy.MiscEntry) and e. resource.key.t == SkeletonRig.ID).resource.key) if rig: try: rig = rig.fetch(SkeletonRig) armature_rig = load_rig(rig) except: print('Unable to load rig, please patch your game...') if not armature_rig: print('No rig found') armature_rig = create_marker_node(objd.resource_name, True) print('Loading Model...') modl = package.find_key( first( vpxy.entries, lambda e: isinstance(e, VisualProxy.MiscEntry) and e. resource.key.t == Model.ID).resource.key).fetch(Model) if any(objd.presets): preset = objd.presets[0] else: preset = package.find_key( ResourceKey(t=PackedPreset.ID, g=1, i=modl.key.i)) if preset: preset = preset.fetch(PackedPreset) else: preset = Preset() ml = MaterialLoader(package, preset) load_model(package, modl, armature_rig, ml) return armature_rig
def __init__(self): self.name = "" self.resource = ExternalResource(ResourceKey()) self.values = {} self.patterns = [] self.variable = None
def __init__(self, stream=None, resources=None, parent=None): self.index = 0 self.resource = ExternalResource(ResourceKey()) VisualProxy.Entry.__init__(self, stream, resources)
def load_caspart(caspart, package, armature_rig, morphs=False, expressions=False): print('Loading CASPart %s...' % caspart.resource_name) bgeo = {} preset = None loaded_morphs = [] # Loads a BlendGeometry and add it to the dictionary. If a key was already loaded, skip it. Either key or index must be specified. # If a name is provided, it will be used, otherwise it will default to the package name or the instance id def load_bgeo(key=None, name=None, index=None): if index: assert isinstance(index, Package.IndexEntry) key = index.key print('Loading %s %s' % (key, index)) if not key.i: print( 'Skipping invalid BlendGeometry %s: Instance must not be 0.' % key) return if key in loaded_morphs: print('Skipping BlendGeometry %s: Already loaded.' % key) return try: if not index: if key.t == BlendData.ID: blend_data = package.find_key(key).fetch(BlendData) assert isinstance(blend_data, BlendData) key = blend_data.blend_geometry.key index = package.find_key(key) if not index: print( 'Skipping BlendGeometry %s: Resource not found in package' % key) return assert isinstance(index, Package.IndexEntry) resource = index.fetch(BlendGeometry) assert isinstance(resource, BlendGeometry) if not name: name = resource.resource_name if not name: name = '%16X' % key.i bgeo[name] = resource loaded_morphs.append(key) except Exception as ex: print('Skipping BlendGeometry %s: Error loading' % key) print(ex) pass pass # Maps blend LOD vertex by it's id def map_blend_vertex(blend_lod): bvmap = {} for v in blend_lod.vertices: bvmap[v.id] = v return bvmap # Adds a bone to the skeleton def create_armature_bone(bone_name, parent_bone=None, min_bone=.001): set_context('EDIT', armature_rig) armature_bone = find_bone(armature_rig.data.edit_bones, bone_name) if not armature_bone: armature_bone = armature_rig.data.edit_bones.new(bone_name) armature_bone.use_connect = False armature_bone.tail = [0, min_bone, 0] if parent_bone: armature_bone.parent = armature_rig.data.edit_bones[parent_bone] set_context('POSE', armature_rig) return armature_bone if caspart: print('CASP found...') preset = package.find_key( ResourceKey(t=PackedPreset.ID, g=caspart.key.g, i=caspart.key.i)) if preset: preset = preset.fetch(PackedPreset) elif any(caspart.presets): preset = caspart.presets[0] part_name = caspart.part_name assert isinstance(caspart, CASPart) vpxy = package.get_resource(key=caspart.sources[0].key, wrapper=VisualProxy) # Load standard morphs if specified with user friendly name if morphs: if caspart.blend_fat.key.i: load_bgeo(name='Fat', key=caspart.blend_fat.key) if caspart.blend_fit.key.i: load_bgeo(name='Fit', key=caspart.blend_fit.key) if caspart.blend_thin.key.i: load_bgeo(name='Thin', key=caspart.blend_thin.key) if caspart.blend_special.key.i: load_bgeo(name='Pregnant', key=caspart.blend_special.key) else: print('No CASP found, defaulting to first VPXY') vpxy = first(package.find_all_type(VisualProxy.ID)) if vpxy: vpxy = vpxy.fetch(VisualProxy) assert isinstance(vpxy, VisualProxy) part_name = vpxy.resource_name print('Loading morphs...') for bgeo_index in package.find_all_type(BlendGeometry.ID): try: load_bgeo(index=bgeo_index) except Exception as ex: print("Unable to load morph %s" % bgeo_index) print(ex) if not preset: preset = Preset() ml = MaterialLoader(package, preset) lod_hi = first(vpxy.entries, lambda e: e.TYPE == VisualProxy.LodEntry.TYPE) assert isinstance(lod_hi, VisualProxy.LodEntry) # Arrange morph data for processing blend_vertex_lod_map = {} for blend_name in bgeo: cur_bgeo = bgeo[blend_name] for blend in cur_bgeo.blends: blend_vertex_lod_map[blend_name] = map_blend_vertex( blend.lods[lod_hi.index]) # Load face morphs for animal meshes. Loads any BodyGeometry matching the name 'Expression' as a morph if expressions: driver_root = 'b__DRIVERS__' create_armature_bone(driver_root) print('creating root: %s' % driver_root) for index in package.find_all_type(BodyGeometry.ID): assert isinstance(index, Package.IndexEntry) geom = index.fetch(BodyGeometry) assert isinstance(geom, BodyGeometry) if not 'Expressions' in geom.resource_name: continue blend_name = geom.resource_name[17:-2] create_armature_bone(blend_name, parent_bone=driver_root) blend_vertex_lod_map[blend_name] = map_blend_vertex(geom) meshes = [] for lod_sub_index, geom in enumerate( package.find_key(item.key).fetch(BodyGeometry) for item in lod_hi.resources): material = ml.generate('%s_%i' % (part_name, lod_sub_index), geom.material) meshes.append( load_geom(part_name + '_' + str(lod_sub_index), geom, blend_vertex_lod_map, armature_rig, material)) return meshes
def commit(self): """ """ tmp_filename = tempfile.mktemp() tmp_stream = io.open(tmp_filename, 'wb') s = StreamWriter(tmp_stream) self.header.index_entry_count = len(self.entries) pkg_stream = None if self.stream: pkg_stream = self.stream elif exists(self.filename): pkg_stream = io.open(self.filename, 'rb') #skip over header tmp_stream.seek(self.Header.SIZE, SEEK_SET) # Write data, update header and index self.index_flags = 0 self.static_key = ResourceKey() if any(self.entries): self.index_flags = self.INDEX_FLAG.TYPE | self.INDEX_FLAG.GROUP static_key = None for index in self.entries: if index.delete_pending: self.entries.remove(index) continue data = None if index.key in self.__loaded_resources: index.compressed = False wrapper = self.__loaded_resources[index.key] with BytesIO() as wrapper_stream: wrapper.write(wrapper_stream) wrapper_stream.seek(0, SEEK_SET) data = wrapper_stream.read(-1) index.file_size = len(data) index.mem_size = index.file_size elif isinstance(pkg_stream, io.FileIO): pkg_stream.seek(index.offset) data = pkg_stream.read(index.mem_size) else: continue # if static_key == None: static_key = index.key.clone() # if not index.key.t == static_key.t: # static_key.t = 0 # self.index_flags = Flag.unset(self.index_flags, self.INDEX_FLAG.TYPE) # if not index.key.g == static_key.g: # static_key.g = 0 # self.index_flags = Flag.unset(self.index_flags, self.INDEX_FLAG.GROUP) index.offset = tmp_stream.tell() tmp_stream.write(data) if self.index_flags: self.static_key = static_key # Write index table self.header.index_offset = tmp_stream.tell() s.u32(0) # if Flag.is_set(self.index_flags, self.INDEX_FLAG.TYPE): # s.u32(self.static_key.t) # if Flag.is_set(self.index_flags, self.INDEX_FLAG.GROUP): # s.u32(self.static_key.g) for index in self.entries: # if not Flag.is_set(self.index_flags, self.INDEX_FLAG.TYPE): # s.u32(index.key.t) # if not Flag.is_set(self.index_flags, self.INDEX_FLAG.GROUP): # s.u32(index.key.g) s.u32(index.key.t) s.u32(index.key.g) instance_hi = index.key.i >> 32 instance_lo = index.key.i & 0xFFFFFFFF s.u32(instance_hi) s.u32(instance_lo) s.u32(index.offset) s.u32(index.file_size | 0x80000000) s.u32(index.mem_size) s.u16(0 if not index.compressed else 0xFFFF) s.u16(index.unknown) end = tmp_stream.tell() self.header.index_size = end - self.header.index_offset # Go back and write header tmp_stream.seek(0, SEEK_SET) self.header.write(tmp_stream) if pkg_stream: pkg_stream.close() os.unlink(self.filename) tmp_stream.close() shutil.move(tmp_filename, self.filename)