Skip to main content

Code libraries for working with Naomi ROMs and EEPROMs.

Project description

naomi

Collection of routines written in Python for manipulating Naomi ROM and EEPROM files. This is geared towards enthusiasts building their own netboot servers or RPI setups and provides libraries for examining ROM and manipulating ROM headers as well as attaching EEPROM settings to ROM files and manipulating their contents. It is fully typed and requires a minimum of Python 3.6 to operate.

NaomiEEPRom

The NaomiEEPRom class provides high-level accessors to a 128-byte Naomi EEPROM dump as obtained through a ROM dumper or from an emulator's saved state. It handles correcting various CRCs as well as allowing high-level access to the duplicated game and system settings sections. Use this to create or manipulate a raw EEPROM data file.

Default Constructor

Takes a single byte argument "data" and verifies that it is a valid 128-byte EEPROM before returning an instance of the NaomiEEPRom class used to manipulate that data. If any of the CRCs do not match this will raise a NaomiEEPRomException.

NaomiEEPRom.default

An alternate constructor that takes a single byte argument "serial" and an optional byte argument "game_defaults" and creates a valid EEPROM based on this data, returning an instance of the NaomiEEPRom class that can be used to manipulate this newly created EEPROM. The serial argument should be exactly bytes and begin with a "B", followed by two characters and finally a digit, as represented by a bytestring. This is a Naomi system restriction. Optionally, a string of bytes can be given in the "game_defaults" section which will be used to determine the length and default values of the game section of the EEPROM.

NaomiEEPRom.validate

A static method that takes a byte argument "data" and checks it for validity. This includes making sure the length is 128 bytes and that all CRCs are correct. Optionally you can pass in the boolean keyword argument "only_system" set to True to only check that the system section is valid. This is useful for validating EEPROMs where the BIOS has written system settings but the game has not yet booted and created its own defaults yet. You can use this function to ensure that passing data to the default constructor will not result in an exception.

data property

An instance of NaomiEEPRom has the "data" property, which returns a bytes object representing the current 128-byte EEPROM. This will have all CRC sections fixed. Use the "data" property to retrieve the EEPROM for writing to a file or sending to a Naomi system after manipulating data using the NaomiEEPRom class. Note that this is read-only, you should not attempt to manipulate the raw data using this property.

serial property

Returns the 4 byte serial that is found in the system section of the EEPROM. This will match a serial given in the NaomiEEPRom.default constructor when it is used. Use this to help determine what game an EEPROM goes with. Note that this is read-only. To modify the serial, create a new EEPROM with that serial. Game settings and system settings are not compatible across games on the Naomi platform.

length property

The length in bytes as an integer of the game section of the EEPROM. If the game section is not valid this return 0 bytes. Otherwise it returns the length of the game section itself. This property is writeable. If you provide it a new value, the game section will be resized to that length. Use this to determine the bounds of the game section as documented below, as well as to resize the game section.

system property

Returns a bytes-like wrapper object representing the system section of the EEPROM. This operates like a bytearray object in Python. That means you can access or mutate any byte or section in the system area using this property. Note that this wrapper object takes care of reading from and writing to both mirrors of the system section in the EEPROM file as well as ensuring that the CRC is correct. Note also that the system section is hard-coded to 16 bytes in length which cannot be modified. This is a system restriction on the Naomi platform. Much like bytes objects in python, accessing a single byte returns an integer in the range of 0-255, but accessing a range returns a bytes object.

A simple example of reading bytes 6-8 of the system section:

eeprom = NaomiEEPRom(somedata)
print(eeprom.system[6:8])  # Will print a bytes object of length 2.

A simple example of writing bytes 10-12 of the system section:

eeprom = NaomiEEPRom(somedata)
eeprom.system[10:12] = b"\x12\x34"

game property

Returns a bytes-like wrapper object representing the game section of the EEPROM. This operates identically to the system property as documented above, only it accesses the game section of the EEPROM. Note that for this to work properly, the game section needs to be initialized by setting the length property on the instance of NaomiEEPRom. If you are manipulating an existing EEPROM file, this property will already be set for you.

Note that this wrapper object includes a valid property which returns if the current section is valid in the EEPROM you are manipulating. This will always be True for the system section. However, if you access the game section on a newly-created EEPROM without setting defaults or a length, the game property's valid property will return False.

An example of verifying that the game section is valid:

eeprom = NaomiEEPRom.default(serial=b"BBG0")
print(eeprom.game.valid)  # Will print "False" as the EEPROM was created without a game section default.
eeprom.length = 20
print(eeprom.game.valid)  # Will print "True" as the EEPROM game section was initialized to be 20 bytes long.

NaomiRom

The NaomiRom class provides high-level accessors to a Naomi ROM header as found at the beginning of a ROM file suitable for netbooting. It handles decoding all sections of the ROM header as well as allowing modification and even creation of new ROM header sections given valid data. Use this if you wish to manipulate or create your own Naomi ROM files form scratch.

Default Constructor

Takes a single byte argument "data" and uses it as the ROM image where the header will be extracted. Note that there is no CRC over the ROM header so any data that is 1280 bytes or longer will appear valid.

NaomiRom.default

An alternate constructor that creates an entirely blank Naomi ROM containing no loaded executable or test sections and no ROM name. Use this when you want to programatically construct a ROM image, such as when you are building a final ROM in a homebrew program you are building for the Naomi platform.

valid property

An instance of NaomiRom has the "valid" property which will be "True" when the ROM passed into the constructor is a valid Naomi ROM and "False" otherwise. This is a read-only property as the vailidity of a ROM is entirely dictated by the data passed into the constructor.

data property

The ROM data, as passed into the constructor for the instance of NaomiRom, or as created when using NaomiRom.default alternate constructor. Note that when any of the following properties are written, the data property will be changed to reflect those settings. Use this to retrieve the updated ROM after you've made adjustments to the values you wish to change.

publisher property

The publisher of this ROM, as a string. When read, grabs the current publisher of the ROM image. When written, updates the publisher to the new string provided.

names property

A dictionary of names indexed by region. Given the current system region, the names that show up here will also be the names that show up in the test menu for a given game. Note that there are the following constants that can be used to index into the names list: NaomiRomRegionEnum.REGION_JAPAN, NaomiRomRegionEnum.REGION_USA, NaomiRomRegionEnum.REGION_EXPORT, NaomiRomRegionEnum.REGION_KOREA, and finally NaomiRomRegionEnum.REGION_AUSTRALIA. Note that the last region, Australia, exists in many ROM files but is not accessible as there is no Australia BIOS for the Naomi platform. When read, grabs a dictionary of names of the ROM given the region. When written, updates the ROM names by region using the dictionary provided.

sequencetexts property

A list of 8 sequence texts that are used by the game for coin insertion messages. Many ROMs only have the first sequence set. When read, grabs all 8 sequence texts and returns a list of them. When written, updates the sequence texts to the new list of strings provided.

defaults property

A dictionary of NaomiEEPROMDefaults instance representing what defaults the BIOS will set in the system EEPROM section when initializing the EEPROM on first boot. Note that this is indexed by the same enumeration as the "names" property. When read, grabs the defaults and returns them. When written, extracts values from the provided NaomiEEPROMDefaults instances and updates the per-region defaults in the ROM accordingly.

date property

A datetime.date instance representing what date the ROM was build and released. When read, returns the current date in the ROM header. When written, updates the date of the ROM with the new datetime.date provided.

serial property

A 4-byte bytestring representing the serial number of the ROM. This is used to tie EEPROM data to the ROM itself and lets the Naomi know when to reset certain defaults. When read, returns the current serial from the ROM header. When written, updates the serial in the ROM header.

regions property

A list of NaomiRomRegionEnum values representing valid regions this ROM will run under. Uses the same region constants as the names property. When read, returns a list of the valid regions this ROM executes under. When written, updates the list of regions the ROM is allowed to execute under. When booting, the Naomi BIOS will check the current region against this list and show an error if the current region is not included in the list.

players property

A list of integers representing the valid number of player configurations that this ROM will boot under. Valid player numbers include 1, 2, 3 and 4. When read, returns a list of all valid number of player configurations that this game will boot with. When written, updates the list of player configurations. When booting, the Naomi BIOS will check the "Number of Players" setting in the system assignments and see if that setting appears in this list.

frequencies property

A list of frequencies that the monitor is allowed to run at for this ROM. This includes the values 15 and 31. On read, returns the list of allowed frequencies. On write, updates the list of allowed frequencies. On boot, the Naomi BIOS will check the current horizontal refresh rate of the system as controlled by a DIP switch and show an error if it isn't in the list of allowed frequencies.

orientations property

A list of strings representing the allowed orientations for the monitor for this ROM. The includes the values "horizontal" and "vertical". On read, returns the list of all acceptable orientations. On write, updates that list based on the provided list of strings. On boot, the Naomi BIOS will check the current "Monitor Orientation" setting in the system assignments and see if that orientation is on this list.

servicetype property

A string value of either "individual" or "common" for the expected service button type for the ROM. On read, returns either "individual" or "common" to represent the current service type selected. On write, updates the service type to match the string provided.

main_executable property

An instance of a NaomiExecutable including sections of the ROM that the Naomi BIOS will copy before executing the ROM, as well as the entrypoint in main RAM that the BIOS will jump to after copying sections. On read, returns the current list of sections to copy as well as the main entrypoint, as encapsulated as an instance of NaomiExecutable. On write, it updates the ROM to the new executable configuration by unpacking the NaomiExecutable instance given.

test_executable property

This property is identical to the main_executable property, except for it represents the code and entrypoint that the Naomi BIOS will use when executing the "Game Test Mode" section of the test menu. It can be similarly read and written.

NaomiSettingsPatcher

The NaomiSettingsPatcher class provides logic for attaching an EEPROM or SRAM configuration file to a Naomi ROM so that it can be written to the EEPROM/SRAM when netbooting that ROM. Note that this is not a supported feature of the Naomi platform, so it uses an executable stub that it attaches to the ROM in order to make this work. If you do not care what executable stub is attached and only want to patch settings into a ROM file, use the get_default_trojan function which will return a bytes object suitable for passing into a NaomiSettingsPatcher constructor.

Default Constructor

Takes a bytes "rom" argument and a bytes "trojan" argument creates an instance of NaomiSettingsPatcher which can attach or retrieve previously-attached EEPROM or SRAM settings in a Naomi ROM file suitable for netbooting. An example of how to initialize this is as follows:

from naomi import NaomiSettingsPatcher, get_default_trojan

patcher = NaomiSettingsPatcher(somedata, get_default_trojan())

data property

The same bytes as passed to the NaomiSettingsPatcher constructor. After calling put_settings() as documented below, this will be updated to the new ROM contents with the settings applied. A recommended workflow is to patch ROMs on-the-fly when netbooting by creating an instance of NaomiSettingsPatcher with the ROM data you were about to send, calling put_settings() with the settings you wish to attach, and then getting the data using this property and sending it down the wire to the Naomi system. Note that you can attach either an EEPROM file (128 bytes) or an SRAM file (32kb) but not both.

serial property

An instance of NaomiSettingsPatcher has the serial property. When read, this will examine the serial of the Naomi ROM passed into the constructor and return the 4 byte serial number, suitable for matching against an EEPROM's system serial. Note that this property is read-only.

rom property

Returns a NaomiRom instance that encapsulates the ROM passed into the patcher. This instance should not be edited, as it will not be read again when performing the patches. Note that this property is read-only.

has_eeprom property

Returns True if the ROM passed into the patcher has an attached EEPROM file. Returns False otherwise.

eeprom_info property

Returns an optional instance of NaomiSettingsInfo if the ROM has a configured EEPROM section. If the ROM does not have a configured EEPROM section, this returns None. The NaomiSettingsInfo instance represents the configuration passed to put_eeprom() on a previous invocation. Note that this property is read-only.

get_eeprom() method

Returns a 128-byte EEPROM bytestring that was previously attached to the Naomi ROM, or None if this ROM does not include any EEPROM settings.

put_eeprom() method

given a bytes "eeprom" argument which is a valid 128-byte EEPROM, ensures that it is attached to the Naomi ROM such that the settings are written when netbooting the ROM image. If there are already EEPROM settings attached to the ROM, this overwrites those with new settings. If there are not already settings attached, this does the work necessary to attach the settings file as well as the writing trojan supplied to the NaomiSettingsPatcher constructor.

Valid EEPROM files can be obtained form a number of places. If you use an emulator to set up system and game settings, then the EEPROM file that emulator writes can usually be supplied here to make your game boot to the same settings. If you use the NaomiEEPRom class to manipulate an EEPROM, the data it produces can also be supplied here to force the Naomi to use the same settings.

Optionally, pass in the boolean keyword argument "enable_sentinel" set to True and the Naomi ROM will re-initialize the settings when netbooting even if the last game netbooted was this game. Use this when iterating over settings that you want to choose so that you can ensure the settings are written. If you do not provide this argument, the default behavior is that settings will not be overwritten when we netboot a game that is already running on the system.

Optionally, pass in the boolean keyword argument "enable_debugging" set to True which forces the Naomi to display debugging information on the screen before booting the game. Use this to see what is actually going on under the hood when using the settings patching feature.

Optionally, pass in the boolean keyword argument "verbose" set to True which forces the put_eeprom() function to output progress text to stdout. Use this if you are making a command-line tool and wish to display information about the patch process to the user.

has_sram property

Returns True if the ROM passed into the patcher has an attached SRAM file. Returns False otherwise.

get_sram() method

Returns a 32k-byte SRAM bytestring that was previously attached to the Naomi ROM, or None if this ROM does not include any SRAM settings.

put_sram() method

given a bytes "settings" argument which is a valid 32k-byte SRAM, ensures that it is attached to the Naomi ROM such that the settings are written when netbooting the ROM image. If there are already SRAM settings attached to the ROM, this overwrites those with new settings. If there are not already settings attached, this does the work necessary to attach the settings file.

Valid SRAM files can be obtained from an emulator that is capable of writing an SRAM file. This only makes sense to use in the context of atomiswave conversions and in a select few Naomi games that store their settings in SRAM such as Ikaruga.

Optionally, pass in the boolean keyword argument "verbose" set to True which forces the put_settings() function to output progress text to stdout. Use this if you are making a command-line tool and wish to display information about the patch process to the user.

naomi.settings

Collection of routines written in Python for safe manipulation of 128-byte Naomi EEPROM files using supplied system definition files. Essentially, given a valid 128-byte EEPROM or a valid 4-byte Naomi ROM serial and a set of system and game definition files, naomi.settings will provide you a high-level representation of valid settings including their defaults, valid values and relationships to each other. Settings editors can be built using this module which work together with naomi.NaomiEEPRom and naomi.NaomiSettingsPatcher to make the settings available when netbooting a game on a Naomi system.

Setting

A single setting, with its name, default, current value, possible allowed values, and any possible relationship to other settings. Note that any relationship, if it exists, will only be to other Setting objects inside a Settings class. Note that you should not attempt to construct an instance of this yourself. You should only work with previously-constructed instances of it as found inside an instance of Settings.

name property

The name of this setting, as a string. This is what you should display to a user if you are developing a settings editor.

order property

The order that this setting showed up in the definition file that created it. Note that if you are implementing an editor, you can safely ignore this as the settings will already be placed in the correct display order.

size property

The size of this setting, as an instance of SettingSizeEnum. The valid values for this are SettingSizeEnum.NIBBLE and SettingSizeEnum.BYTE. Note that if you are developing an editor, you can safely ignore this as the values property will include all valid values that this setting can be set to. You do not have to understand or manipulate this in any way and it is only present so that other parts of the naomi.settings module can do their job properly.

length property

The length in bytes this setting takes up, if the size property is SettingSizeEnum.BYTE. If the size property is instead SettingSizeEnum.NIBBLE then this will always be set to 1. Note that much like the size property if you are implementing an editor you can safely ignore this property for the same rationale as above.

read_only property

Whether this property is read-only or not. Some settings are not modifiable, such as the system serial number. Other settings are only modifiable if other settings are set to some value, such as the "Continue" setting on Marvel vs. Capcom 2 which is dependent on "Event" mode being off. If this property is "False" then this setting is user-editable under all circumstances. If this property is "True" then this setting is never user-editable. If this property is an instance of ReadOnlyCondition then it depends on some other settings for whether it is read-only. You can call the evaluate() method on the instance of ReadOnlyCondition which takes a list of Setting objects (this setting's siblings as found in a Settings object) and returns a boolean. If that boolean is "True", then this setting is currently read-only because of some other setting's value. If the boolean is "False", then the setting is currently editable because of some other setting's value.

In the Naomi Test Mode, settings that are always read-only are hidden completely from the user. Settings which are never read-only are displayed to the user. And settings which are conditionally read-only will be conditionally hidden based on whether they are read-only. It is recommended that your editor perform a similar thing when you display settings. Settings whose read_only property is "False" should always be displayed. Settings whose read_only property is "True" should be completely hidden from the user. Settings whose read_only property is a ReadOnlyCondition should be evaluated and then the setting either grayed out when it is "True" or conditionally hidden from the user.

values property

A dictionary whose keys are integers which the current property could be set to, and whose values are the strings which should be displayed to the user for those value selections. Note that if a setting is always read-only this may instead be None. It is guaranteed to be a dictionary with at least one value whenever a setting is user-editable.

current property

The current integer value that the setting is set to. In order to display the correct thing to a user, you should use this as a key into the values property to look up the correct string to display.

default property

The default value for this setting. Note that under some circumstances, this may not be available and will return None. You can safely ignore this property if you are developing an editor. If you wish to provide a "defaults" button in your editor, it is recommended to instead use the from_serial() or from_rom() method on an instance of SettingsManager which will return you a new SettingsWrapper with default values. This will correctly handle system and game defaults as well as dependendent default settings.

Settings

A class which represents a collection of settings that can be used to manipulate a section of an EEPROM file. Note that you should not attempt to construct this yourself. You should only work with previously-constructed instances of it as found inside an instance of SettingsWrapper.

filename property

The name of the settings definition file that was used to create this collection. Note that this is not a fully qualified path, but instead just the name of the file, like "system.settings" or "BBG0.settings". If you wish to look up the actual file location given this property, use the files property on an instance of SettingsManager.

type property

An instance of SettingType which specifies whether this collection of settings is a system settings section or a game settings section in an EEPROM. Valid values are SettingType.SYSTEM and SettingType.GAME.

settings property

A python list of Setting objects, representing the list of settings that can be mofidied or displayed. You should not assign to this property directly when modifying settings in a settings editor you are implementing. However, you are welcome to modify the properties of each setting in this list directly.

length property

An integer representing how many bytes long the section of EEPROM represented by this collection is. For system settings, this will always be 16 since the system section is hardcoded at 16 bytes. For game settings, this will be determined by the settings definition file that was looked up for the game in question.

SettingsWrapper

A class whose sole purpose is to encapsulate a group of system settings, game settings and the serial number of the game that the system and game settings go with. This is returned by many methods in SettingsManager and taken as a parameter of several more methods in `SettingsManager.

Note that you should not attempt to construct this yourself. You should only work with previously-constructed instances of it as returned by methods in SettingsManager.

serial property

The 4-byte serial of the game this SettingsWrapper instance has been created for.

system

A collection of settings that manipulate the system section of the EEPROM for the game this instance has been created for. This is inside of a Settings wrapper object.

game

A collection of settings that manipulate the game section of the EEPROM for the game this instance has been created for. This is inside of a Settings wrapper object.

to_json() method

Converts the current instance of SettingsWrapper to a dictionary suitable for passing to json.dumps. This is provided as a convenience wrapper so that if you are implementing a web interface you don't have to serialize anything yourself. To unserialize a dictionary that you get from this method, call the from_json method on an instance of SettingsManager.

SettingsManager

The SettingsManager class manages the ability to parse a 128-byte EEPROM file given a directory of settings definitions. It is responsible for identifying the correct files for patching given an EEPROM or ROM serial. It is also responsible for taking a modified list of settings and writing a new EEPROM file.

Note that default definitions are included with this module. To grab the default definitions directory, use the get_default_settings_directory function which will return a fully qualified path to the settings directory of this module.

Note that since this is parsing user-supplied settings definitions files, there can be errors in processing those files. In any function that returns a SettingsWrapper instance, a SettingsParseException can be thrown. This is a subclass of Exception so you can get the error message to display to a user by calling str() on the exception instance. The instance will also have a filename property which is the filename of the settings definition file that caused the problem.

There can also be problems in saving EEPROM settings given the same definitions files. In this case, a SettingsSaveException can be thrown. This is identical to SettingsParseException save for the source, so all of the above documentation applies.

There can also be problems in deserializing JSON data when calling the from_json() method. In this case, a JSONParseException can be thrown. Similar to the above two exceptions, calling str() on the instance will give you back an error message that can be displayed to a user. The instance will also have a context property which is the exact location in the JSON where the failure occured as represented by a list of attributes that were dereferenced in the JSON to get to the section that had an error.

Default Constructor

Takes a single string argument "directory" which points at the directory which contains settings definition files and returns an instance of the SettingsManager class. In this repository, that directory is naomi/settings/definitions/. Note that the settings definitions in this repository can be found by using the get_default_settings_directory function. An example of how to initialize this is as follows:

from naomi.settings import get_default_settings_directory, SettingsManager

dir = get_default_settings_directory()
man =  SettingsManager(dir)

files property

An instance of SettingsManager has the "files" property, which returns a dictionary of recognized settings definitions in the directory supplied to the default constructor. The returned dictionary has keys representing the settings definition file, such as "system.settings" or "BBG0.settings". The values of the dictionary are fully qualified system paths to the file in question.

from_serial() method

Takes a single bytes argument "serial" as retrieved from Naomi ROM header and uses that to construct a SettingsWrapper class representing the available settings for a game that has the serial number provided. This can be used when you want to edit settings for a game but do not have an EEPROM already created. This will read the definitions files and create a SettingsWrapper with default settings. This can be then passed to the to_eeprom() function to return a valid 128-byte EEPROM representing the default settings.

from_rom() method

Takes a NaomiRom instance argument "rom" and a NaomiRomReginEnum argument "region" and retrieves any requested system defaults from the Naomi ROM header. It uses that as well as the game's settings definition file to create a default EEPROM that is then used to construct a SettingsWrapper class repressenting the default settings as a Naomi would create them on first boot. This can then be edited or passed to the to_eeprom() function to return a valid 128-byte EEPROM representing the edited settings.

from_eeprom() method

Takes a single bytes argument "data" as loaded from a valid 128-byte EEPROM file or as grabbed from the data property of an instance of NaomiEEPRom and constructs a SettingsWrapper class representing the available settings for a game that matches the serial number provided in the EEPROM file. This can be used when you want to edit the settings for a game and you already have the EEPROM file created. This will read the definitions file and parse out the current settings in the EEPROM and return a SettingsWrapper with those settings. This can then be modified and passed to the to_eeprom() function to return a valid 128-byte EEPROM representing the current settings.

from_json() method

Takes a single dictionary argument "jsondict" and deserializes it to a SettingsWrapper instance. The dictionary argument can be retrieved by calling the to_json() method on an existing SettingsWrapper instance. This is provided specifically as a convenience method for code wishing to provide web editor interfaces. A recommended workflow is to create an instance of SettingsManager, request a SettingsWrapper by calling either from_eeprom() or from_serial() as appropriate, calling to_json() on the resulting SettingsWrapper class and then passing that to json.dumps to get valid JSON that can be sent to a JS frontend app. After the frontend app has manipulated the settings by modifying the current value of each setting, you can use json.loads to get back a dictionary that can be passed to this function to get a deserialized SettingsWrapper class. The deserialized SettingsWrapper instance can then be passed to the to_eeprom() function to return a valid 128-byte EEPROM representing the settings chosen by the JS frontend.

to_eeprom() method

Given an instance of SettingsWrapper returned by either from_serial(), from_eeprom() or from_json(), calculates and returns a valid 128-byte EEPROM file that represents the settings. Use this when you are finished modifying system and game settings using code and wish to generate a valid EEPROM file that can be modified with NaomiEEPRom, placed in an emulator's data directory to load those settings or attached to a Naomi ROM using the naomi.NaomiSettingsPatcher class so that the settings are written when netbooting the rom on a Naomi system.

Settings Definitions Format

Settings definition files are meant to be simple, human readable documentation for a game's EEPROM settings. They are written in such a way that on top of being human-readable documentation, they can also be parsed by naomi.settings.SettingsManager to help with making settings editors for any game on the Naomi platform. Each setting in a settings definition file represents how to parse some number of bytes in a game's EEPROM. You'll notice that while there is a size specifier for each setting there is no location specifier. That's because each setting is assumed to come directly after the previous setting in the section.

All settings sections in an game's EEPROM are assumed to be little-endian, much like the Naomi system itself. Defaults and valid values are specified as hex digits as copied directly out of a hex editor. When specifying half-byte settings, the first setting is assumed to be the top half of the byte (the first hex digit that appears when reading the EEPROM in a hex editor) and the second setting is assumed to be the bottom half of the byte. All half-byte settings are expected to come in pairs.

Aside from the "system.settings" file, all settings files are named after the serial number of the game they are associated with. The serial number for the game can be found by looking at the ROM header using a tool such as rominfo, or by looking at bytes 3-7 of an EEPROM that you got out of an emulator and loaded into a hex editor.

The only necessary parts of a setting are the name and the size. If the setting is user-editable, there should be at least one valid value that the setting is allowed to be. Optionally, you can specify the default value for any setting and whether the setting is read-only. Additionally, read-only and default values can depend on the value of another setting.

Settings are defined by writing any valid string name followed by a colon. Setting parts come after the colon and are either comma-separated or are placed one per line after the setting name. You can mix and match any number of comma-separated parts and parts on their own lines. Whatever makes the most sense and is the most readable is allowed. Settings parts can show up in any order after the setting name. You can define size, read-only, defaults and valid options in any order you wish. The only restriction is that the size part MUST appear before any default parts.

Any line in a settings definition file that starts with a hashtag (#) is treated as a comment. You can write anything you want in comments so feel free to write down any useful information about settings you think somebody else might care to know.

A Simple Setting

The most basic setting is one that has a name, a size and some allowed values. An example of such a setting is like so:

Sample Setting: byte, values are 1 to 10

This defines a setting named "Sample Setting" which is a single byte and can have the hex values 01, 02, 03, 04, 05, 06, 07, 08, 09 and 0a. Editors that display this setting will display a drop-down or selection box that includes the decimal values "1", "2", "3", "4", "5", "6", "7", "8", "9", and "10". The decimal values for each valid setting is automatically inferred based on the range given in the setting.

If you want to specify some alternate text for each valid setting, you may do so like so:

Sample Setting: byte, 1 - On, 0 - Off

This defines a setting named "Sample Setting" which is a single byte and can have the hex values 01 and 00 applied to it. Editors that display this setting will display a drop-down or selection box that includes the value "On" and "Off" and will select the correct one based on the value in the EEPROM when it is parsed.

You can mix and match how you define settings values if it is most convenient. For example, the following setting mixes the two ways of specifying valid values:

Sample Setting: byte, 0 - Off, 1 to 9, 10 - MAX

This defines a setting named "Sample Setting" which is a single byte and can have the hex values 00, 01, 02, 03, 04, 05, 06, 07, 08, 09 and 0a. Editors that display this setting will display a drop-down or selection box that includes the options "Off", "1", "2", "3", "4", "5", "6", "7", "8", "9", "MAX". The correct one will be selected based on the value in the EEPROM when it is parsed.

Changing the Setting Display

Normally, if you have some number of values that a setting can be and you want to control what an editor displays when selecting each value, you would list each value out individually along with the text it should be displayed as. However, if you have a large range of values and you want to display them in hex instead of decimal, you can instead do the following:

Sample Setting: byte, values are 1 to 10 in hex

This defines a setting named "Sample Setting" which is a single byte and can have the hex values 01, 02, 03, 04, 05, 06, 07, 08, 09 and 0a. This is identical to the simple setting in the previous section. However, editors that display this setting will display a drop-down or selection box that includes the options "01", "02", "03", "04", "05", "06", "07", "08", "09" and "0a". You could have written the settings out individually, but for large ranges that you want to display in hex this is faster.

Changing the Setting Size

If your setting spans more than 1 byte, or it is only the top half or bottom half of a byte, you can specify that in the size part. For settings that occupy more than 1 byte, you can simply write the number of bytes in the part section. If a setting only occupies the top or bottom half of a byte, you can specify a half-byte for the size.

An example of a setting that takes up 4 bytes is as follows:

Big Setting: 2 bytes, 12 34 - On, 56 78 - Off

This defines a setting named "Big Setting" that takes up two bytes and has the two hex values 12 34 and 56 78 as read in a hex editor as its options. Editors will display either "On" or "Off" as they would for 1 byte settings.

An example of a pair of settings that take up half a byte each is as follows:

Small Setting 1: half-byte, values are 1 to 2
Small Setting 2: half-byte, values are 3 to 4

This defines two settings named "Small Setting 1" and "Small Setting 2". Each setting takes up half a byte. The first setting, "Small Setting 1", will take the top half of the byte, and the second, "Small Setting 2", will take the bottom half of the byte. The hex values for each are the same as they would be for all other documented settings. Note that the settings came in a pair because you have to specify both halves of the byte!

Specifying Read-Only Settings

Sometimes there is a setting that you can't figure out, or there's a setting that the game writes when it initializes the EEPROM but never changes. In this case you can mark the setting read-only and editors will not let people see or change the setting. However, the setting will still be created when somebody needs to make a default EEPROM based on the settings definition file.

An example of how to mark a setting as read-only:

Hidden Setting: byte, read-only

In this case, there is a setting named "Hidden Setting" which is a single byte. We specified that it was read-only, so editors will not display the setting to the user. Also, since it was read-only, we didn't need to specify any allowed values. You can use this when there are parts of the EEPROM you don't want people to mess with, or that you don't understand so you just need to skip it.

Sometimes there are settings that only display in some scenarios, such as when another setting is set to a certain value. If you run into a setting such as this, you can specify that relationship like so:

Sometimes Hidden Setting: byte, read-only if Other Setting is 1, values are 0 to 2

This defines a setting called "Sometimes Hidden Setting" which is a single byte and can have the hex values 00, 01 and 02. When another setting named "Other Setting" is set to 1, this setting becomes read-only and cannot be modified by the user. When that other setting named "Other Setting" is set to any other value, this setting becomes user-changeable.

If you want to specify that a setting is read-only unless another setting is a certain value, you can do so like the following:

Sometimes Hidden Setting: byte, read-only unless Other Setting is 1, values are 0 to 2

This defines the same setting as the first example, but the read-only logic is reversed. This setting will be read-only when "Other Setting" is any value but 1, and will be user-changeable when "Other Setting" is 1.

If you need to specify multiple values for the other setting, you can do so like so:

Sometimes Hidden Setting: byte, read-only if Other Setting is 1 or 2, values are 0 to 2

This defines the same setting as the first example, but the read-only logic is changed. The setting will be read only when "Other Setting" is 1 or 2, and will be user-changeable when "Other Setting" is any other value.

Specifying Defaults

Its nice to specify what the default for each setting is. This way, editors can make a new EEPROM from scratch for the game you are defining without needing an EEPROM to exist first. If you don't specify a default, the default for the setting is assumed to be 0. If that isn't a valid value for a setting, you'll run into problems so it is best to define defaults for settings when you can.

To specify a default, you can do the following:

Default Setting: byte, default is 1, values are 1, 2

This defines a setting named "Defaut Setting" which is a single byte and whose valid values are 01 and 02. The default value when creating an EEPROM from scratch is 01.

If a setting is read-only, then when we an EEPROM is edited and saved, the default value will take precidence over the current value. If a setting is user-editable, then the current value will take precidence over the default value. This is so that you can have settings which are optionally read-only based on other settings and specify what value the setting should be when it is read-only. This isn't often necessary but it can come in handy in some specific scenarios.

For example, in Marvel Vs. Capcom 2, the "Continue" setting is defaulted to "On". However, if event mode is turned on, then the "Continue" setting is forced to "Off" and becomes no longer user-editable. To represent such a case as this, you can do something like the following:

Event: byte, default is 0
  0 - Off
  1 - On
Continue: byte, read-only if Event is 1, default is 1 if Event is 0, default is 0 if Event is 1
  0 - Off
  1 - On

This can be a bit daunting to read at first, so let's break it down. First, it defines a setting named "Event" which is a byte and can have values 00 and 01. Those values are labelled "Off" and "On" respectively. Event mode is off by default. Then, it defines a setting named "Continue" which is a byte as well. It has values 00 and 01 labelled "Off" and "On" respectively. It is user-editable when event mode is off, and it is read-only when event mode is on. When event mode is off, the default is 01, which corresponds to "On". When event mode is on, the default is "00" which corresponds to "Off". Remember how settings that are read-only try to save the default first, and settings that are user-changeable try to save the current value first? That's where the magic happens. When the "Event" setting is set to "On" then the "Continue" setting is read-only, so we will save the default hex value of 00! When the "Event" setting is set to "Off", the "Continue" setting is user-changeable so we will save whatever value the user selected! When we create a new EEPROM from scratch, we set "Event" to 00 which tells the "Continue" setting to default to 01. It all works perfectly!

Specifying Entirely-Dependent Defaults

Sometimes you might run into a setting that seems to be identical to another setting, or a setting that seems to be the same as another setting plus or minus some adjustment value. If you encounter such a relationship, you can represent it by doing something like the following:

Setting: byte, default is 0, values are 1 to 10
Dependent Setting: byte, read-only, default is value of Setting

This defines a setting named "Setting" which is a single byte that can have hex values 01, 02, 03, 04, 05, 06, 07, 08, 09 and 0a. It defines a second setting named "Dependent Setting" which defaults to whatever "Setting" is set to. Since it is read-only, the default will take precidence over the current value, so when somebody edits "Setting" in an editor, both "Setting" and "Dependent Setting" will be saved with the same value!

In some cases, a setting will be dependent on another setting, but won't have the exact same value. If you wanted to, you could list out a whole bunch of default conditionals to represent all of the possibilities, like so:

Setting: byte, default is 0, values are 1 to 3
Dependent Setting: byte, read-only
  default is 0 if Setting is 1
  default is 1 if Setting is 2
  default is 2 if Setting is 3

This would work, and sets up "Dependent Setting" to be 00 when Setting is 01, 01 when Setting is 02, and 02 when Setting is 03. However, if there are a lot of possible values for "Setting", this can get tedious. Instead, you can represent the relationship like so:

Setting: byte, default is 0, values are 1 to 3
Dependent Setting: byte, read-only, default is value of Setting - 1

This defines the exact same pair of settings, with the exact same defaults!

Specifying an Alternate Display Order

Normally settings are displayed in exactly the order the show up in the file. Sometimes settings show up in a different order in a game's test menu than they appear in the EEPROM file itself. You can't just rearrange the order that the settings appear in the definition file since that dictates the order that the settings themselves are processed. So, instead you can specify that a setting should be displayed before or after another setting. Here is an example:

Simple Setting: byte, values are 1 to 10
Other Setting: byte, values are 2 to 5, display before Simple Setting

This defines two settings named "Simple Setting" and "Other Setting". While "Simple Setting" comes first when parsing the EEPROM itself, when it comes time to display the settings in an editor, "Other Setting" will be displayed first and then "Simple Setting".

Similarly, you can specify that a setting come after another setting like so:

Simple Setting: byte, values are 1 to 10, display after Other Setting
Other Setting: byte, values are 2 to 5

Both the above examples produce the exact same list of settings in an editor.

Using ":" or "," in Setting Names or Values

Since these are special characters used to figure out where a setting name ends as well as separate sections, using one of these characters in a setting name or value description will result in an error. In order to have a setting that includes one of these symbols, you can escale it like so:

Setting With A Colon\: The Revengence: byte, 1 - Good\, Very Good, 2 - Bad\, Very Bad

This defines a setting named "Setting With a Colon: The Revengence" that has two labelled values consisting of "Good, Very Good" and "Bad, Very Bad". Whenever you need to use a character that is special, prefix it with a "\". This includes the "\" character as it denotes that the next character should be escaped. So if you want a "\" character in your setting name or value, you should use two "\" characters in a row.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

naomiutils-0.5.4.tar.gz (105.7 kB view hashes)

Uploaded Source

Built Distribution

naomiutils-0.5.4-py3-none-any.whl (89.8 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page