bethesda文件格式的解析器

bethesda-structs的Python项目详细描述


Bethesda Structs LogoPyPi StatusSupported VersionsLicenseBuild StatusDocumentation StatusCodacy GradeSay Thanks!Waffle.io

关于

modding bethesda的游戏可以是一门艺术。
这个包打算提供cleanaccessible方法来解析和理解bethesda的文件类型。

例如:

Bethesda的归档文件有很多“非归档”工具(.bsa.ba2),但是没有读取这些文件类型的好的编程方法。 使用这个包,理解关于存档的每一个小细节都是简单而直接的(请参见BSA UsageBA2 Usage)。

有关更高级的用法和信息,check out the documentation

The supported filetypes are parsers not writers.
We do not currently support the writing of archives or plugins.

安装

因为这是光荣的python,所以安装bethesda-structs应该非常简单。

使用pypi

安装此软件包的最快和最快的方法是使用pipenv(或者如果您是oldschool pip)。

$ pipenv install bethesda-structs

使用git

只需克隆repo并自己构建这个包,就可以使用git安装这个包!

$ git clone https://github.com/stephen-bunn/bethesda-structs.git
$ pipenv install --dev
$ pipenv run python setup.py install

用法

使用bethesda-structs是为了直接直观。
下面是一些分析各种文件类型的简短示例。

esp

分析插件文件的能力对于理解游戏中的添加和更改非常有帮助。
目前only可以向您公开此信息的其他真正工具是TESEdit及其同级应用程序。

此软件包旨在提供对插件的深入细节的简单编程访问!

Because of how long it takes to build complete subrecord parers for a given plugin version, the only currently supported plugins are:

  • ^{tt5}$ - Fallout: New Vegas (partial)
  • ^{tt6}$ - Fallout 3 (partial and experimental)
>>> from bethesda_structs.plugin.fnv import FNVPlugin
>>> plugin = FNVPlugin.parse_file('/media/sf_VMShared/esp/fnv/NVWillow.esp')
>>> print(plugin)
FNVPlugin(filepath='/media/sf_VMShared/esp/fnv/NVWillow.esp')
>>>
>>> # print plugin header (is a record)
...
>>> print(plugin.container.header)
Container:
    type = u'TES4' (total 4)
    data_size = 163
    flags = Container:
        master = True
    id = 0
    revision = 0
    version = 15
    data = b'HEDR\x0c\x00\x1f\x85\xab?\x97\x12\x00\x00#\xad'... (truncated, total 163)
    subrecords = ListContainer:
        Container:
            type = u'HEDR' (total 4)
            data_size = 12
            data = b'\x1f\x85\xab?\x97\x12\x00\x00#\xad\r\x00' (total 12)
            parsed = Container:
                value = Container:
                    version = 1.340000033378601
                    num_records = 4759
                    next_object_id = 896291
                description = u'Header' (total 6)
        Container:
            type = u'CNAM' (total 4)
            data_size = 9
            data = b'llamaRCA\x00' (total 9)
            parsed = Container:
                value = u'llamaRCA' (total 8)
                description = u'Author' (total 6)
        Container:
            type = u'SNAM' (total 4)
            data_size = 16
            data = b'NVWillow v.1.10\x00' (total 16)
            parsed = Container:
                value = u'NVWillow v.1.10' (total 15)
                description = u'Description' (total 11)
        Container:
            type = u'MAST' (total 4)
            data_size = 14
            data = b'FalloutNV.esm\x00' (total 14)
            parsed = Container:
                value = u'FalloutNV.esm' (total 13)
                description = u'Master Plugin' (total 13)
        Container:
            type = u'DATA' (total 4)
            data_size = 8
            data = b'\x00\x00\x00\x00\x00\x00\x00\x00' (total 8)
            parsed = Container:
                value = 0
                description = u'File Size' (total 9)
        Container:
            type = u'ONAM' (total 4)
            data_size = 68
            data = b'V\xe3\x0c\x00\xc3\xe3\x0c\x00\xc4\xe3\x0c\x00\xc5\xe3\x0c\x00'... (truncated, total 68)
            parsed = Container:
                value = ListContainer:
                    844630
                    844739
                    844740
                    844741
                    1372461
                    1372463
                    1383111
                    1385321
                    1387301
                    1387302
                    1387303
                    1387304
                    1387906
                    1457771
                    1479505
                    1520201
                    1544392
                description = u'Overridden Records' (total 18)
>>>
>>> # iterate over KEYM records (only 1 in this plugin)
...
>>> for record in plugin.iter_records('KEYM'):
...     print(record)
...
Container:
    type = u'KEYM' (total 4)
    data_size = 279
    flags = Container:
    id = 17415634
    revision = 0
    version = 15
    data = b'EDID\x17\x00WillowNova'... (truncated, total 279)
    subrecords = ListContainer:
        Container:
            type = u'EDID' (total 4)
            data_size = 23
            data = b'WillowNovacBunga'... (truncated, total 23)
            parsed = Container:
                value = u'WillowNovacBungalowKey' (total 22)
                description = u'Editor ID' (total 9)
        Container:
            type = u'OBND' (total 4)
            data_size = 12
            data = b'\xff\xff\xfc\xff\x00\x00\x01\x00\x04\x00\x00\x00' (total 12)
            parsed = Container:
                value = Container:
                    X1 = -1
                    Y1 = -4
                    Z1 = 0
                    X2 = 1
                    Y2 = 4
                    Z2 = 0
                description = u'Object Bounds' (total 13)
        Container:
            type = u'FULL' (total 4)
            data_size = 27
            data = b'Dino Dee-lite Bu'... (truncated, total 27)
            parsed = Container:
                value = u'Dino Dee-lite Bungalow Key' (total 26)
                description = u'Name' (total 4)
        Container:
            type = u'MODL' (total 4)
            data_size = 23
            data = b'Clutter\\Key01Dir'... (truncated, total 23)
            parsed = Container:
                value = u'Clutter\\Key01Dirty.NIF' (total 22)
                description = u'Model Filename' (total 14)
        Container:
            type = u'ICON' (total 4)
            data_size = 48
            data = b'Interface\\Icons\\'... (truncated, total 48)
            parsed = Container:
                value = u'Interface\\Icons\\PipboyImages\\Ite'... (truncated, total 47)
                description = u'Large Icon Filename' (total 19)
        Container:
            type = u'MICO' (total 4)
            data_size = 66
            data = b'Interface\\Icons\\'... (truncated, total 66)
            parsed = Container:
                value = u'Interface\\Icons\\PipboyImages_sma'... (truncated, total 65)
                description = u'Small Icon Filename' (total 19)
        Container:
            type = u'SCRI' (total 4)
            data_size = 4
            data = b'T.\n\x01' (total 4)
            parsed = Container:
                value = FormID(form_id=17444436, forms=['SCPT'])
                description = u'Script' (total 6)
        Container:
            type = u'YNAM' (total 4)
            data_size = 4
            data = b'\xbb\x10\x07\x00' (total 4)
            parsed = Container:
                value = FormID(form_id=463035, forms=['SOUN'])
                description = u'Sound - Pick Up' (total 15)
        Container:
            type = u'ZNAM' (total 4)
            data_size = 4
            data = b'\xbc\x10\x07\x00' (total 4)
            parsed = Container:
                value = FormID(form_id=463036, forms=['SOUN'])
                description = u'Sound - Drop' (total 12)
        Container:
            type = u'DATA' (total 4)
            data_size = 8
            data = b'\x00\x00\x00\x00\x00\x00\x00\x00' (total 8)
            parsed = Container:
                value = Container:
                    value = 0
                    weight = 0.0
                description = u'Data' (total 4)

牛血清白蛋白

贝塞斯达的默认存档结构。

>>> from bethesda_structs.archive.bsa import BSAArchive
>>> archive = BSAArchive.parse_file('/media/sf_VMShared/bsa/Campfire.bsa')
>>> print(archive)
BSAArchive(filepath=PosixPath('/media/sf_VMShared/bsa/Campfire.bsa'))
>>>
>>> # print archive header
...
>>> print(archive.container.header)
Container:
    magic = b'BSA\x00' (total 4)
    version = 105
    directory_offset = 36
    archive_flags = Container:
        directories_named = True
        files_named = True
    directory_count = 4
    file_count = 493
    directory_names_length = 50
    file_names_length = 14839
    file_flags = Container:
>>>
>>> # print last directory block, containing 1 file record
...
>>> print(archive.container.directory_blocks[-1])
Container:
    name = u'meshes\\mps\x00' (total 11)
    file_records = ListContainer:
        Container:
            hash = 16183754957220078963
            size = 2384
            offset = 25094933
>>>
>>> # print archived filenames (only first 5, 488 more)
...
>>> print(archive.container.file_names)
ListContainer:
    _camp_objectplacementindicatorthread01.psc
    _camp_objectplacementindicatorthread02.psc
    _camp_objectplacementindicatorthread03.psc
    _camp_tentsitlayscript.psc
    campcampfire.psc
    ...
>>>
>>> # extract archive to directory
...
>>> archive.extract('/home/USER/Downloads')

ba2

贝塞斯达的第二个档案结构(用于放射性尘埃4)。
BTDX存档(BA2)比以前的版本BA2更难提取。

两个可用的存档子类型都受支持。

一般(GNRL

用于将通用文件存储在压缩/捆绑文件中。

>>> from bethesda_structs.archive.btdx import BTDXArchive
>>> archive = BTDXArchive.parse_file('/media/sf_VMShared/ba2/CheatTerminal - Main.ba2')
>>> print(archive)
BTDXArchive(filepath=PosixPath('/media/sf_VMShared/ba2/CheatTerminal - Main.ba2'))
>>>
>>> # print archive header
...
>>> print(archive.container.header)
Container:
    magic = b'BTDX' (total 4)
    version = 1
    type = u'GNRL' (total 4)
    file_count = 982
    names_offset = 3600179
>>>
>>> # print first archive file entry
...
>>> print(archive.container.files[0])
Container:
    hash = 153050373
    ext = u'pex' (total 3)
    directory_hash = 1081231424
    offset = 35376
    packed_size = 0
    unpacked_size = 887
>>>
>>> # extract archive to directory
...
>>> archive.extract('/home/USER/Downloads')

直接绘制(DX10

用于存储(特别是)Microsoft Direct Draw纹理。

>>> from bethesda_structs.archive.btdx import BTDXArchive
>>> archive = BTDXArchive.parse_file('/media/sf_VMShared/ba2/AK74m - Textures.ba2')
>>> print(archive)
BTDXArchive(filepath=PosixPath('/media/sf_VMShared/ba2/AK74m - Textures.ba2'))
>>>
>>> # print archive header
...
>>> print(archive.container.header)
Container:
    magic = b'BTDX' (total 4)
    version = 1
    type = u'DX10' (total 4)
    file_count = 116
    names_offset = 329069673
>>>
>>> # print first archive file entry
...
>>> print(archive.container.files[0])
Container:
    header = Container:
        hash = 362144756
        ext = u'dds' (total 3)
        directory_hash = 1416395408
        chunks_count = 4
        chunk_header_size = 24
        height = 2048
        width = 2048
        mips_count = 12
        format = 99
    chunks = ListContainer:
        Container:
            offset = 11136
            packed_size = 2714729
            unpacked_size = 4194304
            start_mip = 0
            end_mip = 0
        Container:
            offset = 2725865
            packed_size = 840614
            unpacked_size = 1048576
            start_mip = 1
            end_mip = 1
        Container:
            offset = 3566479
            packed_size = 217598
            unpacked_size = 262144
            start_mip = 2
            end_mip = 2
        Container:
            offset = 3784077
            packed_size = 71579
            unpacked_size = 87408
            start_mip = 3
            end_mip = 11
>>>
>>> # extract archive to directory
...
>>> archive.extract('/home/USER/Downloads')

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
我们应该在测试java代码时模拟黄瓜测试吗。我们应该在多大程度上使用黄瓜?   Hibernate Weblogic 10.3.4 java。lang.NoSuchMethodError:javax/persistence/spi/PersistenceUnitInfo。getValidationMode()Ljavax/persistence/ValidationMode;   java如何在main()中访问私有静态实例变量   java JMockit无法模拟类的公共final字段   java是否可以返回特定控制器操作的输出(html)?   java如何返回正确类型的列表?   rest-OpenUI/Swagger-java-to-API   java组织。springframework。豆。工厂NoSuchBeanDefinitionException或加载ApplicationContext失败   java使用POST将参数从JSP发送到Servlet   java如何监听特定的按钮按下和主视图用户交互?   java如何让gradle在本地maven repo中覆盖库?   如何在Java中“合并”两个URI?   java如何制作一个方法来移动数组中的字符?   使用来自java的命令启动powershell窗口   java垃圾收集器和匿名类   java如何为CellTable(GWT 2.4)中的ImageResourceCell创建PanelPopup?