Skip to content

Instantly share code, notes, and snippets.

@SomeCrazyGuy
Created March 1, 2023 17:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SomeCrazyGuy/9760ed54895009cf3e3f9cda10609a8d to your computer and use it in GitHub Desktop.
Save SomeCrazyGuy/9760ed54895009cf3e3f9cda10609a8d to your computer and use it in GitHub Desktop.
predicted Starloader public API
#ifndef MOD_API_H
#define MOD_API_H
#include <stdint.h>
/** (chatgpt generated documentation)
These macros define functions for extracting the different parts of a software version number.
The version number is assumed to be passed in as an unsigned 32 bit integer `VERSION`, where
each part of the version (major, minor, patch, and revision) is stored as one byte.
The macros use bitwise operations to extract each part of the version number. The >> operator
is used to shift the bits of VERSION to the right, so that the relevant part of the version
number is in the least significant byte. The & operator is used to mask out all the bits except
for the relevant byte. Finally, the result is cast to unsigned char to ensure it is stored as
an 8-bit integer.
The ModAPI struct provides version information for starloader and starfield
*/
#define VERSION_GET_MAJOR(VERSION)(unsigned char)(((VERSION)>>24)&0xFF)
#define VERSION_GET_MINOR(VERSION)(unsigned char)(((VERSION)>>16)&0xFF)
#define VERSION_GET_PATCH(VERSION)(unsigned char)(((VERSION)>>8)&0xFF)
#define VERSION_GET_REVISION(VERSION)(unsigned char)((VERSION)&0xFF)
/// The MAKE_VERSION macro takes four arguments: MAJOR, MINOR, PATCH, and REVISION.
/// It returns a 32-bit unsigned integer that represents a software version.
/// Each component is masked with 0xFF to ensure only the least significant 8 bits are used,
/// and then shifted to the appropriate position within the 32-bit integer. The result is the
/// combined version number, which can be used to identify the version of the software.
/// Use this macro to specify your mod version
#define MAKE_VERSION(MAJOR, MINOR, PATCH, REVISION) ((uint32_t)((((MAJOR)&0xFF)<<24)|(((MINOR)&0xFF)<<16)|(((PATCH)&0xFF)<<8)|(((REVISION)&0xFF)<<0)))
/// this macro stores the current version of the modinfo struct
#define MODINFO_VERSION MAKE_VERSION(0,1,0,0)
/// this macro stores the current version of starloader
#define STARLOADER_VERSION MAKE_VERSION(0,1,0,0)
/// The main interface for a mod to interact with the mod loader
struct ModAPI;
/// Provides functions for saving and loading mod configuration from disk
struct ModAPI_Config;
/// A lightweight UI framework for use by dll mods without linking with imgui
struct ModAPI_UI;
/// An interface for getting information about loaded mods
struct ModAPI_Loaded;
/// An interface for providing and locating APIs exposed by mods
struct ModAPI_RPC;
///A struct containing information about the mod, used by the mod loader
struct ModInfo;
#if 0
/** (chatgpt generated documentation)
The NativeModInit function is the entry point for a your mod and is loaded by a starloader.
This function must be implemented by the mod author in a dynamic library(DLL) and is responsible
for initializing the mod and returning information about it to the modloader.
The function takes as its argument a pointer to a ModAPI structure, which provides access to various
services and functionality provided by the modloader.
The return value of NativeModInit is a pointer to a ModInfo structure, which provides information about
your mod to starloader. This structure includes the mod's name, version, and other relevant data that
starloader uses to manage the mod.
By implementing NativeModInit, mod authors ensure that their mod can be loaded and initialized by starloader,
and that the modloader can properly manage and interact with the mod. This function is crucial for ensuring
compatibility and seamless integration between the mod and starloader.
*/
///in your mod's dll, you must implement the following function with this exact signature
extern "C" __declspec(dllexport) const struct ModInfo *NativeModInit(const struct ModAPI *api);
#endif
struct ModAPI {
/// Mod API version represented as a 32-bit unsigned int.
/// Use the version helper defines to unpack or compare directly.
/// This variable is always the first struct member to allow
/// incompatible dll mods to exit gracefully.
uint32_t mod_api_version;
/// Game version represented as a 32-bit unsigned int.
/// Use the version helper defines to unpack or compare directly.
uint32_t game_version;
/// Logging function for your mod.
/// Uses the same format specifiers as printf()
/// Do not use from a separate thread.
/// NOTE: the total length of the expanded format string is limited to 4096 bytes
void(*Log)(const char* format, ...);
/// A simple function to get a pointer + offset from the base address.
/// Think `GetModuleHandle(NULL) + pointer arithmetic`.
void*(*GetGameOffset)(uint64_t offset);
/// Queue a longer running task to run on a separate thread
/// task must return an exit code from 0-255
/// task_handle is initialized to -1 (task still running)
/// when task completes, task handle is updated to the 0-255 return value
/// if task_handle < -1, an error occurred
void(*QueueTask)(unsigned char(*task)(void), int* task_handle);
};
/** (chatgpt generated documentation)
The ModAPI_Config is a C-style interface for loading and reading persistent configuration data for a mod.
It provides four functions for reading values from the configuration file:
GetConfigInteger, GetConfigDouble, GetConfigString, and GetConfigBuffer.
The values read from the file are stored in the out pointers that are passed as arguments to these functions.
This interface allows mod developers to save and load their mod's state in a flexible and convenient way,
without having to handle the complexities of reading and writing to the disk themselves.
The `variable_name` parameter is the name of the configuration value that you are trying to retrieve.
It is used as a key to look up the value in the configuration file. Key names are namespaced to your
ModInfo mod_name, so no need to worry about making your values globally unique.
The `out` parameter is a pointer to the location where the retrieved configuration value will be stored and saved.
When calling one of the functions from the ModAPI_Config struct, you pass in a pointer to a variable you want the
retrieved value to be stored. The `out` parameter must have static or heap storage and must be in scope for the
life of the program, starloader will periodically read and save your out variables automatically.
The `default_value` parameter is used to specify the default value to be used if the requested configuration value
cannot be found in the configuration file. If the requested variable_name is not found, the function will store
the default value in the out parameter.
*/
struct ModAPI_Config {
/// Read an integer value from the config file, or use the default value
void(*GetConfigInteger)(const char* variable_name, int *out, int default_value);
/// Read a double value from the config file, or use the default value
void(*GetConfigDouble)(const char* variable_name, double *out, double default_value);
/// Read a string value from the config file, or use the default value.
/// The string must not contain '"' or control characters '\r', '\n', etc...
void(*GetConfigString)(const char* variable_name, const char **out, const char *default_value);
/// Read a buffer of data from the config file, or use the default value.
/// This function requires a size parameter to know the size of the default
/// buffer and return the size of the buffer from the config file.
/// there are no restrictions on what type of data can be stored in a buffer
void(*GetConfigBuffer)(const char* variable_name, void **out, unsigned *out_size, void *default_value, unsigned default_size);
};
/** (chatgpt generated documentation)
The struct ModAPI_UI is a part of an API for user interface in a mod. It provides a set of
functions for creating different types of user interface elements in the mod, such as
separators, labels, buttons, checkboxes, radio buttons, text inputs, and numerical inputs.
This simplified UI API allows dll mods to draw simple user interfaces without needing to
link with imgui. Internally these calls use imgui, but a future SFSE could wrap these to
present a game-native ui and mod menu.
*/
struct ModAPI_UI {
///draw a separator line
void(*Separator)(void);
///display text
void(*Text)(const char* label);
///show a button, returns true when button is clicked
unsigned char(*Button)(const char *label);
///checkbox, returns true while checked, requires a variable to hold state
unsigned char(*Checkbox)(const char *label, unsigned char *state);
///radiobutton, returns true while selected, requires a state integer per group
unsigned char(*RadioButton)(const char* label, int *state, int current);
///text input, returns true when enter is pressed
unsigned char(*InputText)(const char *label, char* buffer, unsigned buffer_size);
///int input, returns true when changed
unsigned char(*InputInt)(const char *label, int *value, int min, int max, int step);
///float input, returns true when changed
unsigned char(*InputFloat)(const char *label, float *value, float min, float max, float step);
};
/** (chatgpt generated documentation)
The ModAPI_Loaded struct provides two functions to query information about
the currently loaded mods in the system: `GetLoadedModCount` and
`GetLoadedModInfo`.
`GetLoadedModCount` retrieves the number of currently loaded mods.
`GetLoadedModInfo` retrieves the ModInfo structure for a particular mod
specified by its id. The id should be a value between 0 and the value
returned by GetLoadedModCount()-1. The returned ModInfo structure contains
information about the mod such as its name, version, and description.
*/
struct ModAPI_Loaded {
///retrieve the number of loaded mods
unsigned(*GetLoadedModCount)(void);
///retrieve the ModInfo for a particular mod by its index
const struct ModInfo*(*GetLoadedModInfo)(unsigned mod_number);
};
struct ModAPI_RPC {
/* (chatgpt generated documentation)
ProvideInterface is a function pointer that allows mods to provide an interface to other mods.
The interface should be a struct that contains function pointers, similar in structure to this ModAPI_RPC struct.
If your mod provides an interface, it should have a header file available for other mods to use.
The first argument, `interface_id`, is a string that identifies the interface.
It is recommended that the `interface_id` string only contain lowercase ASCII letters, underscore characters,
and end with an API version number (e.g. "my_interface_v1").
The second argument, `interface_api`, is a pointer to the data your mod provides.
For consistency, it is recommended to provide a pointer to a struct containing function pointers
similar to the interfaces provided by starloader
*/
void(*ProvideInterface)(const char* interface_id, const void* interface_api);
/* (chatgpt generated documentation)
LocateInterface is a function pointer that allows mods to locate an interface provided by another mod.
The argument, `interface_id`, is a string that identifies the interface being sought.
The return value is a void pointer to the struct that contains the function pointers for that interface.
LocateInterface returns NULL if the interface could not be found
*/
const void*(*LocateInterface)(const char* interface_id);
};
enum RequestType {
// no action
REQUEST_NONE = 0,
// request the mod stop all activity
REQUEST_STOP,
// request a mod restart, or start after a previous stop request
REQUEST_RESTART,
};
struct ModInfo {
/*
`modinfo_version` is the version of the `ModInfo` struct that you are using.
It is important to keep this field up to date so that your mod will continue
to be compatible with the latest version of starloader.
This field is required to be non-zero for your mod to be loaded.
*/
unsigned modinfo_version;
/*
`mod_version` is the version of your mod.
This field should be updated whenever you release a new version of your mod.
This field is required to be non-zero for your mod to be loaded.
*/
unsigned mod_version;
/*
`mod_name` is the name of your mod.
It is recommended to keep the name short (preferably less than 32 characters)
and to only use ASCII characters.
This field is required to be non-null for your mod to be loaded.
*/
const char * mod_name;
/*
`mod_description` is a brief description of your mod.
It is recommended to keep the description concise (2-3 sentences) and informative.
This field is required to be non-null for your mod to be loaded.
*/
const char * mod_description;
/*
`mod_author` is the name of the person who created the mod.
This field is required to be non-null for your mod to be loaded.
*/
const char * mod_author;
/*
`mod_url` is the URL for the mod's page on a website like Nexus Mods.
This field is optional, but recommended, as it provides a way for users
to find additional information about your mod.
*/
const char * mod_url;
/*
`source_url` is the URL for the mod's source code repository (e.g. on GitHub).
This field is optional, but recommended, as it provides a way for users to view
the source code and contribute to the development of your mod.
*/
const char * source_url;
/*
The following callbacks are used to integrate with the mod loader
these pointers may be set to NULL to indicate that your mod does not
use the corresponding feature.
*/
/// Called once after your mod's DLL is loaded.
/// Use this callback to load or save any persistent state.
void(*OnConfigure)(const struct ModAPI_Config *config_api);
/// Called once after all mod DLLs have been initialized.
/// Use this callback to resolve inter-mod dependencies.
void(*OnLoad)(const struct ModAPI_Loaded *loaded_api);
/// Called once after OnLoad.
/// Use this callback to register any interfaces that your mod provides.
void(*OnInterfaceProvide)(const ModAPI_RPC *rpc_api);
/// Called once after OnInterfaceProvide.
/// Use this to locate any interfaces that your mod uses.
void(*OnInterfaceLocate)(const ModAPI_RPC *rpc_api);
/// Called every frame, even when the mod UI is not showing.
void(*OnPresent)(void);
/// Called every frame when the mod UI is showing and your mod is focused
/// Use the `ui_api` to provide a simple ui interface without linking to imgui
/// Use `imgui_context` to draw more complex interfaces using ImGui directly.
/// to draw with imgui, you must link with ImGui and call imgui::setcurrentcontext()
/// for consistency, use only one of the provided gui interfaces
void(*OnDraw)(const struct ModAPI_UI * ui_api, void * imgui_context);
/// starloader provides a few options for the user to manage a mod at runtime
/// if possible, handle a stop request, but there are no hard requirements
/// these are just requests, there is no return value to report sucess or failure.
void(*OnRequest)(enum RequestType request);
};
#endif //MOD_API_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment