Exemple #1
0
    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
Exemple #2
0
    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)
Exemple #3
0
    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
Exemple #4
0
 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
Exemple #5
0
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))
Exemple #6
0
    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'])