Files
Commonwealth-Online-Public/docs/FFDEC_MainMenu_Multiplayer_Guide.md
T
andrew d4d3268b12 Add runtime MainMenu injection and docs
Introduce a C++ runtime injection that adds a Multiplayer row to the Fallout 4 main menu instead of patching MainMenu.swf. Adds F4TMainMenuInject.h/cpp implementing injection, ITEM_PRESS handling, accept/button hooks, resync tasks and logging; integrates installation by calling MainMenuInject::Install() from PrismaUI init. Update PrismaUI to use the new helper and remove a duplicate IsMainMenuOnMainPanel implementation. Documentation updated to deprecate FFDec SWF patching (new docs/MainMenu_Injection.md, note in FFDEC guide, and setup.md) and restore-vanilla-mainmenu.ps1 messaging updated to instruct using the runtime injection.
2026-06-09 14:52:27 +12:00

10 KiB
Raw Blame History

FFDec guide — add Multiplayer button to MainMenu.swf

Deprecated: Use C++ runtime injection instead. See MainMenu_Injection.md. Do not deploy a patched MainMenu.swf for Commonwealth Online.

Step-by-step instructions for adding the Multiplayer main-menu item using JPEXS FFDec, without breaking Settings → Gameplay / Display / Audio.

This guide is kept for historical reference only.


Before you start

Restore vanilla SWF

Always patch from the vanilla file, not an old broken copy:

.\tools\restore-vanilla-mainmenu.ps1

Or manually copy Interface/MainMenu.swf.vanilla.bakInterface/MainMenu.swf.

Vanilla size is 61,959 bytes. If your file is 64 KB+, it is probably a bad re-import — restore and start again.

Requirements

  • FFDec installed
  • Game launched via F4SE with CommonwealthOnline.dll in Data/F4SE/Plugins/
  • Loose Interface overrides enabled in %USERPROFILE%/Documents/My Games/Fallout4/Fallout4Custom.ini:
[Archive]
bInvalidateOlderFiles=1

Critical rule

Do Don't
Edit individual methods (double-click method in traits list) Paste the full MainMenu.as export into the class editor
Save after each small edit Use Import script on the whole MainMenu class
Keep SWF ~6263 KB Re-export the entire decompiled script

Full re-import recompiles RequestOptions and breaks settings sub-menus. Controls will still work; Gameplay / Display / Audio will crash.


FFDec navigation

  1. Open Interface/MainMenu.swf in FFDec.
  2. Left tree: scripts → MainMenu.
  3. You should see a traits / members list (constants, functions).
  4. Double-click a method name (e.g. InitList) to open only that method in the editor.
  5. After each edit: apply/save the method, then File → Save the SWF.

Do not use Edit ActionScript on the entire MainMenu class if FFDec offers a single giant class view — use per-method editing instead.


Summary of changes

# Where in FFDec What
1 Class constants Add MULTIPLAYER_INDEX
2 Method InitList Push Multiplayer row after Load
3 Method onMainListItemPress Add case for Multiplayer
4 New method CloseMultiplayerBrowser Helper (recommended)
5 Method set currentState Call close helper when leaving main panel
6 Method onMainListItemPress Close browser when another item is selected

Changes 46 are recommended so the HTML browser closes immediately when opening Settings, etc. The plugin also hides the browser when currentState leaves MAIN_STATE, but the SWF hooks make it feel instant.


Change 1 — Add index constant

FFDec: MainMenu → constants section (near other *_INDEX constants)

Find this block (search for INSTALLED_CONTENT_INDEX):

      private const INSTALLED_CONTENT_INDEX:Number = 14;
      
      private const MAIN_PANEL_BACKGROUND:uint = 0;

Insert between those lines:

      private const MULTIPLAYER_INDEX:Number = 15;

Index 15 is unused in vanilla (highest defined index is 14).


Change 2 — Add menu row in InitList

FFDec: MainMenu → method InitList

Find this block (search for "$LOAD" push — it appears after the $NEW block on title screen):

         this.MainPanel_mc.List_mc.entryList.push({
            "text":"$LOAD",
            "disabled":!this.HasRecentSave || !param6,
            "index":this.LOAD_INDEX
         });
         if(param8 == true)

Replace with (add Multiplayer block between Load and if(param8 == true)):

         this.MainPanel_mc.List_mc.entryList.push({
            "text":"$LOAD",
            "disabled":!this.HasRecentSave || !param6,
            "index":this.LOAD_INDEX
         });
         if(!this.PauseMode)
         {
            this.MainPanel_mc.List_mc.entryList.push({
               "text":"Multiplayer",
               "index":this.MULTIPLAYER_INDEX
            });
         }
         if(param8 == true)

Notes:

  • "Multiplayer" is a literal label (no $ prefix). Strings with $ are looked up in Interface/Translate_en.txt.
  • !this.PauseMode limits the row to the title screen, not the in-game pause menu.
  • Row appears between Load and Add-ons (or PS5 transfer if enabled).

Change 3 — Handle click in onMainListItemPress

FFDec: MainMenu → method onMainListItemPress

Find this block (search for case this.HELP_INDEX:):

                  break;
               case this.HELP_INDEX:
                  this.StartState(this.HELP_STATE);
                  this.BGSCodeObj.PlayOKSound();
                  break;

Insert immediately before case this.HELP_INDEX::

                  break;
               case this.MULTIPLAYER_INDEX:
                  this.BGSCodeObj.PlayOKSound();
                  if(root.f4se != null && root.f4se.plugins != null && root.f4se.plugins.commonwealthOnline != null)
                  {
                     root.f4se.plugins.commonwealthOnline.openManager();
                  }
                  break;
               case this.HELP_INDEX:
                  this.StartState(this.HELP_STATE);
                  this.BGSCodeObj.PlayOKSound();
                  break;

This calls the C++ API registered by CommonwealthOnline.dll (openManager → PrismaUI server browser). F9 still toggles the same browser.


Change 4 — Add CloseMultiplayerBrowser method

FFDec: MainMenuadd new method (right-click class → Add script / Add method, or paste near other private helpers like onMainListItemPress)

Add this entire method:

      private function CloseMultiplayerBrowser() : *
      {
         if(root.f4se != null && root.f4se.plugins != null && root.f4se.plugins.commonwealthOnline != null)
         {
            root.f4se.plugins.commonwealthOnline.closeManager();
         }
      }

Change 5 — Close browser in set currentState

FFDec: MainMenu → method set currentState (may appear as currentState setter)

Find:

      public function set currentState(param1:String) : *
      {
         this.strCurrentState = param1;
         this.UpdateButtons(param1);
         this.UpdateStateFocus(param1);
      }

Change to:

      public function set currentState(param1:String) : *
      {
         this.strCurrentState = param1;
         if(param1 != this.MAIN_STATE)
         {
            this.CloseMultiplayerBrowser();
         }
         this.UpdateButtons(param1);
         this.UpdateStateFocus(param1);
      }

Change 6 — Close browser when another main-menu item is selected

FFDec: MainMenu → method onMainListItemPress (same method as Change 3)

Find the start of the else branch, after the while loop that returns to main state:

            while(this.strCurrentState != this.MAIN_STATE)
            {
               this.onCancelPress(true,false);
            }
            if(this.MainPanel_mc.List_mc.selectedEntry.index == this.CONTINUE_INDEX && this.PauseMode)

Insert between the while loop and the CONTINUE_INDEX check:

            while(this.strCurrentState != this.MAIN_STATE)
            {
               this.onCancelPress(true,false);
            }
            if(this.MainPanel_mc.List_mc.selectedEntry.index != this.MULTIPLAYER_INDEX)
            {
               this.CloseMultiplayerBrowser();
            }
            if(this.MainPanel_mc.List_mc.selectedEntry.index == this.CONTINUE_INDEX && this.PauseMode)

Save and deploy

  1. File → Save in FFDec (overwrite Interface/MainMenu.swf).

  2. Check file size: should be roughly 62,00063,500 bytes. If 64,000+, restore vanilla and redo using method-only edits.

  3. Copy to game:

    Fallout 4/Data/Interface/MainMenu.swf
    
  4. Launch via F4SE.


Test checklist

Step Expected
Main menu (title screen) Multiplayer appears after Load
Pause menu → Settings No Multiplayer row
Click Multiplayer Server browser opens
Settings → Gameplay No crash
Settings → Display No crash
Settings → Audio No crash
Settings → Controls Still works
Open Multiplayer, then Settings Browser closes
F9 Still toggles browser

Troubleshooting

Settings sub-menus crash again

You likely re-imported the full class. Run .\tools\restore-vanilla-mainmenu.ps1 and redo changes 16 using per-method editing only.

Multiplayer row missing

  • Confirm bInvalidateOlderFiles=1 in Fallout4Custom.ini.
  • Confirm loose Data/Interface/MainMenu.swf exists and is not overridden by another mod (check MO2 load order).
  • Confirm you added the InitList block with if(!this.PauseMode).

Multiplayer row visible but click does nothing

  • Launch via F4SE, not vanilla exe.
  • Confirm CommonwealthOnline.dll is loading (check Documents/My Games/Fallout4/F4SE/CommonwealthOnline.log).
  • Confirm Change 3 (case this.MULTIPLAYER_INDEX) is present.

Button shows $MULTIPLAYER or wrong text

Use literal "Multiplayer" (no $), or add a translation key to Interface/Translate_en.txt.


Reference files

File Purpose
MainMenu.swf.vanilla.bak Untouched vanilla backup
scripts/MainMenu.as Full decompiled reference — do not import wholesale
PATCH_MainMenu_Multiplayer.md Short overview
../../tools/restore-vanilla-mainmenu.ps1 Restore vanilla SWF from game BA2

Plugin API (already implemented in C++):

  • root.f4se.plugins.commonwealthOnline.openManager()
  • root.f4se.plugins.commonwealthOnline.closeManager()