Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
60bcdff
Add ci builds
KaninHop Mar 29, 2026
3ffe3ae
Fix missing github action permission
KaninHop Mar 29, 2026
98f13de
Address coderabbit feedback part 1
KaninHop Mar 29, 2026
b386b86
ensure dev paths don't get committed
KaninHop Mar 29, 2026
f3a2f28
revert jmap changes
KaninHop Mar 29, 2026
f550cbb
update tasks.json and complile.ps1 to work better with dev builds
KaninHop Mar 29, 2026
b052276
Fix build status url
KaninHop Mar 29, 2026
96e05b7
more rabbit requested changes
KaninHop Mar 29, 2026
3a8d3f9
Merge remote-tracking branch 'origin/main' into Improve-Builds-and-Ad…
KaninHop Mar 29, 2026
f99aef5
Merge branch 'Improve-Builds-and-Add-CI' into feat/add-frame-time-bug…
KaninHop Mar 29, 2026
8c9fb45
Rabbit feedback and fix some incorrect labels when upgrading existing…
KaninHop Mar 29, 2026
efdfd3e
Rabbit fixes to improve loading robustness
KaninHop Mar 29, 2026
1eb6bdb
fix Potential logic inconsistency between pre-check and sequential pa…
KaninHop Mar 29, 2026
e48240c
Switch to submodule for skyui, move stubs to dependencies folder
KaninHop Mar 30, 2026
3ff1c32
Feat/add frame time buget with ci (#2)
KaninHop Mar 30, 2026
f28d241
Merge branch 'DaymareOn:main' into Improve-Builds-and-Add-CI
KaninHop Mar 30, 2026
b1bde03
Publish github release when tag is added
KaninHop Mar 30, 2026
644546b
Merge branch 'Improve-Builds-and-Add-CI' of https://github.com/KaninH…
KaninHop Mar 30, 2026
a730813
Cleanup and rabbit feedback
KaninHop Mar 30, 2026
0827de3
Remove old pex files before each build rabbit feedback
KaninHop Mar 30, 2026
9c047f0
Ensure Ci and Local release builds are the same
KaninHop Mar 30, 2026
d6e9c2e
Fix rootDir Lookup - Rabbit Feedback
KaninHop Mar 30, 2026
17311b6
Fix incorrect vanilla script stub
KaninHop Mar 30, 2026
fe9de8e
Update .github/workflows/build.yml
KaninHop Mar 30, 2026
5092d16
Fix submodule declaration
KaninHop Mar 30, 2026
17ecc8d
fix: remove ghost submodule Source/Scripts/Stubs/SkyUI-Community
KaninHop Mar 30, 2026
5f5104f
Add default xml and separte max skelotons
KaninHop Apr 6, 2026
d8b89f5
Merge remote-tracking branch 'upstream/main' into Improve-Builds-and-…
KaninHop Apr 15, 2026
3a1d6e9
Ensure the right compiled scripts are included
KaninHop Apr 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .agents/workflows/build.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
description: Build the FSMP MCM Papyrus scripts using Caprica
---

# Build FSMP MCM

Compiles the Papyrus source scripts (`.psc`) into compiled Papyrus executables (`.pex`) using the Caprica compiler. This project uses in-repo stubs for all dependencies, making it easy to build without external setup.

## Prerequisites

- **Caprica Compiler**: `Caprica/Caprica.exe` must be present.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix markdownlint issues (trailing space and final newline).

Line 11 has trailing whitespace, and the file should end with exactly one newline.

Suggested fix
-- **Caprica Compiler**: `Caprica/Caprica.exe` must be present. 
+- **Caprica Compiler**: `Caprica/Caprica.exe` must be present.
@@
 - Warning `W4007` about `loadConfigDone` being unused is expected and harmless.
+

Also applies to: 41-41

🧰 Tools
🪛 markdownlint-cli2 (0.22.0)

[warning] 11-11: Trailing spaces
Expected: 0 or 2; Actual: 1

(MD009, no-trailing-spaces)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/workflows/build.md at line 11, Remove the trailing whitespace at the
end of the line containing "**Caprica Compiler**: `Caprica/Caprica.exe`" and
ensure the file ends with exactly one newline character; also check and remove
any trailing spaces on the other occurrence noted (line with the same text
around the 41st line) so both instances have no trailing spaces and the document
has a single final newline.

- If missing, download version 0.3.0a from [KrisV-777/Caprica Releases](https://github.com/KrisV-777/Caprica/releases/tag/0.3.0a).
- **PowerShell**: Used to run the build script.

## Build Command

1. Run the compilation script from the repository root:

```powershell
# Default Release mode (uses stubs)
./dev-scripts/compile.ps1

# Dev mode (uses your real local scripts)
./dev-scripts/compile.ps1 -Mode Dev
```

The compiled `.pex` files will be placed in the `Scripts/` directory.

## Alternative: Papyrus Project (.ppj)

You can also use the `skyrimse.ppj` file with any Papyrus project runner (like `Pypro` or `Caprica` directly if your version supports it).

```powershell
./Caprica/Caprica.exe skyrimse.ppj
```

## Notes

- The build script uses the `--ignorecwd` flag to prevent Caprica from auto-adding the CWD to imports, avoiding namespace conflicts.
- It also uses `--game skyrim` for Skyrim-specific compatibility.
- Warning `W4007` about `loadConfigDone` being unused is expected and harmless.
90 changes: 90 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
name: Build FSMP MCM

on:
push:
branches: [main]
tags:
- 'v*.*.*'
- 'v*.*'
pull_request:
branches: [main]
workflow_dispatch:

permissions:
contents: write

jobs:
build:
runs-on: windows-latest
Comment thread
KaninHop marked this conversation as resolved.
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
submodules: recursive

- name: Setup CI Dependencies
shell: powershell
run: ./dev-scripts/setup_ci.ps1

- name: Compile Papyrus Scripts
shell: powershell
run: |
$flagsFile = Resolve-Path "Dependencies/Stubs/BaseGame/TESV_Papyrus_Flags.flg"
$imports = @(
(Resolve-Path "Source/Scripts"),
(Resolve-Path "Dependencies/SkyUI-Community/source/scripts"),
(Resolve-Path "Dependencies/Stubs/BaseGame"),
(Resolve-Path "Dependencies/Stubs/SKSE"),
(Resolve-Path "Dependencies/Stubs/JContainers"),
(Resolve-Path "Dependencies/Stubs/PapyrusUtil"),
(Resolve-Path "Dependencies/Stubs/ConsoleUtil")
) -join ";"
if (-not (Test-Path "Scripts")) { New-Item -ItemType Directory -Path "Scripts" }
Remove-Item "Scripts/*.pex" -ErrorAction SilentlyContinue
$output = Resolve-Path "Scripts"

# Compile FSMPM.psc
$fsmpm = Resolve-Path "Source/Scripts/FSMPM.psc"
& ./ci_tools/Caprica.exe --game skyrim --flags "$flagsFile" --import "$imports" --output "$output" --ignorecwd "$fsmpm"
if ($LASTEXITCODE -ne 0) { throw "FSMPM.psc compilation failed" }

# Compile FSMPMPlayerScript.psc
$player = Resolve-Path "Source/Scripts/FSMPMPlayerScript.psc"
& ./ci_tools/Caprica.exe --game skyrim --flags "$flagsFile" --import "$imports" --output "$output" --ignorecwd "$player"
if ($LASTEXITCODE -ne 0) { throw "FSMPMPlayerScript.psc compilation failed" }

Write-Host "All scripts compiled successfully."
Get-ChildItem Scripts/*.pex | ForEach-Object { Write-Host " $($_.Name) - $($_.Length) bytes" }

- name: Package Distributable
shell: powershell
run: |
$buildDir = "Build/FSMPM - The FSMP MCM"
if (Test-Path "Build") { Remove-Item -Recurse -Force "Build" }
New-Item -ItemType Directory -Path "$buildDir/Scripts" -Force
New-Item -ItemType Directory -Path "$buildDir/SKSE/Plugins/hdtSkinnedMeshConfigs/configsPresets" -Force
New-Item -ItemType Directory -Path "$buildDir/Source/Scripts" -Force

Copy-Item "FSMPM - The FSMP MCM.esp" $buildDir/
Copy-Item Scripts/*.pex "$buildDir/Scripts/"
Copy-Item SKSE/Plugins/hdtSkinnedMeshConfigs/configs.xml "$buildDir/SKSE/Plugins/hdtSkinnedMeshConfigs/"
Copy-Item SKSE/Plugins/hdtSkinnedMeshConfigs/configsPresets/*.xml "$buildDir/SKSE/Plugins/hdtSkinnedMeshConfigs/configsPresets/"
Copy-Item Source/Scripts/*.psc "$buildDir/Source/Scripts/"

Compress-Archive -Path "$buildDir/*" -DestinationPath "Build/FSMP-MCM.zip" -Force
Write-Host "Distributable archive created: Build/FSMP-MCM.zip"

- name: Upload Build Artifact
uses: actions/upload-artifact@v4
with:
name: FSMP-MCM
path: Build/FSMP-MCM.zip

- name: Publish GitHub Release
if: startsWith(github.ref, 'refs/tags/v')
uses: softprops/action-gh-release@v2
with:
files: Build/FSMP-MCM.zip
name: FSMP-MCM ${{ github.ref_name }}
draft: false
prerelease: false
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Build artifacts
Build/

# Local configuration
Caprica/Caprica.exe
skyrimse.dev.ppj


# OS generated files
.DS_Store
Thumbs.db
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "Dependencies/SkyUI-Community"]
path = Dependencies/SkyUI-Community
url = https://github.com/doodlum/SkyUI-Community.git
40 changes: 33 additions & 7 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,43 @@
"version": "2.0.0",
"tasks": [
{
"type": "pyro",
"projectFile": "skyrimse.ppj",
"gamePath": "C:\\Games\\Nolvus\\Instances\\Nolvus Natural Lighting\\STOCK GAME\\",
"problemMatcher": [
"$PapyrusCompiler"
"label": "Build: Dev (Local Project)",
"type": "shell",
"command": "pwsh",
"args": [
"-ExecutionPolicy",
"Bypass",
"-File",
"${workspaceFolder}/dev-scripts/compile.ps1",
"Dev"
],
"label": "pyro: Compile Project (skyrimse.ppj)",
"group": {
"kind": "build",
"isDefault": true
}
},
"presentation": {
"reveal": "always",
"panel": "new"
},
"problemMatcher": "$PapyrusCompiler"
},
{
"label": "Build: Release (CI Stubs)",
"type": "shell",
"command": "pwsh",
"args": [
"-ExecutionPolicy",
"Bypass",
"-File",
"${workspaceFolder}/dev-scripts/compile.ps1",
"Release"
],
"group": "build",
"presentation": {
"reveal": "always",
"panel": "new"
},
"problemMatcher": "$PapyrusCompiler"
}
]
}
1 change: 1 addition & 0 deletions Dependencies/SkyUI-Community
Submodule SkyUI-Community added at de600b
8 changes: 8 additions & 0 deletions Dependencies/Stubs/BaseGame/Actor.psc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
; Minimal stub for CI builds
Scriptname Actor extends ObjectReference Hidden

Function AddToFaction(Faction akFaction) native
Function RemoveFromFaction(Faction akFaction) native
Function StopCombat() native
Function EvaluatePackage() native
Function Kill(Actor akKiller = None) native
49 changes: 49 additions & 0 deletions Dependencies/Stubs/BaseGame/Alias.psc
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
; Minimal stub for CI builds
Scriptname Alias Hidden

Quest Function GetOwningQuest() native
bool Function RegisterForAnimationEvent(ObjectReference akSender, string asEventName) native
Function RegisterForLOS(Actor akViewer, ObjectReference akTarget) native
Function RegisterForSingleLOSGain(Actor akViewer, ObjectReference akTarget) native
Function RegisterForSingleLOSLost(Actor akViewer, ObjectReference akTarget) native
Function RegisterForSingleUpdate(float afInterval) native
Function RegisterForUpdate(float afInterval) native
Function RegisterForUpdateGameTime(float afInterval) native
Function RegisterForSingleUpdateGameTime(float afInterval) native
Function RegisterForSleep() native
Function RegisterForTrackedStatsEvent() native
Function StartObjectProfiling() native
Function StopObjectProfiling() native
Function UnregisterForLOS(Actor akViewer, ObjectReference akTarget) native
Function UnregisterForAnimationEvent(ObjectReference akSender, string asEventName) native
Function UnregisterForSleep() native
Function UnregisterForTrackedStatsEvent() native
Function UnregisterForUpdate() native
Function UnregisterForUpdateGameTime() native

Comment thread
coderabbitai[bot] marked this conversation as resolved.
Event OnAnimationEvent(ObjectReference akSource, string asEventName)
EndEvent

Event OnAnimationEventUnregistered(ObjectReference akSource, string asEventName)
EndEvent

Event OnGainLOS(Actor akViewer, ObjectReference akTarget)
EndEvent

Event OnLostLOS(Actor akViewer, ObjectReference akTarget)
EndEvent

Event OnSleepStart(float afSleepStartTime, float afDesiredSleepEndTime)
EndEvent

Event OnSleepStop(bool abInterrupted)
EndEvent

Event OnTrackedStatsEvent(string arStatName, int aiStatValue)
EndEvent

Event OnUpdate()
EndEvent

Event OnUpdateGameTime()
EndEvent
Comment thread
KaninHop marked this conversation as resolved.
8 changes: 8 additions & 0 deletions Dependencies/Stubs/BaseGame/Debug.psc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
; Minimal stub for CI builds
Scriptname Debug Hidden

Function MessageBox(string asMessageBoxText) native global
Function Notification(string asNotificationText) native global
Function Trace(string asTextToPrint, int aiSeverity = 0) native global
Function TraceStack(string asTextToPrint = "Tracing stack on request", int aiSeverity = 0) native global
bool Function TraceUser(string asUserLog, string asTextToPrint, int aiSeverity = 0) native global
2 changes: 2 additions & 0 deletions Dependencies/Stubs/BaseGame/Faction.psc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
; Minimal forward-declaration stub for CI builds
Scriptname Faction extends Form Hidden
58 changes: 58 additions & 0 deletions Dependencies/Stubs/BaseGame/Form.psc
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
; Minimal stub for CI builds - provides the base Form class
; This is an interface-only file for compilation purposes
Scriptname Form Hidden

Int Function GetFormID() native
int Function GetGoldValue() native
bool Function HasKeyword(Keyword akKeyword) native
bool Function PlayerKnows() native
bool Function RegisterForAnimationEvent(ObjectReference akSender, string asEventName) native
Function RegisterForLOS(Actor akViewer, ObjectReference akTarget) native
Function RegisterForSingleLOSGain(Actor akViewer, ObjectReference akTarget) native
Function RegisterForSingleLOSLost(Actor akViewer, ObjectReference akTarget) native
Function RegisterForSingleUpdate(float afInterval) native
Function RegisterForSleep() native
Function RegisterForTrackedStatsEvent() native
Function RegisterForUpdate(float afInterval) native
Function RegisterForUpdateGameTime(float afInterval) native
Function RegisterForSingleUpdateGameTime(float afInterval) native
Function StartObjectProfiling() native
Function StopObjectProfiling() native
Function UnregisterForAnimationEvent(ObjectReference akSender, string asEventName) native
Function UnregisterForLOS(Actor akViewer, ObjectReference akTarget) native
Function UnregisterForSleep() native
Function UnregisterForTrackedStatsEvent() native
Function UnregisterForUpdate() native
Function UnregisterForUpdateGameTime() native

; SKSE additions
Function RegisterForModEvent(string eventName, string callbackName) native
Function UnregisterForModEvent(string eventName) native
Function SendModEvent(string eventName, string strArg = "", float numArg = 0.0) native
Comment thread
KaninHop marked this conversation as resolved.

Event OnAnimationEvent(ObjectReference akSource, string asEventName)
EndEvent

Event OnAnimationEventUnregistered(ObjectReference akSource, string asEventName)
EndEvent

Event OnGainLOS(Actor akViewer, ObjectReference akTarget)
EndEvent

Event OnLostLOS(Actor akViewer, ObjectReference akTarget)
EndEvent

Event OnSleepStart(float afSleepStartTime, float afDesiredSleepEndTime)
EndEvent

Event OnSleepStop(bool abInterrupted)
EndEvent

Event OnTrackedStatsEvent(string arStatName, int aiStatValue)
EndEvent

Event OnUpdate()
EndEvent

Event OnUpdateGameTime()
EndEvent
6 changes: 6 additions & 0 deletions Dependencies/Stubs/BaseGame/GlobalVariable.psc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
; Minimal forward-declaration stub for CI builds
Scriptname GlobalVariable extends Form Hidden

Function SetValue(float afNewValue) native
float Function GetValue() native
float Function Mod(float afHowMuch) native
2 changes: 2 additions & 0 deletions Dependencies/Stubs/BaseGame/Keyword.psc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
; Minimal forward-declaration stub for CI builds
Scriptname Keyword extends Form Hidden
15 changes: 15 additions & 0 deletions Dependencies/Stubs/BaseGame/ObjectReference.psc
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
; Minimal stub for CI builds
Scriptname ObjectReference extends Form Hidden

Function Disable(bool abFadOut = false) native
Function DisableNoWait(bool abFadOut = false) native
Function Enable(bool abFadIn = false) native
Function EnableNoWait(bool abFadIn = false) native
Function MoveTo(ObjectReference akTarget, float afXOffset = 0.0, float afYOffset = 0.0, float afZOffset = 0.0, bool abMatchRotation = true) native
Function Reset() native

Event OnActivate(ObjectReference akActionRef)
EndEvent

Event OnInit()
EndEvent
39 changes: 39 additions & 0 deletions Dependencies/Stubs/BaseGame/Quest.psc
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
; Minimal stub for CI builds
Scriptname Quest extends Form Hidden

Function CompleteAllObjectives() native
Function CompleteQuest() native
Function FailAllObjectives() native
Alias Function GetAlias(int aiAliasID) native
int Function GetCurrentStageID() native
bool Function IsActive() native
bool Function IsCompleted() native
bool Function IsObjectiveCompleted(int aiObjective) native
bool Function IsObjectiveDisplayed(int aiObjective) native
bool Function IsObjectiveFailed(int aiObjective) native
bool Function IsRunning() native
bool Function IsStageDone(int aiStage) native
bool Function IsStarting() native
bool Function IsStopping() native
bool Function IsStopped() native
Function Reset() native
Function SetActive(bool abActive = true) native
bool Function SetCurrentStageID(int aiStageID) native
Function SetObjectiveCompleted(int aiObjective, bool abCompleted = true) native
Function SetObjectiveDisplayed(int aiObjective, bool abDisplayed = true, bool abForce = false) native
Function SetObjectiveFailed(int aiObjective, bool abFailed = true) native
bool Function Start() native
Function Stop() native
bool Function UpdateCurrentInstanceGlobal(GlobalVariable aUpdateGlobal) native

int Function GetStage()
return GetCurrentStageID()
EndFunction

bool Function GetStageDone(int aiStage)
return IsStageDone(aiStage)
EndFunction

bool Function SetStage(int aiStage)
return SetCurrentStageID(aiStage)
EndFunction
Loading