Theme
Config and paths
The on-disk layout: the main scripthook.ini, one folder per plugin, and a single logs directory.
text
<gamedir>/
├── GRW.exe
├── dinput8.dll
├── scripthook.ini main config
├── logs/ every log file
└── plugins/<name>/
├── <name>.asi
└── <name>.ini the plugin's own configEvery path is anchored to the folder holding GRW.exe, so it stays correct no matter what the working directory is.
| Export | Summary |
|---|---|
ShConfigInit | Parse scripthook.ini. |
ShConfigGetInt | Integer setting from the main config; def when missing. |
ShConfigGetBool | Boolean setting: 1/0, true/false, yes/no, on/off. |
ShConfigGetStr | String setting; copies the value or def. |
ShLogLevel | The [Settings] LogLevel in force, as one of the SH_LOG_* values: 0 none, 1 error, 2 warn, 3 info, 4 debug. |
ShConfigSetStr | Write a value back to scripthook.ini. |
ShConfigSetInt | See ShConfigSetStr. |
ShConfigSetBool | See ShConfigSetStr. |
ShPluginConfigGetStr | A plugin's own ini, read and written by section. |
ShPluginConfigGetInt | See ShPluginConfigGetStr. |
ShPluginConfigGetBool | See ShPluginConfigGetStr. |
ShPluginConfigSetStr | See ShPluginConfigGetStr. |
ShPluginConfigSetInt | See ShPluginConfigGetStr. |
ShPluginConfigSetBool | See ShPluginConfigGetStr. |
ShGameDir | The folder containing GRW.exe, no trailing backslash. |
ShFrameworkDir | WildM : the folder holding the framework DLL (dinput8.dll), no trailing backslash. |
ShPluginsDir | <gamedir>\plugins\ (with trailing backslash); every .asi plugin lives in its own folder under it. |
ShScriptsDir | Compatibility alias for ShPluginsDir: older third-party .asi plugins resolve this name by GetProcAddress. |
ShLogPath | <gamedir>\logs\<name>; the logs directory is created if missing. |
ShPluginIniPath | The config file that belongs beside a plugin of the same name: <its folder>\<name>.ini. |
ShPluginLangPath | <the plugin's folder>\lang.ini, the text file that belongs beside a plugin of the same name. |
ShConfigInit
c
SH_API void ShConfigInit(void);Parse scripthook.ini. The loader runs this before any plugin loads; calling it again is harmless.
scripthook.h, line 3473
ShConfigGetInt
c
SH_API int ShConfigGetInt(const char *section, const char *key,
int def);Integer setting from the main config; def when missing.
scripthook.h, line 3476
ShConfigGetBool
c
SH_API int ShConfigGetBool(const char *section, const char *key,
int def);Boolean setting: 1/0, true/false, yes/no, on/off.
scripthook.h, line 3480
ShConfigGetStr
c
SH_API int ShConfigGetStr(const char *section, const char *key,
const char *def, char *out, int size);String setting; copies the value or def. Returns 1.
scripthook.h, line 3484
ShLogLevel
c
SH_API int ShLogLevel(void);The [Settings] LogLevel in force, as one of the SH_LOG_* values: 0 none, 1 error, 2 warn, 3 info, 4 debug. Parsed once and kept, so editing the ini takes effect on the next launch. Every module - and every plugin that logs - asks this one function, which is what keeps a session's logs\ folder telling one story.
The files that follow the level are the framework's own module logs: those exist at SH_LOG_INFO and SH_LOG_DBG, and not below. The two the support flow asks for - the loader's log and the crash report - are written whatever it says, and a plugin's own log is written at every level except SH_LOG_NONE, so a plugin that failed is still on record in an otherwise quiet session.
scripthook.h, line 3508
ShConfigSetStr
c
SH_API int ShConfigSetStr(const char *section, const char *key,
const char *value);Write a value back to scripthook.ini. The on-disk file is updated in place (comments and other sections preserved) and the in-memory copy is refreshed, so later ShConfigGet* calls see the new value. Most loader/plugins keys only take effect on the next launch.
scripthook.h, line 3515
ShConfigSetInt
c
SH_API int ShConfigSetInt(const char *section, const char *key,
int value);Documented together with ShConfigSetStr just above.
scripthook.h, line 3517
ShConfigSetBool
c
SH_API int ShConfigSetBool(const char *section, const char *key,
int value);Documented together with ShConfigSetStr just above.
scripthook.h, line 3519
ShPluginConfigGetStr
c
SH_API int ShPluginConfigGetStr(const char *plugin, const char *section,
const char *key, const char *def,
char *out, int size);A plugin's own ini, read and written by section.
Same engine and same rules as the main config: a key is replaced where it already sits, a missing key is appended to the end of its section, a section that is not there yet is created, and every other line - other keys, other sections, comments, the byte order mark - survives byte for byte. The file is the one ShPluginIniPath names, so a plugin never has to know where it was installed.
plugin is the plugin's name as the loader knows it (its .asi name), the same string ShPluginIniPath takes. A name that was never scanned gets no path: the Get calls answer the default and the Set calls fail with SH_ERR_NO_PLUGIN, rather than writing a file nothing would read.
Reads are not cached. A plugin ini is a couple of kilobytes and this is meant for startup and for a settings change, not for a frame.
scripthook.h, line 3538
ShPluginConfigGetInt
c
SH_API int ShPluginConfigGetInt(const char *plugin, const char *section,
const char *key, int def);Documented together with ShPluginConfigGetStr just above.
scripthook.h, line 3541
ShPluginConfigGetBool
c
SH_API int ShPluginConfigGetBool(const char *plugin, const char *section,
const char *key, int def);Documented together with ShPluginConfigGetStr just above.
scripthook.h, line 3543
ShPluginConfigSetStr
c
SH_API int ShPluginConfigSetStr(const char *plugin, const char *section,
const char *key, const char *value);Documented together with ShPluginConfigGetStr just above.
scripthook.h, line 3545
ShPluginConfigSetInt
c
SH_API int ShPluginConfigSetInt(const char *plugin, const char *section,
const char *key, int value);Documented together with ShPluginConfigGetStr just above.
scripthook.h, line 3547
ShPluginConfigSetBool
c
SH_API int ShPluginConfigSetBool(const char *plugin, const char *section,
const char *key, int value);Documented together with ShPluginConfigGetStr just above.
scripthook.h, line 3549
ShGameDir
c
SH_API int ShGameDir(char *buf, int size);The folder containing GRW.exe, no trailing backslash.
scripthook.h, line 3553
ShFrameworkDir
c
SH_API int ShFrameworkDir(char *buf, int size);WildM : the folder holding the framework DLL (dinput8.dll), no trailing backslash. plugins\, logs\, scripthook.ini, lang.ini and mods\ live here. Injected from a launcher folder it differs from ShGameDir; as a classic proxy next to GRW.exe both are the same folder.
scripthook.h, line 3559
ShPluginsDir
c
SH_API int ShPluginsDir(char *buf, int size);<gamedir>\plugins\ (with trailing backslash); every .asi plugin lives in its own folder under it.
scripthook.h, line 3563
ShScriptsDir
c
SH_API int ShScriptsDir(char *buf, int size);Compatibility alias for ShPluginsDir: older third-party .asi plugins resolve this name by GetProcAddress. It returns the same plugins\ directory. New code should use ShPluginsDir.
scripthook.h, line 3568
ShLogPath
c
SH_API int ShLogPath(const char *name, char *buf, int size);<gamedir>\logs\<name>; the logs directory is created if missing. Name may include a subfolder.
scripthook.h, line 3572
ShPluginIniPath
c
SH_API int ShPluginIniPath(const char *plugin, char *buf, int size);The config file that belongs beside a plugin of the same name: <its folder>\<name>.ini.
Plugin config convention (follow this in every plugin): the .ini lives in the SAME folder as the .asi and uses the SAME base name, so plugins\foo\bar.asi reads and writes plugins\foo\bar.ini. Derive <name> from your own module path rather than hardcoding it, so the pairing survives a rename: GetModuleFileNameA(instance, path, MAX_PATH), take the file part and strip the ".asi".
<its folder> is where the .asi was installed, which is not always a folder named after the plugin: a plugin may sit at the root of plugins\ (plugins\foo.asi reads plugins\foo.ini) or share a folder with others (plugins\pack\foo.asi reads plugins\pack\foo.ini). "Beside the .asi" is the rule; the folder is looked up, not built from the name.
<name> is the .asi's stem, and only an installed plugin has one: 0 with SH_ERR_NO_PLUGIN when nothing under plugins\ carries that name, and SH_ERR_BAD_ARG for a NULL argument or a buffer the path does not fit. A name taken from your own module file is always one the scan knows, so the failure means the file was renamed or moved after it loaded.
scripthook.h, line 3596
ShPluginLangPath
c
SH_API int ShPluginLangPath(const char *plugin, char *buf, int size);<the plugin's folder>\lang.ini, the text file that belongs beside a plugin of the same name. The framework reads it for a menu that plugin created (see lang); a plugin does not have to ship one, and should not write one - the framework never does. Handy for a tool that wants to seed or inspect it.
Plugins that share a folder share this file, which is what lets a pack of small plugins keep one lang.ini between them: the owner a plugin declares (ShLangDeclare) is what keeps their rows apart inside it.
Same resolution and the same two failures as ShPluginIniPath.
scripthook.h, line 3609