Skip to content

Plugin mode blacklist ​

Group blacklist · 10 exports · from forks/gamexueren/scripthook.h (framework 1.0-beta7-wildm1, SH_API_VERSION 2)

Which play modes a plugin must not run in, and what the framework does about it.

A plugin declares its modes once, from its own source:

text
ShPluginBlacklist(SH_MODE_BLACKLIST_GHOST_WAR |
                  SH_MODE_BLACKLIST_MERCENARIES);

and the framework takes its row out of the F4 root menu, everything under it with it, for as long as the session is in one of those modes. The declaration is the only input: nothing in any ini can widen or narrow it.

A mask names play modes, and play modes are the only conditions. The front end was one of them until 2026-09-13 and is not any more: the reading it rested on (the GameFlow machine's mode-screen object) latches once a mode screen has been opened, so it was right at startup and wrong after a round trip through a campaign - and ShGetGameState puts the main menu and every lobby in one bucket, so there was no second reading to fall back on. Better no condition than one that is right half the time.

Three cases, and the third is the one that matters:

  • declared bits blocked in exactly those;
  • declared NONE (0) blocked nowhere - declaring "none" is the only way to be unrestricted;
  • not declared at all blocked in Ghost War and Mercenaries. Every third party plugin is in this group by construction, and so is any plugin of ours that has not been taught otherwise. Built-in pages are not plugins (their menu owner is "") and are never blocked.

What is in force comes from one place: ShSelectedPlayMode, the mode the game's own manager was handed. When it cannot be read - the manager has not set a mode yet, or the hook is not armed on this build - nothing is in force and nobody is blocked: a menu that vanishes with no reason to give would be worse than one that stays.

What this cannot do: stop a plugin's code. Plugins run their own threads and carry their own MinHook copy, and the framework has no registry that could suspend them. Blocked means hidden and told; a plugin that wants its work to stop has to stop it. The usual shape is a tick thread that returns early plus a callback that tears down what it installed:

text
static void OnBlocked(int allowed, int mode, void *user) {
    (void)mode; (void)user;
    if (!allowed) StopMyWork();      // drop hooks, park the thread
    else          StartMyWork();
}
ShPluginOnBlocked(OnBlocked, NULL);

The callback arrives on a framework thread (250 ms poll), once per change, and only when the answer actually flips. Keep it short; it is not holding any lock of ours, so calling back into the framework from it is allowed. See docs/plugin-blacklist.md.

ExportSummary
ShPluginBlacklistDeclare which conditions this plugin must not run in - a mask of the bits above.
ShPluginBlockedByWhat is switching this plugin off right now, as the bits above (SH_MODE_BLACKLIST_*), or 0 when nothing is.
ShPluginAllowed1 when this plugin may run now.
ShPluginBlacklistModesThe conditions in force for this plugin: what it declared, or the default (Ghost War and Mercenaries) when it never declared anything.
ShPluginOnBlocked—
ShBlacklistNameThe name of one bit, for a log line or a menu: "Ghost War", "MERCENARIES", "campaign", "Ghost Mode", "Guerrilla"; "" for 0 or for more than one bit (use ShBlockedText for that).
ShBlockedTextThe bits as one line, for a log: "Ghost War+MERCENARIES".
ShPluginBlacklistCountThe registry, for a settings page: how many plugins were seen, and one entry per index - its folder name, the conditions in force, and the bits blocking it now (0 for none).
ShPluginBlacklistAtSee ShPluginBlacklistCount.
ShPluginBlacklistNoticeOne translated line naming the plugins the current conditions have switched off: "Off now (Ghost War): firstperson, freecam (+3)".

ShPluginBlacklist ​

c
SH_API int      ShPluginBlacklist(uint32_t modes);

Declare which conditions this plugin must not run in - a mask of the bits above. Call it once, from your own code: the caller's module is what identifies the plugin. 1 when accepted; 0 with ShLastError saying why - SH_ERR_BAD_ARG when the caller is not a plugin, SH_ERR_REGISTRY_FULL when 64 plugins are already registered.

scripthook.h, line 417

ShPluginBlockedBy ​

c
SH_API int      ShPluginBlockedBy(void);

What is switching this plugin off right now, as the bits above (SH_MODE_BLACKLIST_*), or 0 when nothing is.

scripthook.h, line 421

ShPluginAllowed ​

c
SH_API int      ShPluginAllowed(void);

1 when this plugin may run now. Cheap; safe to call every frame.

scripthook.h, line 424

ShPluginBlacklistModes ​

c
SH_API uint32_t ShPluginBlacklistModes(void);

The conditions in force for this plugin: what it declared, or the default (Ghost War and Mercenaries) when it never declared anything. 0 for a declarer of "none".

scripthook.h, line 429

ShPluginOnBlocked ​

c
SH_API int      ShPluginOnBlocked(ShPluginBlockedFn fn, void *user);

No doc comment in the header.

scripthook.h, line 435

ShBlacklistName ​

c
SH_API const char *ShBlacklistName(uint32_t bit);

The name of one bit, for a log line or a menu: "Ghost War", "MERCENARIES", "campaign", "Ghost Mode", "Guerrilla"; "" for 0 or for more than one bit (use ShBlockedText for that). A translation key: pass it through ShLang before showing it.

scripthook.h, line 441

ShBlockedText ​

c
SH_API int      ShBlockedText(uint32_t bits, char *buf, int cap);

The bits as one line, for a log: "Ghost War+MERCENARIES". 1 when something was written.

scripthook.h, line 445

ShPluginBlacklistCount ​

c
SH_API int      ShPluginBlacklistCount(void);

The registry, for a settings page: how many plugins were seen, and one entry per index - its folder name, the conditions in force, and the bits blocking it now (0 for none).

scripthook.h, line 450

ShPluginBlacklistAt ​

c
SH_API int      ShPluginBlacklistAt(int i, char *name, int cap,
                                    uint32_t *modes, int *blockedBy);

Documented together with ShPluginBlacklistCount just above.

scripthook.h, line 451

ShPluginBlacklistNotice ​

c
SH_API int      ShPluginBlacklistNotice(char *buf, int cap);

One translated line naming the plugins the current conditions have switched off: "Off now (Ghost War): firstperson, freecam (+3)". Short on purpose - the Plugins page shows it on the hint line it shares with the "needs a restart" note - and empty with a 0 return when there is nothing to say.

scripthook.h, line 459

WildM is an independent community project. It is not affiliated with or endorsed by Ubisoft. Ghost Recon Wildlands is a trademark of Ubisoft Entertainment.