def __init__(self,pakpath): self.pakpath = pakpath self.pakdir = os.path.dirname(pakpath) self.pakname = os.path.basename(pakpath) self.files = {} self.file_count = 0 self._metadata = None self.extractfile = "" self.extractpercent = 0 with open(self.pakpath, 'rb') as fh: mm = mmap.mmap(fh.fileno(), 0, access=mmap.ACCESS_READ) package = starbound.SBAsset6(mm) package.read_index() for path in package.index: length = package.index[path].length self.files[path] = length if len(package.metadata) != 0: self._metadata = json.dumps(package.metadata).encode('utf-8') self.files['/_metadata'] = len(self._metadata) self.file_count = package.file_count
def extractFiles(self,filelist,pathto,maingui): package_path = self.pakpath base = pathto with open(package_path, 'rb') as fh: mm = mmap.mmap(fh.fileno(), 0, access=mmap.ACCESS_READ) package = starbound.SBAsset6(mm) package.read_index() num_files = 0 total_num_files = len(filelist) for path in filelist: self.extractfile = path self.extractpercent = round((num_files / total_num_files)*100,2) wx.CallAfter(maingui.updatedialog,self.extractpercent,False) dest_path = base + path dir_path = os.path.dirname(dest_path) if not os.path.exists(dir_path): os.makedirs(dir_path) try: if path == '/_metadata': data = self._metadata else: data = package.get(path) except: print(path+" Extract Fail") continue with open(dest_path, 'wb') as file: file.write(data) num_files += 1 self.extractpercent = 100 wx.CallAfter(maingui.updatedialog, self.extractpercent,True)
def getFile(self,path): if path == '/_metadata': return self._metadata with open(self.pakpath, 'rb') as fh: mm = mmap.mmap(fh.fileno(), 0, access=mmap.ACCESS_READ) package = starbound.SBAsset6(mm) package.read_index() data = package.get(path) return data
def SetFileData(self,baseFileList,type='picture'): with open(self.pakpath, 'rb') as fh: for baseFile in baseFileList: if baseFile.type in ['png', 'jpeg', 'jpg', 'gif', 'bmp']: path = baseFile.dir + baseFile.name if path == '/_metadata': data = self._metadata else: mm = mmap.mmap(fh.fileno(), 0, access=mmap.ACCESS_READ) package = starbound.SBAsset6(mm) package.read_index() data = package.get(path) baseFile.data = data return baseFileList
def main(): p = optparse.OptionParser('Usage: %prog <package path>') p.add_option('-d', '--destination', dest='path', help='Destination directory') options, arguments = p.parse_args() # Validate the arguments. if len(arguments) != 1: p.error('Only one argument is supported (package path)') package_path = arguments[0] base = options.path if options.path else '.' # Load the assets file and its index. start = time.clock() with open(package_path, 'rb') as fh: mm = mmap.mmap(fh.fileno(), 0, access=mmap.ACCESS_READ) package = starbound.SBAsset6(mm) print('Loading index...') # Get the paths from the index in the database. package.read_index() print('Index loaded. Extracting {} files...'.format( package.file_count)) # Start extracting everything. num_files = 0 percentage_count = max(package.file_count // 100, 1) for path in package.index: dest_path = base + path dir_path = os.path.dirname(dest_path) if not os.path.exists(dir_path): os.makedirs(dir_path) try: data = package.get(path) except: # Break the dots in case std{out,err} are the same tty: sys.stdout.write('\n') sys.stdout.flush() print >> sys.stderr, 'W: Failed to read', path continue with open(dest_path, 'wb') as file: file.write(data) num_files += 1 if not num_files % percentage_count: sys.stdout.write('.') sys.stdout.flush() elapsed = time.clock() - start print('') print('Extracted {} files in {:.1f} seconds.'.format(num_files, elapsed))
def __init__(self, config): """ `config` should be a Config object (which will have the base game installation directory info). """ self.config = config self.base_game = config.starbound_data_dir self.base_storage = os.path.join(self.base_game, 'storage') self.base_player = os.path.join(self.base_storage, 'player') self.base_universe = os.path.join(self.base_storage, 'universe') self.base_pak = os.path.join(self.base_game, 'assets', 'packed.pak') # Read in the data file pakdf = open(self.base_pak, 'rb') self.pakdf = pakdf if pakdf: paktree = PakTree() pakdata = starbound.SBAsset6(pakdf) # py-starbound doesn't let you "browse" inside the pakfile's # internal "directory", so we're doing it by hand here pakdata.read_index() for path in pakdata.index.keys(): paktree.add_path(path) # Cropping parameters for our various material templates. # TODO: obviously if we want to render things *correctly* # we'd have to actually parse/understand these. Instead # we're just grabbing the top-left image, basically. crop_params = { '/tiles/classicmaterialtemplate.config': (4, 12, 12, 20), '/tiles/platformtemplate.config': (8, 0, 16, 8), '/tiles/girdertemplate.config': (1, 1, 9, 9), '/tiles/screwtemplate.config': (2, 14, 10, 22), '/tiles/columntemplate.config': (2, 14, 10, 22), '/tiles/rowtemplate.config': (2, 14, 10, 22), # Out of all of these, this will be the one that's Most # Wrong. I think this is space station stuff '/tiles/slopedmaterialtemplate.config': (24, 0, 32, 8), # These two are quite wrong, of course, since they're supposed # to "join up" properly. For pipes I chose a tile which is # the straight horizontal image for most, though note that it's # a vertical image for tentacle pipes. '/tiles/pipetemplate.config': (68, 36, 76, 44), '/tiles/railtemplate.config': (3, 5, 11, 13), } # Load in our materials self.materials = {} obj_list = paktree.get_all_recurs_matching_ext( '/tiles', 'material') for idx, (obj_path, obj_name) in enumerate(obj_list): matpath = '{}/{}'.format(obj_path, obj_name) material = read_config(pakdata.get(matpath)) if 'renderTemplate' in material: if material['renderTemplate'] in crop_params: self.materials[material['materialId']] = Material( material, obj_path, matpath, pakdata, crop_params[material['renderTemplate']], ) else: print('Unhandled material render template: {}'.format( material['renderTemplate'])) else: print('No render template found for {}'.format(matpath)) # Load in our material mods. self.matmods = {} for idx, matmod_name in enumerate( paktree.get_all_matching_ext('/tiles/mods', '.matmod')): # All matmods, at least in the base game, are classicmaterialtemplate matmodpath = '/tiles/mods/{}'.format(matmod_name) matmod = read_config(pakdata.get(matmodpath)) self.matmods[matmod['modId']] = Matmod(matmod, matmodpath, pakdata) # Load in object data (this also populates some item names, for container reporting) self.items = {} self.objects = {} obj_list = paktree.get_all_recurs_matching_ext( '/objects', 'object') for idx, (obj_path, obj_name) in enumerate(obj_list): obj_full_path = '{}/{}'.format(obj_path, obj_name) obj_json = read_config(pakdata.get(obj_full_path)) self.objects[obj_json['objectName']] = SBObject( obj_json, obj_name, obj_path, pakdata) self.items[ obj_json['objectName']] = StarboundData.strip_colors( obj_json['shortdescription']) # Load in plant data # The Entities seem to actually only references these by PNG path, so # I guess that's what we'll do too. self.plants = {} img_list = paktree.get_all_recurs_matching_ext('/plants', 'png') for idx, (img_path, img_name) in enumerate(img_list): img_full_path = '{}/{}'.format(img_path, img_name) self.plants[img_full_path] = Plant(img_full_path, pakdata) # Load in liquid data self.liquids = {} liquid_list = paktree.get_all_recurs_matching_ext( '/liquids', 'liquid') for idx, (liquid_path, liquid_name) in enumerate(liquid_list): liquid_full_path = '{}/{}'.format(liquid_path, liquid_name) liquid = read_config(pakdata.get(liquid_full_path)) self.liquids[liquid['liquidId']] = Liquid(liquid) # Load in extra item name mapping (just for reporting container contents) # (have verified that none of these "overwrite" the mappings set up by # the object processing) item_list = paktree.get_all_recurs_matching_ext( '/items', set([ # There may be some things in here which shouldn't be, but whatever. # Might make more sense to *exclude* extensions instead? That # list would be a bit shorter: animation, combofinisher, # config, frames, lua, png, weaponability, weaponcolors 'activeitem', 'augment', 'back', 'beamaxe', 'chest', 'consumable', 'currency', 'flashlight', 'harvestingtool', 'head', 'inspectiontool', 'instrument', 'item', 'legs', 'liqitem', 'matitem', 'miningtool', 'painttool', 'thrownitem', 'tillingtool', 'unlock', 'wiretool', ])) for item_path, item_name in item_list: item_full_path = '{}/{}'.format(item_path, item_name) item = read_config(pakdata.get(item_full_path)) self.items[item['itemName']] = StarboundData.strip_colors( item['shortdescription'])