Code Insights - Tkachov/ALERT GitHub Wiki

dat1lib

To increase speed of development, dat1lib/__init__.py walks through its types/ and types/sections/ subdirectories to find all the modules that are there. In these modules, it gathers all classes that have MAGIC field into possible asset types classes map, and all classes derived from Section with TAG field into possible sections classes map.

dat1lib.read() tries to use appropriate class based on magic in the file given. DAT1 constructor creates corresponding section objects based on their tags, passing the data read from the file (and also providing reference to self, so sections could communicate with each other or, for example, access DAT1 strings block).

This allows adding new classes by simply defining them in module of any name within types/ directory.

Sections

Base Section class is defined in types/sections/__init__.py, along with a few generic subclasses such as SerializedSection or ReferencesSection.

All sections are supposed to be derived from base Section class and have TAG set to correct section tag.

save() method can be implemented if section knows how to serialize itself back into game's format.

For Assets Browser, sections can also implement:
print_verbose() — method that prints text instead of displaying hex representation of the section;
web_repr() — method that also specifies section user-friendly name and can pass additional parameters that determine how section will appear.

Typically, in constructor of a section, additional comments about section and its format can be given. This is also where brief stats are given: for every game, how many assets contain this section, what is min, max and average size of those sections, whether they always come first or last in the file and a few asset IDs where this section can be found in.

Versions

Because ALERT aims to support assets from different versions of Insomniac Games' engine, there is a dat1lib.VERSION_OVERRIDE that can be set to force code to treat assets or sections in specific way. Some of them can deduct the format (based on sizes or other markers), but sometimes this external tip is needed.

Version override is passed as version argument of assets classes, and they should pass it down to DAT1, which, in turn, passes it to its sections.

Assets Browser

Assets Browser is in server/, backend being in server/state/ and frontend in server/static/.

Backend uses Flask, and starts from State class. It creates all its submodules and passes them reference to self, so they could communicate with each other if needed. It also provides some commonly used methods.

To reference an asset, Locator class is used. It parses "0/ABCD" and "stage/path" notations, so Assets Browser can work with in-game assets and real files from stages directories in similar way.

To increase speed of the app, there are caches for assets classes, assets raw data and textures mipmaps. If they were recently accessed, next access (cache hit) would be much faster than loading asset from scratch.

Every submodule of State can add its API routes for frontend to use. Typically they are made using helper methods from api_utils.py.

Frontend is in vanilla JS. All "modules" are included in index.html, and have a corresponding declared global variable in app.js. This way, controller and the modules can communicate with one another.

Modules are split similarly to backend modules, and use corresponding API routes. UI is mostly generated in runtime. Also, Assets Browser opens most viewers in separate "windows", which are made via windows module.