modwright 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +35 -0
- package/README.md +212 -0
- package/assets/claude/agents/mw-explore.md +46 -0
- package/assets/claude/agents/mw-fixture.md +33 -0
- package/assets/claude/agents/mw-rule-author.md +51 -0
- package/assets/claude/agents/mw-scaffold-author.md +48 -0
- package/assets/claude/skills/mw-author.md +59 -0
- package/assets/claude/skills/mw-new-item.md +51 -0
- package/assets/claude/skills/mw-new-spell.md +50 -0
- package/assets/claude/skills/mw-scaffold.md +59 -0
- package/assets/claude/skills/mw-ship.md +57 -0
- package/assets/claude/skills/mw-validate.md +51 -0
- package/assets/claude/skills/mw-verify.md +59 -0
- package/assets/nivalisnights/extract_resources.py +177 -0
- package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Config.json +5 -0
- package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Lua/BootstrapClient.lua +55 -0
- package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Lua/BootstrapServer.lua +81 -0
- package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Lua/ModWrightBridge/Log.lua +96 -0
- package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Lua/ModWrightBridge/Probes.lua +1038 -0
- package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Lua/ModWrightBridge/ProbesClient.lua +74 -0
- package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Lua/ModWrightBridge/Protocol.lua +985 -0
- package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Lua/ModWrightBridge/Watch.lua +175 -0
- package/bridges/bg3-se/Mods/ModWrightBridge/meta.lsx +45 -0
- package/bridges/bg3-se/README.md +99 -0
- package/bridges/bg3-se/bridge.json +68 -0
- package/bridges/cp2077-cet/ModWrightBridge/init.lua +375 -0
- package/bridges/cp2077-cet/ModWrightBridge/probes.lua +1104 -0
- package/bridges/cp2077-cet/ModWrightBridge/protocol.lua +1306 -0
- package/bridges/cp2077-cet/README.md +165 -0
- package/bridges/cp2077-cet/bridge.json +53 -0
- package/dist/core/bridge/arm.js +175 -0
- package/dist/core/bridge/cet-console.js +26 -0
- package/dist/core/bridge/cet-log.js +362 -0
- package/dist/core/bridge/index.js +11 -0
- package/dist/core/bridge/locate.js +35 -0
- package/dist/core/bridge/paths.js +34 -0
- package/dist/core/bridge/pending.js +89 -0
- package/dist/core/bridge/poll.js +155 -0
- package/dist/core/bridge/stage.js +100 -0
- package/dist/core/bridge/status.js +97 -0
- package/dist/core/bridge/types.js +145 -0
- package/dist/core/bridge/validate.js +107 -0
- package/dist/core/build/index.js +6 -0
- package/dist/core/build/manifest.js +47 -0
- package/dist/core/build/paths.js +32 -0
- package/dist/core/build/run.js +342 -0
- package/dist/core/build/stage.js +265 -0
- package/dist/core/build/steps/bg3.js +129 -0
- package/dist/core/build/steps/core.js +195 -0
- package/dist/core/build/steps/cyberpunk.js +95 -0
- package/dist/core/build/steps/listing.js +35 -0
- package/dist/core/build/types.js +13 -0
- package/dist/core/build/zip.js +148 -0
- package/dist/core/compat/check.js +113 -0
- package/dist/core/compat/pe.js +220 -0
- package/dist/core/compat/types.js +1 -0
- package/dist/core/compat/version.js +70 -0
- package/dist/core/deploy/guards.js +292 -0
- package/dist/core/deploy/index.js +5 -0
- package/dist/core/deploy/plan.js +696 -0
- package/dist/core/deploy/reload-apply.js +361 -0
- package/dist/core/deploy/reload.js +358 -0
- package/dist/core/deploy/sources.js +169 -0
- package/dist/core/deploy/types.js +1 -0
- package/dist/core/epic.js +54 -0
- package/dist/core/fsutil.js +191 -0
- package/dist/core/home.js +70 -0
- package/dist/core/knowledge/facts.js +229 -0
- package/dist/core/knowledge/index.js +4 -0
- package/dist/core/knowledge/search.js +112 -0
- package/dist/core/knowledge/store.js +123 -0
- package/dist/core/knowledge/types.js +1 -0
- package/dist/core/ledger/check.js +42 -0
- package/dist/core/ledger/hooks.js +80 -0
- package/dist/core/ledger/index.js +7 -0
- package/dist/core/ledger/query.js +17 -0
- package/dist/core/ledger/record.js +84 -0
- package/dist/core/ledger/status.js +53 -0
- package/dist/core/ledger/store.js +98 -0
- package/dist/core/ledger/types.js +108 -0
- package/dist/core/logs/index.js +4 -0
- package/dist/core/logs/registry.js +50 -0
- package/dist/core/logs/scan.js +195 -0
- package/dist/core/logs/triage.js +160 -0
- package/dist/core/logs/types.js +1 -0
- package/dist/core/lsx.js +10 -0
- package/dist/core/lz4.js +66 -0
- package/dist/core/mods.js +229 -0
- package/dist/core/process.js +49 -0
- package/dist/core/project/build-steps.js +83 -0
- package/dist/core/project/describe.js +74 -0
- package/dist/core/project/index.js +5 -0
- package/dist/core/project/load.js +146 -0
- package/dist/core/project/schema.js +264 -0
- package/dist/core/project/types.js +3 -0
- package/dist/core/prompts.js +72 -0
- package/dist/core/registry.js +35 -0
- package/dist/core/safety/backup.js +206 -0
- package/dist/core/safety/execute.js +188 -0
- package/dist/core/safety/index.js +5 -0
- package/dist/core/safety/plan.js +122 -0
- package/dist/core/safety/restore.js +172 -0
- package/dist/core/safety/types.js +1 -0
- package/dist/core/scaffold/bootstrap.js +7 -0
- package/dist/core/scaffold/catalog.js +28 -0
- package/dist/core/scaffold/claude-assets.js +271 -0
- package/dist/core/scaffold/collisions.js +64 -0
- package/dist/core/scaffold/emit.js +356 -0
- package/dist/core/scaffold/engine.js +680 -0
- package/dist/core/scaffold/ids.js +78 -0
- package/dist/core/scaffold/index.js +10 -0
- package/dist/core/scaffold/jsonpath.js +121 -0
- package/dist/core/scaffold/load.js +81 -0
- package/dist/core/scaffold/render.js +85 -0
- package/dist/core/scaffold/sequence.js +396 -0
- package/dist/core/scaffold/types.js +309 -0
- package/dist/core/steam.js +63 -0
- package/dist/core/surfaceutil.js +36 -0
- package/dist/core/testplan/check.js +67 -0
- package/dist/core/testplan/index.js +5 -0
- package/dist/core/testplan/load.js +100 -0
- package/dist/core/testplan/registry.js +317 -0
- package/dist/core/testplan/run.js +389 -0
- package/dist/core/testplan/types.js +82 -0
- package/dist/core/text/converters/bg3.js +50 -0
- package/dist/core/text/converters/cyberpunk.js +36 -0
- package/dist/core/text/converters/index.js +261 -0
- package/dist/core/text/diff/cr2w.js +180 -0
- package/dist/core/text/diff/index.js +16 -0
- package/dist/core/text/diff/loca.js +43 -0
- package/dist/core/text/diff/lsx.js +126 -0
- package/dist/core/text/handles.js +86 -0
- package/dist/core/text/index.js +6 -0
- package/dist/core/text/json.js +46 -0
- package/dist/core/text/templates/cache.js +71 -0
- package/dist/core/text/templates/index.js +3 -0
- package/dist/core/text/templates/library.js +245 -0
- package/dist/core/text/templates/types.js +51 -0
- package/dist/core/text/toolchain.js +16 -0
- package/dist/core/text/types.js +1 -0
- package/dist/core/text/validate.js +149 -0
- package/dist/core/text/xml.js +58 -0
- package/dist/core/toolchain/datafetch.js +151 -0
- package/dist/core/toolchain/env.js +63 -0
- package/dist/core/toolchain/features.js +170 -0
- package/dist/core/toolchain/index.js +8 -0
- package/dist/core/toolchain/install.js +191 -0
- package/dist/core/toolchain/locate.js +275 -0
- package/dist/core/toolchain/remember.js +84 -0
- package/dist/core/toolchain/run.js +318 -0
- package/dist/core/toolchain/specs.js +351 -0
- package/dist/core/toolchain/types.js +1 -0
- package/dist/core/types.js +1 -0
- package/dist/core/userconfig.js +66 -0
- package/dist/core/validate/context.js +139 -0
- package/dist/core/validate/index.js +5 -0
- package/dist/core/validate/registry.js +58 -0
- package/dist/core/validate/run.js +131 -0
- package/dist/core/validate/suppressions.js +91 -0
- package/dist/core/validate/types.js +2 -0
- package/dist/core/yamledit.js +51 -0
- package/dist/index.js +389 -0
- package/dist/server.js +1914 -0
- package/dist/surfaces/baldursgate3/compat.js +164 -0
- package/dist/surfaces/baldursgate3/identity.js +110 -0
- package/dist/surfaces/baldursgate3/index/build.js +331 -0
- package/dist/surfaces/baldursgate3/index/index.js +17 -0
- package/dist/surfaces/baldursgate3/index/info.js +40 -0
- package/dist/surfaces/baldursgate3/index/parsers/loca.js +41 -0
- package/dist/surfaces/baldursgate3/index/parsers/lsx.js +137 -0
- package/dist/surfaces/baldursgate3/index/parsers/stats.js +45 -0
- package/dist/surfaces/baldursgate3/index/parsers/treasuretable.js +57 -0
- package/dist/surfaces/baldursgate3/index/parsers/xmlutil.js +142 -0
- package/dist/surfaces/baldursgate3/index/queries.js +327 -0
- package/dist/surfaces/baldursgate3/index/schema.js +62 -0
- package/dist/surfaces/baldursgate3/index.js +3 -0
- package/dist/surfaces/baldursgate3/logs.js +278 -0
- package/dist/surfaces/baldursgate3/modsettings.js +115 -0
- package/dist/surfaces/baldursgate3/pak.js +153 -0
- package/dist/surfaces/baldursgate3/settings.js +49 -0
- package/dist/surfaces/baldursgate3/surface.js +232 -0
- package/dist/surfaces/baldursgate3/validators/bridge.js +7 -0
- package/dist/surfaces/baldursgate3/validators/files.js +476 -0
- package/dist/surfaces/baldursgate3/validators/items.js +1001 -0
- package/dist/surfaces/baldursgate3/validators/progression.js +734 -0
- package/dist/surfaces/baldursgate3/validators/stats.js +1076 -0
- package/dist/surfaces/baldursgate3/validators/story.js +790 -0
- package/dist/surfaces/baldursgate3/validators/templates.js +7 -0
- package/dist/surfaces/cyberpunk2077/compat.js +223 -0
- package/dist/surfaces/cyberpunk2077/index/build.js +231 -0
- package/dist/surfaces/cyberpunk2077/index/index.js +17 -0
- package/dist/surfaces/cyberpunk2077/index/info.js +51 -0
- package/dist/surfaces/cyberpunk2077/index/model.js +52 -0
- package/dist/surfaces/cyberpunk2077/index/parsers/tweak.js +483 -0
- package/dist/surfaces/cyberpunk2077/index/parsers/tweakxl-yaml.js +183 -0
- package/dist/surfaces/cyberpunk2077/index/queries.js +504 -0
- package/dist/surfaces/cyberpunk2077/index/resource.js +135 -0
- package/dist/surfaces/cyberpunk2077/index/schema.js +90 -0
- package/dist/surfaces/cyberpunk2077/index.js +3 -0
- package/dist/surfaces/cyberpunk2077/logs.js +742 -0
- package/dist/surfaces/cyberpunk2077/paths.js +12 -0
- package/dist/surfaces/cyberpunk2077/surface.js +218 -0
- package/dist/surfaces/cyberpunk2077/validators/bridge.js +7 -0
- package/dist/surfaces/cyberpunk2077/validators/cr2w.js +349 -0
- package/dist/surfaces/cyberpunk2077/validators/garments.js +1181 -0
- package/dist/surfaces/cyberpunk2077/validators/mesh.js +338 -0
- package/dist/surfaces/cyberpunk2077/validators/modsettings.js +120 -0
- package/dist/surfaces/cyberpunk2077/validators/packaging.js +463 -0
- package/dist/surfaces/cyberpunk2077/validators/red4ext.js +318 -0
- package/dist/surfaces/cyberpunk2077/validators/redscript.js +193 -0
- package/dist/surfaces/cyberpunk2077/validators/templates.js +7 -0
- package/dist/surfaces/cyberpunk2077/validators/tweaks.js +768 -0
- package/dist/surfaces/cyberpunk2077/validators/vehicles.js +531 -0
- package/dist/surfaces/cyberpunk2077/validators/xl.js +308 -0
- package/dist/surfaces/eldenring/binders.js +111 -0
- package/dist/surfaces/eldenring/compat.js +166 -0
- package/dist/surfaces/eldenring/dcx.js +49 -0
- package/dist/surfaces/eldenring/index.js +13 -0
- package/dist/surfaces/eldenring/loaders.js +132 -0
- package/dist/surfaces/eldenring/logs.js +67 -0
- package/dist/surfaces/eldenring/paramdef.js +256 -0
- package/dist/surfaces/eldenring/params.js +129 -0
- package/dist/surfaces/eldenring/surface.js +121 -0
- package/dist/surfaces/eldenring/tools.js +52 -0
- package/dist/surfaces/eldenring/validators/binders.js +193 -0
- package/dist/surfaces/eldenring/validators/packages.js +159 -0
- package/dist/surfaces/eldenring/validators/params.js +334 -0
- package/dist/surfaces/eldenring/validators/profiles.js +287 -0
- package/dist/surfaces/index.js +34 -0
- package/dist/surfaces/nivalisnights/compat.js +229 -0
- package/dist/surfaces/nivalisnights/index/build.js +310 -0
- package/dist/surfaces/nivalisnights/index/index.js +5 -0
- package/dist/surfaces/nivalisnights/index/queries.js +231 -0
- package/dist/surfaces/nivalisnights/index.js +4 -0
- package/dist/surfaces/nivalisnights/logs.js +473 -0
- package/dist/surfaces/nivalisnights/surface.js +195 -0
- package/dist/surfaces/skyrimse/archives.js +229 -0
- package/dist/surfaces/skyrimse/compat.js +163 -0
- package/dist/surfaces/skyrimse/index.js +12 -0
- package/dist/surfaces/skyrimse/loadorder.js +174 -0
- package/dist/surfaces/skyrimse/logs.js +241 -0
- package/dist/surfaces/skyrimse/plugins.js +149 -0
- package/dist/surfaces/skyrimse/records.js +94 -0
- package/dist/surfaces/skyrimse/surface.js +240 -0
- package/dist/surfaces/skyrimse/validators/archive-records.js +165 -0
- package/dist/surfaces/skyrimse/validators/archives.js +110 -0
- package/dist/surfaces/skyrimse/validators/plugins.js +374 -0
- package/dist/surfaces/skyrimse/validators/records.js +117 -0
- package/dist/surfaces/stardewvalley/compat.js +190 -0
- package/dist/surfaces/stardewvalley/config.js +42 -0
- package/dist/surfaces/stardewvalley/contentpatcher.js +203 -0
- package/dist/surfaces/stardewvalley/index/index.js +229 -0
- package/dist/surfaces/stardewvalley/index/wiki.js +190 -0
- package/dist/surfaces/stardewvalley/index.js +12 -0
- package/dist/surfaces/stardewvalley/logs.js +307 -0
- package/dist/surfaces/stardewvalley/mods.js +182 -0
- package/dist/surfaces/stardewvalley/surface.js +244 -0
- package/dist/surfaces/stardewvalley/validators/content.js +321 -0
- package/dist/surfaces/stardewvalley/validators/fields.js +147 -0
- package/dist/surfaces/stardewvalley/validators/loadorder.js +69 -0
- package/dist/surfaces/stardewvalley/validators/manifest.js +221 -0
- package/dist/surfaces/subnautica2/compat.js +138 -0
- package/dist/surfaces/subnautica2/index.js +5 -0
- package/dist/surfaces/subnautica2/logs.js +129 -0
- package/dist/surfaces/subnautica2/paks.js +173 -0
- package/dist/surfaces/subnautica2/surface.js +151 -0
- package/dist/surfaces/subnautica2/validators/packaging.js +298 -0
- package/dist/surfaces/valheim/compat.js +171 -0
- package/dist/surfaces/valheim/index/index.js +301 -0
- package/dist/surfaces/valheim/index/tables.js +103 -0
- package/dist/surfaces/valheim/index.js +11 -0
- package/dist/surfaces/valheim/logs.js +197 -0
- package/dist/surfaces/valheim/packaging.js +131 -0
- package/dist/surfaces/valheim/plugins.js +270 -0
- package/dist/surfaces/valheim/references.js +121 -0
- package/dist/surfaces/valheim/surface.js +223 -0
- package/dist/surfaces/valheim/validators/packaging.js +218 -0
- package/dist/surfaces/valheim/validators/plugins.js +287 -0
- package/dist/surfaces/valheim/validators/references.js +169 -0
- package/knowledge/baldursgate3/animations.gr2.yaml +166 -0
- package/knowledge/baldursgate3/audio.voice.yaml +182 -0
- package/knowledge/baldursgate3/audio.wwise.yaml +104 -0
- package/knowledge/baldursgate3/charactercreation.heads-hair.yaml +193 -0
- package/knowledge/baldursgate3/communitylibrary.shared-content.yaml +129 -0
- package/knowledge/baldursgate3/compatibilityframework.api.yaml +176 -0
- package/knowledge/baldursgate3/crash.causes.yaml +90 -0
- package/knowledge/baldursgate3/dialogue.dialogbank.yaml +120 -0
- package/knowledge/baldursgate3/dialogue.files.yaml +236 -0
- package/knowledge/baldursgate3/dialogue.osiris-goals.yaml +386 -0
- package/knowledge/baldursgate3/dialogue.yaml +122 -0
- package/knowledge/baldursgate3/feats.classes.yaml +164 -0
- package/knowledge/baldursgate3/items.cloth-physics.yaml +167 -0
- package/knowledge/baldursgate3/items.roottemplates.yaml +320 -0
- package/knowledge/baldursgate3/items.visualbank.yaml +628 -0
- package/knowledge/baldursgate3/journal.quests.yaml +214 -0
- package/knowledge/baldursgate3/loadorder.modsettings.yaml +128 -0
- package/knowledge/baldursgate3/localization.handles.yaml +92 -0
- package/knowledge/baldursgate3/misc.encoding-and-practice.yaml +111 -0
- package/knowledge/baldursgate3/origins.companions.yaml +144 -0
- package/knowledge/baldursgate3/osiris.signatures.yaml +211 -0
- package/knowledge/baldursgate3/packaging.meta.yaml +155 -0
- package/knowledge/baldursgate3/packaging.paks.yaml +79 -0
- package/knowledge/baldursgate3/process.launch.yaml +34 -0
- package/knowledge/baldursgate3/progressions.yaml +92 -0
- package/knowledge/baldursgate3/publishing.modio-nexus.yaml +170 -0
- package/knowledge/baldursgate3/publishing.toolkit-modio.yaml +135 -0
- package/knowledge/baldursgate3/races.progression.yaml +228 -0
- package/knowledge/baldursgate3/scriptextender.console.yaml +257 -0
- package/knowledge/baldursgate3/scriptextender.yaml +252 -0
- package/knowledge/baldursgate3/stats.boosts.yaml +293 -0
- package/knowledge/baldursgate3/stats.equipment-kits.yaml +69 -0
- package/knowledge/baldursgate3/stats.interrupts.yaml +45 -0
- package/knowledge/baldursgate3/stats.itemcombos.yaml +65 -0
- package/knowledge/baldursgate3/stats.spells.yaml +293 -0
- package/knowledge/baldursgate3/stats.weapons.yaml +210 -0
- package/knowledge/baldursgate3/toolchain.divine.yaml +179 -0
- package/knowledge/baldursgate3/toolchain.lslib-formats.yaml +242 -0
- package/knowledge/baldursgate3/toolkit.levels.yaml +177 -0
- package/knowledge/baldursgate3/ui.icons-atlas.yaml +78 -0
- package/knowledge/baldursgate3/ui.icons.yaml +412 -0
- package/knowledge/baldursgate3/ui.mcm.yaml +161 -0
- package/knowledge/baldursgate3/vfx.materials.yaml +174 -0
- package/knowledge/baldursgate3/visuals.characterfix.yaml +73 -0
- package/knowledge/cyberpunk2077/animations.anims.yaml +118 -0
- package/knowledge/cyberpunk2077/anims.archivexl.yaml +163 -0
- package/knowledge/cyberpunk2077/anims.authoring.yaml +579 -0
- package/knowledge/cyberpunk2077/anims.encoder.yaml +156 -0
- package/knowledge/cyberpunk2077/anims.graph.yaml +629 -0
- package/knowledge/cyberpunk2077/anims.method.yaml +360 -0
- package/knowledge/cyberpunk2077/anims.pipeline.yaml +352 -0
- package/knowledge/cyberpunk2077/anims.roundtrip.yaml +222 -0
- package/knowledge/cyberpunk2077/anims.sets.yaml +176 -0
- package/knowledge/cyberpunk2077/archivexl.bodytypes.yaml +149 -0
- package/knowledge/cyberpunk2077/archivexl.dynamic-appearances.yaml +218 -0
- package/knowledge/cyberpunk2077/archivexl.manifest.yaml +214 -0
- package/knowledge/cyberpunk2077/audio.events.yaml +168 -0
- package/knowledge/cyberpunk2077/audio.sounds.yaml +164 -0
- package/knowledge/cyberpunk2077/audio.voicesets.yaml +146 -0
- package/knowledge/cyberpunk2077/cet.sandbox.yaml +219 -0
- package/knowledge/cyberpunk2077/clothing.garments.yaml +283 -0
- package/knowledge/cyberpunk2077/clothing.refits.yaml +215 -0
- package/knowledge/cyberpunk2077/codeware.overview.yaml +111 -0
- package/knowledge/cyberpunk2077/codeware.systems.yaml +192 -0
- package/knowledge/cyberpunk2077/drones.combat.yaml +416 -0
- package/knowledge/cyberpunk2077/drones.control.yaml +552 -0
- package/knowledge/cyberpunk2077/entities.appearance.yaml +166 -0
- package/knowledge/cyberpunk2077/equipmentex.slots.yaml +151 -0
- package/knowledge/cyberpunk2077/fx.effects.yaml +246 -0
- package/knowledge/cyberpunk2077/fx.lights.yaml +171 -0
- package/knowledge/cyberpunk2077/hair.modding.yaml +145 -0
- package/knowledge/cyberpunk2077/items.wiring.yaml +246 -0
- package/knowledge/cyberpunk2077/loadorder.archives.yaml +71 -0
- package/knowledge/cyberpunk2077/mesh.blender.yaml +209 -0
- package/knowledge/cyberpunk2077/nativedb.dump.yaml +98 -0
- package/knowledge/cyberpunk2077/npc.appearance.yaml +275 -0
- package/knowledge/cyberpunk2077/npc.behaviour.yaml +128 -0
- package/knowledge/cyberpunk2077/npc.locomotion.yaml +490 -0
- package/knowledge/cyberpunk2077/packaging.deploy.yaml +175 -0
- package/knowledge/cyberpunk2077/packaging.variants.yaml +176 -0
- package/knowledge/cyberpunk2077/player.control.yaml +918 -0
- package/knowledge/cyberpunk2077/process.assetbuild.yaml +154 -0
- package/knowledge/cyberpunk2077/process.lessons.yaml +276 -0
- package/knowledge/cyberpunk2077/quests.minor.yaml +46 -0
- package/knowledge/cyberpunk2077/quests.scenes.yaml +282 -0
- package/knowledge/cyberpunk2077/quickhacks.tiers.yaml +41 -0
- package/knowledge/cyberpunk2077/red4ext.api.yaml +645 -0
- package/knowledge/cyberpunk2077/red4ext.plugins.yaml +124 -0
- package/knowledge/cyberpunk2077/redhottools.hotreload.yaml +245 -0
- package/knowledge/cyberpunk2077/redscript.compile-log.yaml +76 -0
- package/knowledge/cyberpunk2077/redscript.modules.yaml +118 -0
- package/knowledge/cyberpunk2077/toolchain.wolvenkit.yaml +163 -0
- package/knowledge/cyberpunk2077/tweakdb.loot-recipes.yaml +184 -0
- package/knowledge/cyberpunk2077/tweakdb.melee.yaml +352 -0
- package/knowledge/cyberpunk2077/tweakdb.weapons.yaml +325 -0
- package/knowledge/cyberpunk2077/tweakxl.hotreload.yaml +151 -0
- package/knowledge/cyberpunk2077/tweakxl.yaml-syntax.yaml +208 -0
- package/knowledge/cyberpunk2077/ui.icons.yaml +259 -0
- package/knowledge/cyberpunk2077/ui.inkatlas.yaml +81 -0
- package/knowledge/cyberpunk2077/ui.modsettings.yaml +204 -0
- package/knowledge/cyberpunk2077/vehicles.control.yaml +475 -0
- package/knowledge/cyberpunk2077/vehicles.dashboard-ui.yaml +203 -0
- package/knowledge/cyberpunk2077/vehicles.entities.yaml +195 -0
- package/knowledge/cyberpunk2077/vehicles.wiring.yaml +137 -0
- package/knowledge/cyberpunk2077/wolvenkit.cli.yaml +167 -0
- package/knowledge/cyberpunk2077/workspot.system.yaml +55 -0
- package/knowledge/cyberpunk2077/world.interactions.yaml +41 -0
- package/knowledge/cyberpunk2077/world.loot-container.yaml +167 -0
- package/knowledge/cyberpunk2077/world.sectors.yaml +233 -0
- package/knowledge/eldenring/formats.binders.yaml +237 -0
- package/knowledge/eldenring/launcher.me3.yaml +230 -0
- package/knowledge/eldenring/launcher.modengine2.yaml +119 -0
- package/knowledge/eldenring/params.paramdef.yaml +149 -0
- package/knowledge/eldenring/params.regulation.yaml +142 -0
- package/knowledge/eldenring/saves.online.yaml +118 -0
- package/knowledge/eldenring/toolchain.cli.yaml +256 -0
- package/knowledge/nivalisnights/modding.runtime.yaml +157 -0
- package/knowledge/skyrimse/archives.bsa.yaml +212 -0
- package/knowledge/skyrimse/install.detection.yaml +41 -0
- package/knowledge/skyrimse/loadorder.files.yaml +242 -0
- package/knowledge/skyrimse/plugins.esl.yaml +189 -0
- package/knowledge/skyrimse/plugins.format.yaml +224 -0
- package/knowledge/skyrimse/skse.runtime.yaml +283 -0
- package/knowledge/skyrimse/toolchain.xedit-spriggit.yaml +336 -0
- package/knowledge/stardewvalley/contentpatcher.format.yaml +338 -0
- package/knowledge/stardewvalley/distribution.channels.yaml +236 -0
- package/knowledge/stardewvalley/game.versions.yaml +202 -0
- package/knowledge/stardewvalley/install.layout.yaml +277 -0
- package/knowledge/stardewvalley/smapi.loader.yaml +284 -0
- package/knowledge/stardewvalley/smapi.logs.yaml +329 -0
- package/knowledge/stardewvalley/smapi.manifest.yaml +293 -0
- package/knowledge/stardewvalley/toolchain.build.yaml +261 -0
- package/knowledge/stardewvalley/wiki.dataformat.yaml +130 -0
- package/knowledge/subnautica2/game.build.yaml +331 -0
- package/knowledge/subnautica2/modding.state.yaml +210 -0
- package/knowledge/subnautica2/ue5.containers.yaml +72 -0
- package/knowledge/subnautica2/ue5.paks.yaml +203 -0
- package/knowledge/subnautica2/ue5.tooling.yaml +175 -0
- package/knowledge/subnautica2/ue5.ue4ss.yaml +203 -0
- package/knowledge/valheim/bepinex.loader.yaml +247 -0
- package/knowledge/valheim/bepinex.plugins.yaml +251 -0
- package/knowledge/valheim/game.versions.yaml +321 -0
- package/knowledge/valheim/install.layout.yaml +216 -0
- package/knowledge/valheim/jotunn.library.yaml +334 -0
- package/knowledge/valheim/thunderstore.packaging.yaml +217 -0
- package/knowledge/valheim/toolchain.build.yaml +111 -0
- package/package.json +29 -0
- package/scaffolds/baldursgate3/new-class-injection.yaml +148 -0
- package/scaffolds/baldursgate3/new-item.yaml +264 -0
- package/scaffolds/baldursgate3/new-mod.yaml +174 -0
- package/scaffolds/baldursgate3/new-passive.yaml +100 -0
- package/scaffolds/baldursgate3/new-project.yaml +118 -0
- package/scaffolds/baldursgate3/new-quest-stub.yaml +159 -0
- package/scaffolds/baldursgate3/new-spell.yaml +102 -0
- package/scaffolds/baldursgate3/new-status.yaml +119 -0
- package/scaffolds/baldursgate3/sequences/subclass-kit.yaml +50 -0
- package/scaffolds/cyberpunk2077/edit-tweak.yaml +70 -0
- package/scaffolds/cyberpunk2077/mesh-export-preset.yaml +170 -0
- package/scaffolds/cyberpunk2077/new-entity-patch.yaml +255 -0
- package/scaffolds/cyberpunk2077/new-garment-refit.yaml +279 -0
- package/scaffolds/cyberpunk2077/new-item-chain.yaml +548 -0
- package/scaffolds/cyberpunk2077/new-localization.yaml +130 -0
- package/scaffolds/cyberpunk2077/new-mod-settings.yaml +133 -0
- package/scaffolds/cyberpunk2077/new-player-replacer.yaml +1003 -0
- package/scaffolds/cyberpunk2077/new-project.yaml +157 -0
- package/scaffolds/cyberpunk2077/new-sector-node.yaml +156 -0
- package/scaffolds/cyberpunk2077/new-tweak.yaml +121 -0
- package/scaffolds/cyberpunk2077/new-vehicle-livery.yaml +148 -0
- package/scaffolds/cyberpunk2077/new-workspot-entity.yaml +177 -0
- package/scaffolds/cyberpunk2077/sequences/iconic-weapon.yaml +72 -0
- package/scaffolds/cyberpunk2077/sequences/quickhack-takeover.yaml +213 -0
- package/scaffolds/stardewvalley/new-cp-patch.yaml +106 -0
- package/scaffolds/stardewvalley/new-csharp-mod.yaml +195 -0
- package/scaffolds/stardewvalley/new-project.yaml +184 -0
- package/scaffolds/stardewvalley/sequences/content-pack.yaml +31 -0
- package/scripts/mw-tool.mjs +184 -0
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
const BE788 = "https://github.com/BepInEx/BepInEx/blob/5b766a3b7f6c164d4798924a93f3acf4db769d06";
|
|
2
|
+
const CHAINLOADER = `${BE788}/BepInEx.Core/Bootstrap/BaseChainloader.cs`;
|
|
3
|
+
const INTEROP = `${BE788}/Runtimes/Unity/BepInEx.Unity.IL2CPP/Il2CppInteropManager.cs`;
|
|
4
|
+
const REAL_BEPINEX = "test/fixtures/logs/nivalisnights/real/LogOutput.head.log (field 2026-10-03)";
|
|
5
|
+
const REAL_PLAYER = "test/fixtures/logs/nivalisnights/real/Player.excerpt.log (field 2026-10-03)";
|
|
6
|
+
const LITERALS = "global-metadata.dat string literals";
|
|
7
|
+
const PRE = String.raw `^\[(?<level>Fatal|Error|Warning|Message|Info|Debug)\s*:\s*(?<source>.+?)\] `;
|
|
8
|
+
function re(body) {
|
|
9
|
+
return new RegExp(PRE + body);
|
|
10
|
+
}
|
|
11
|
+
const BEPINEX = [
|
|
12
|
+
{
|
|
13
|
+
id: "nivalisnights.bepinex.version-banner",
|
|
14
|
+
game: "nivalisnights",
|
|
15
|
+
sources: ["bepinex"],
|
|
16
|
+
severity: "info",
|
|
17
|
+
category: "version",
|
|
18
|
+
pattern: re(String.raw `BepInEx (?<version>\d[\w.\-+]*) - (?<process>.+?)(?: \(|$)`),
|
|
19
|
+
explain: "BepInEx started and named its build and the process it attached to. The community's tested build is 6.0.0-be.788.",
|
|
20
|
+
seenIn: [CHAINLOADER, REAL_BEPINEX],
|
|
21
|
+
extract: ["version", "process"],
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
id: "nivalisnights.bepinex.unity-banner",
|
|
25
|
+
game: "nivalisnights",
|
|
26
|
+
sources: ["bepinex"],
|
|
27
|
+
severity: "info",
|
|
28
|
+
category: "version",
|
|
29
|
+
pattern: re(String.raw `Running under Unity v?(?<unity>[\w.]+)`),
|
|
30
|
+
explain: "The Unity version BepInEx detected (2020.3.44f1 for this game); interop and AssetBundles are bound to it.",
|
|
31
|
+
seenIn: [REAL_BEPINEX],
|
|
32
|
+
extract: ["unity"],
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: "nivalisnights.bepinex.runtime",
|
|
36
|
+
game: "nivalisnights",
|
|
37
|
+
sources: ["bepinex"],
|
|
38
|
+
severity: "info",
|
|
39
|
+
category: "version",
|
|
40
|
+
pattern: re(String.raw `Runtime version: (?<runtime>[\w.]+)`),
|
|
41
|
+
explain: "The .NET runtime BepInEx's IL2CPP build hosts plugins on (its own dotnet/ folder); plugins must target net6.0.",
|
|
42
|
+
seenIn: [REAL_BEPINEX],
|
|
43
|
+
extract: ["runtime"],
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
id: "nivalisnights.bepinex.plugin-count",
|
|
47
|
+
game: "nivalisnights",
|
|
48
|
+
sources: ["bepinex"],
|
|
49
|
+
severity: "info",
|
|
50
|
+
category: "load",
|
|
51
|
+
pattern: re(String.raw `(?<count>\d+) plugins? to load`),
|
|
52
|
+
explain: "How many plugins the chainloader found to load this run.",
|
|
53
|
+
seenIn: [CHAINLOADER, REAL_BEPINEX],
|
|
54
|
+
extract: ["count"],
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: "nivalisnights.bepinex.plugin-loaded",
|
|
58
|
+
game: "nivalisnights",
|
|
59
|
+
sources: ["bepinex"],
|
|
60
|
+
severity: "info",
|
|
61
|
+
category: "load",
|
|
62
|
+
pattern: re(String.raw `Loading \[(?<plugin>.+) (?<version>[^\s\]]+)\]$`),
|
|
63
|
+
explain: "One per plugin the chainloader loads, in dependency order; the roll-call of what is live.",
|
|
64
|
+
seenIn: [CHAINLOADER, REAL_BEPINEX],
|
|
65
|
+
extract: ["plugin", "version"],
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
id: "nivalisnights.bepinex.chainloader-complete",
|
|
69
|
+
game: "nivalisnights",
|
|
70
|
+
sources: ["bepinex"],
|
|
71
|
+
severity: "info",
|
|
72
|
+
category: "success",
|
|
73
|
+
pattern: re(String.raw `Chainloader startup complete`),
|
|
74
|
+
explain: "Every plugin that was going to load has loaded. A plugin's runtime exceptions land in Player.log, not here.",
|
|
75
|
+
seenIn: [CHAINLOADER, REAL_BEPINEX],
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
id: "nivalisnights.bepinex.missing-dependency",
|
|
79
|
+
game: "nivalisnights",
|
|
80
|
+
sources: ["bepinex"],
|
|
81
|
+
severity: "error",
|
|
82
|
+
category: "order",
|
|
83
|
+
pattern: re(String.raw `Could not load \[(?<plugin>.+?)\] because it has missing dependencies: (?<missing>.+?)(?:\. Install the listed plugin\(s\) and restart the game\.)?$`),
|
|
84
|
+
explain: "A plugin declared a hard dependency that is not installed; the plugin is skipped.",
|
|
85
|
+
hint: "Install the listed dependency (the name is its plugin GUID). Some Nivalis Nights mods need BepInEx.Utility.IL2CPP from GitHub.",
|
|
86
|
+
seenIn: [CHAINLOADER],
|
|
87
|
+
extract: ["plugin", "missing"],
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
id: "nivalisnights.bepinex.incompatible-version",
|
|
91
|
+
game: "nivalisnights",
|
|
92
|
+
sources: ["bepinex"],
|
|
93
|
+
severity: "error",
|
|
94
|
+
category: "version",
|
|
95
|
+
pattern: re(String.raw `Could not load \[(?<plugin>.+?)\] because the following dependencies are installed with an incompatible version: (?<deps>.+?)(?:\. Update the listed plugin\(s\).*)?$`),
|
|
96
|
+
explain: "A dependency is installed but outside the version range the plugin declares; the plugin is skipped.",
|
|
97
|
+
hint: "Update the listed dependency to a version in the stated range.",
|
|
98
|
+
seenIn: [CHAINLOADER],
|
|
99
|
+
extract: ["plugin", "deps"],
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
id: "nivalisnights.bepinex.dependency-cascade",
|
|
103
|
+
game: "nivalisnights",
|
|
104
|
+
sources: ["bepinex"],
|
|
105
|
+
severity: "warn",
|
|
106
|
+
category: "order",
|
|
107
|
+
pattern: re(String.raw `Skipping \[(?<plugin>.+?)\] because it has a dependency that was not loaded`),
|
|
108
|
+
explain: "A plugin was skipped because one it depends on failed earlier; fix the first failure and this one clears.",
|
|
109
|
+
seenIn: [CHAINLOADER],
|
|
110
|
+
extract: ["plugin"],
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
id: "nivalisnights.bepinex.wrong-bepinex-version",
|
|
114
|
+
game: "nivalisnights",
|
|
115
|
+
sources: ["bepinex"],
|
|
116
|
+
severity: "warn",
|
|
117
|
+
category: "version",
|
|
118
|
+
pattern: re(String.raw `Plugin \[(?<plugin>.+?)\] targets a wrong version of BepInEx \((?<targeted>[\w.]+)\) and might not work until you update`),
|
|
119
|
+
explain: "The plugin references a different BepInEx.Core than the one installed; it still loads, and may or may not work.",
|
|
120
|
+
seenIn: [CHAINLOADER],
|
|
121
|
+
extract: ["plugin", "targeted"],
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
id: "nivalisnights.bepinex.similar-guid",
|
|
125
|
+
game: "nivalisnights",
|
|
126
|
+
sources: ["bepinex"],
|
|
127
|
+
severity: "warn",
|
|
128
|
+
category: "order",
|
|
129
|
+
pattern: re(String.raw `Skipping \[(?<plugin>.+?)\] because a plugin with a similar GUID \(\[(?<loaded>.+?)\]\) has been already loaded`),
|
|
130
|
+
explain: "Two plugins' GUIDs differ only in case or punctuation; BepInEx 6 keeps the first and drops this one.",
|
|
131
|
+
seenIn: [CHAINLOADER],
|
|
132
|
+
extract: ["plugin", "loaded"],
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
id: "nivalisnights.bepinex.duplicate-guid",
|
|
136
|
+
game: "nivalisnights",
|
|
137
|
+
sources: ["bepinex"],
|
|
138
|
+
severity: "warn",
|
|
139
|
+
category: "order",
|
|
140
|
+
pattern: re(String.raw `Skipping \[(?<plugin>.+?)\] because a newer version exists \((?<newer>.+?)\)`),
|
|
141
|
+
explain: "Two copies of one plugin GUID are installed; the older is dropped. Usually an update extracted beside the old folder instead of over it.",
|
|
142
|
+
seenIn: [CHAINLOADER],
|
|
143
|
+
extract: ["plugin", "newer"],
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
id: "nivalisnights.bepinex.process-filtered",
|
|
147
|
+
game: "nivalisnights",
|
|
148
|
+
sources: ["bepinex"],
|
|
149
|
+
severity: "info",
|
|
150
|
+
category: "load",
|
|
151
|
+
pattern: re(String.raw `Skipping \[(?<plugin>.+?)\] because of process filters \((?<filters>.+?)\)`),
|
|
152
|
+
explain: "The plugin declares it runs only in another process and was skipped on purpose; it was likely built for a different game.",
|
|
153
|
+
seenIn: [CHAINLOADER],
|
|
154
|
+
extract: ["plugin", "filters"],
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
id: "nivalisnights.bepinex.plugin-load-error",
|
|
158
|
+
game: "nivalisnights",
|
|
159
|
+
sources: ["bepinex"],
|
|
160
|
+
severity: "error",
|
|
161
|
+
category: "load",
|
|
162
|
+
pattern: re(String.raw `Error loading \[(?<plugin>.+?)\]\s*:`),
|
|
163
|
+
explain: "The plugin threw while loading; the exception follows. After a game update this is usually a type or method the interop no longer has.",
|
|
164
|
+
hint: "Check the plugin's page for a build matching the current game update.",
|
|
165
|
+
seenIn: [CHAINLOADER],
|
|
166
|
+
extract: ["plugin"],
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
id: "nivalisnights.bepinex.metadata-rejected",
|
|
170
|
+
game: "nivalisnights",
|
|
171
|
+
sources: ["bepinex"],
|
|
172
|
+
severity: "warn",
|
|
173
|
+
category: "load",
|
|
174
|
+
pattern: re(String.raw `Skipping (?:over )?type \[(?<type>.+?)\] (?:as no metadata attribute is specified|because its (?<field>GUID|version|name))`),
|
|
175
|
+
explain: "A plugin class's [BepInPlugin] attribute is missing or malformed (GUID, version or name), so BepInEx does not treat it as a plugin.",
|
|
176
|
+
seenIn: [CHAINLOADER],
|
|
177
|
+
extract: ["type", "field"],
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
id: "nivalisnights.bepinex.loading-failed",
|
|
181
|
+
game: "nivalisnights",
|
|
182
|
+
sources: ["bepinex"],
|
|
183
|
+
severity: "error",
|
|
184
|
+
category: "crash",
|
|
185
|
+
pattern: re(String.raw `Error occurred loading plugins:`),
|
|
186
|
+
explain: "The chainloader itself failed while loading plugins; what loaded before the failure is all that is live.",
|
|
187
|
+
seenIn: [CHAINLOADER],
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
id: "nivalisnights.bepinex.interop-generating",
|
|
191
|
+
game: "nivalisnights",
|
|
192
|
+
sources: ["bepinex"],
|
|
193
|
+
severity: "info",
|
|
194
|
+
category: "load",
|
|
195
|
+
pattern: re(String.raw `Generating interop assemblies`),
|
|
196
|
+
explain: "BepInEx is building its interop assemblies from GameAssembly.dll: on the first launch after installing, and after every game update. It took about 25 s on this game; the game sits at a black screen meanwhile.",
|
|
197
|
+
seenIn: [INTEROP],
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
id: "nivalisnights.bepinex.interop-outdated",
|
|
201
|
+
game: "nivalisnights",
|
|
202
|
+
sources: ["bepinex"],
|
|
203
|
+
severity: "info",
|
|
204
|
+
category: "version",
|
|
205
|
+
pattern: re(String.raw `Detected outdated interop assemblies, will regenerate them now`),
|
|
206
|
+
explain: "GameAssembly.dll changed since the interop was built: the game updated. Interop regenerates by itself; plugins compiled against the old build may now fail.",
|
|
207
|
+
hint: "Watch this run's plugin errors; the game patches often (two updates in its first four days).",
|
|
208
|
+
seenIn: [INTEROP],
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
id: "nivalisnights.bepinex.interop-possibly-outdated",
|
|
212
|
+
game: "nivalisnights",
|
|
213
|
+
sources: ["bepinex"],
|
|
214
|
+
severity: "warn",
|
|
215
|
+
category: "version",
|
|
216
|
+
pattern: re(String.raw `Interop assemblies are possibly out of date`),
|
|
217
|
+
explain: "BepInEx could not confirm the interop matches the game binary and did not regenerate; plugins may bind to a stale API.",
|
|
218
|
+
hint: "Delete BepInEx/interop and BepInEx/cache and launch once to regenerate.",
|
|
219
|
+
seenIn: [INTEROP],
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
id: "nivalisnights.bepinex.interop-failed",
|
|
223
|
+
game: "nivalisnights",
|
|
224
|
+
sources: ["bepinex"],
|
|
225
|
+
severity: "error",
|
|
226
|
+
category: "crash",
|
|
227
|
+
pattern: re(String.raw `Failed to generate Il2Cpp interop assemblies:`),
|
|
228
|
+
explain: "Interop generation failed, so no plugin can load. The usual causes are the Unity base-library download (first launch needs network access) and a Cpp2IL failure on a new game build.",
|
|
229
|
+
hint: "Check the lines just above for the download or Cpp2IL error. Offline, place the unity-libs .zip for 2020.3.44 in BepInEx/unity-libs by hand.",
|
|
230
|
+
seenIn: [INTEROP],
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
id: "nivalisnights.bepinex.unity-libs-download",
|
|
234
|
+
game: "nivalisnights",
|
|
235
|
+
sources: ["bepinex"],
|
|
236
|
+
severity: "info",
|
|
237
|
+
category: "load",
|
|
238
|
+
pattern: re(String.raw `Downloading unity base libraries from (?<url>\S+)`),
|
|
239
|
+
explain: "First-launch step: BepInEx downloads Unity base libraries to build interop, so the first launch after installing needs network access.",
|
|
240
|
+
seenIn: [INTEROP],
|
|
241
|
+
extract: ["url"],
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
id: "nivalisnights.bepinex.unity-libs-download-failed",
|
|
245
|
+
game: "nivalisnights",
|
|
246
|
+
sources: ["bepinex"],
|
|
247
|
+
severity: "error",
|
|
248
|
+
category: "resource",
|
|
249
|
+
pattern: /Failed to download Unity base libraries for Unity (?<unity>\S+) from (?<url>\S+?):/,
|
|
250
|
+
explain: "The Unity base-library download failed, so interop cannot be generated and nothing loads.",
|
|
251
|
+
hint: "Retry with network access, or place the base-libraries .zip for this Unity version in BepInEx/unity-libs.",
|
|
252
|
+
seenIn: [INTEROP],
|
|
253
|
+
extract: ["unity", "url"],
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
id: "nivalisnights.harmony.target-not-found",
|
|
257
|
+
game: "nivalisnights",
|
|
258
|
+
sources: ["bepinex"],
|
|
259
|
+
severity: "warn",
|
|
260
|
+
category: "resource",
|
|
261
|
+
pattern: re(String.raw `AccessTools\.\w+: Could not find (?<kind>method|field|property|type) (?<target>.+)$`),
|
|
262
|
+
explain: "A plugin's patch reached for a game member that does not exist in this build, usually after a game update; that patch silently does nothing.",
|
|
263
|
+
hint: "The plugin needs an update for the current game version.",
|
|
264
|
+
seenIn: ["HarmonyX AccessTools; HarmonyX 2.10.2 ships in BE #788"],
|
|
265
|
+
extract: ["kind", "target"],
|
|
266
|
+
systemImpact: false,
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
id: "nivalisnights.harmony.undefined-target-method",
|
|
270
|
+
game: "nivalisnights",
|
|
271
|
+
sources: ["bepinex"],
|
|
272
|
+
severity: "error",
|
|
273
|
+
category: "resource",
|
|
274
|
+
pattern: re(String.raw `(?:[\w.]*Exception: )?Undefined target method for patch method (?<patch>.+)$`),
|
|
275
|
+
explain: "A Harmony patch declares a target this game build does not have; the patch is not applied and that plugin's feature is missing.",
|
|
276
|
+
hint: "The plugin needs an update for the current game version.",
|
|
277
|
+
seenIn: ["HarmonyX PatchClassProcessor; HarmonyX 2.10.2 ships in BE #788"],
|
|
278
|
+
extract: ["patch"],
|
|
279
|
+
systemImpact: false,
|
|
280
|
+
},
|
|
281
|
+
];
|
|
282
|
+
const PLAYER = [
|
|
283
|
+
{
|
|
284
|
+
id: "nivalisnights.player.engine-version",
|
|
285
|
+
game: "nivalisnights",
|
|
286
|
+
sources: ["player", "player-prev"],
|
|
287
|
+
severity: "info",
|
|
288
|
+
category: "version",
|
|
289
|
+
pattern: /^Initialize engine version: (?<unity>\S+)/,
|
|
290
|
+
explain: "The first line of a run: the Unity version the game starts on.",
|
|
291
|
+
seenIn: [REAL_PLAYER],
|
|
292
|
+
extract: ["unity"],
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
id: "nivalisnights.player.dev-mode",
|
|
296
|
+
game: "nivalisnights",
|
|
297
|
+
sources: ["player", "player-prev"],
|
|
298
|
+
severity: "info",
|
|
299
|
+
category: "load",
|
|
300
|
+
pattern: /^isDevMode:(?<value>True|False)\b/,
|
|
301
|
+
explain: "The game's own developer-mode check. It logs inside the getter before any Harmony postfix runs, so 'False' does not mean a plugin's forced dev mode failed; the plugin's own log line is the authority.",
|
|
302
|
+
seenIn: [LITERALS, REAL_PLAYER],
|
|
303
|
+
extract: ["value"],
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
id: "nivalisnights.player.scene-loaded",
|
|
307
|
+
game: "nivalisnights",
|
|
308
|
+
sources: ["player", "player-prev"],
|
|
309
|
+
severity: "info",
|
|
310
|
+
category: "success",
|
|
311
|
+
pattern: /^GameSceneManager - (?<from>.*?) -> (?<to>\S+) \| Total Unloading\/Loading Duration: (?<seconds>[\d.]+) seconds/,
|
|
312
|
+
explain: "A scene finished loading; the empty 'from' is the first load after start.",
|
|
313
|
+
seenIn: [REAL_PLAYER],
|
|
314
|
+
extract: ["from", "to", "seconds"],
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
id: "nivalisnights.player.save-loading",
|
|
318
|
+
game: "nivalisnights",
|
|
319
|
+
sources: ["player", "player-prev"],
|
|
320
|
+
severity: "info",
|
|
321
|
+
category: "load",
|
|
322
|
+
pattern: /^Loading save file (?<save>\S+) @Scene:(?<scene>\d+)/,
|
|
323
|
+
explain: "A save began loading; the scene number is its build index.",
|
|
324
|
+
seenIn: [LITERALS, REAL_PLAYER],
|
|
325
|
+
extract: ["save", "scene"],
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
id: "nivalisnights.player.save-loaded",
|
|
329
|
+
game: "nivalisnights",
|
|
330
|
+
sources: ["player", "player-prev"],
|
|
331
|
+
severity: "info",
|
|
332
|
+
category: "success",
|
|
333
|
+
pattern: /^Completed loading save (?<path>.+)$/,
|
|
334
|
+
explain: "A save loaded to the end without the loader quitting the game.",
|
|
335
|
+
seenIn: [LITERALS, REAL_PLAYER],
|
|
336
|
+
extract: ["path"],
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
id: "nivalisnights.player.save-written",
|
|
340
|
+
game: "nivalisnights",
|
|
341
|
+
sources: ["player", "player-prev"],
|
|
342
|
+
severity: "info",
|
|
343
|
+
category: "success",
|
|
344
|
+
pattern: /^Completed saving save (?<path>.+)$/,
|
|
345
|
+
explain: "A save was written and moved into place.",
|
|
346
|
+
seenIn: [LITERALS, REAL_PLAYER],
|
|
347
|
+
extract: ["path"],
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
id: "nivalisnights.player.unknown-save-packet",
|
|
351
|
+
game: "nivalisnights",
|
|
352
|
+
sources: ["player", "player-prev"],
|
|
353
|
+
severity: "error",
|
|
354
|
+
category: "resource",
|
|
355
|
+
pattern: /^No packet found for guid (?<guid>.+)$/,
|
|
356
|
+
explain: "The save holds a manager packet this game does not know, and the loader cannot skip it: everything after it in the save reads wrong. Either a mod that added its own save packet was removed, or the save is from a different game build.",
|
|
357
|
+
hint: "Reinstall the mod that wrote the packet, or restore the save from a backup taken before it. A mod should keep its state in a sidecar file, never a packet.",
|
|
358
|
+
seenIn: [LITERALS],
|
|
359
|
+
extract: ["guid"],
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
id: "nivalisnights.player.unknown-prefab",
|
|
363
|
+
game: "nivalisnights",
|
|
364
|
+
sources: ["player", "player-prev"],
|
|
365
|
+
severity: "warn",
|
|
366
|
+
category: "resource",
|
|
367
|
+
pattern: /^Cannot find prefab with id (?<id>\S+)/,
|
|
368
|
+
explain: "A saved world object names a prefab this build does not have; the loader skips that object. Usually residue of a removed mod's placed object.",
|
|
369
|
+
seenIn: [LITERALS],
|
|
370
|
+
extract: ["id"],
|
|
371
|
+
systemImpact: false,
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
id: "nivalisnights.player.same-scene-twice",
|
|
375
|
+
game: "nivalisnights",
|
|
376
|
+
sources: ["player", "player-prev"],
|
|
377
|
+
severity: "warn",
|
|
378
|
+
category: "load",
|
|
379
|
+
pattern: /^GameSceneManager - Loading the same scene twice!/,
|
|
380
|
+
explain: "A scene load was requested for the scene already loading; often a plugin calling travel or LoadArea during a transition.",
|
|
381
|
+
seenIn: [LITERALS],
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
id: "nivalisnights.player.level-loading-timeout",
|
|
385
|
+
game: "nivalisnights",
|
|
386
|
+
sources: ["player", "player-prev"],
|
|
387
|
+
severity: "error",
|
|
388
|
+
category: "load",
|
|
389
|
+
pattern: /^GameSceneManager LevelLoadingIsBlocked timeout!/,
|
|
390
|
+
explain: "A scene load waited too long on something blocking it; the game may hang at the transition.",
|
|
391
|
+
seenIn: [LITERALS],
|
|
392
|
+
},
|
|
393
|
+
{
|
|
394
|
+
id: "nivalisnights.player.nnue-download-failed",
|
|
395
|
+
game: "nivalisnights",
|
|
396
|
+
sources: ["player", "player-prev"],
|
|
397
|
+
severity: "warn",
|
|
398
|
+
category: "resource",
|
|
399
|
+
pattern: /^Failed to download NNUE file: /,
|
|
400
|
+
explain: "The chess engine's network file was missing from StreamingAssets and the game's download fallback failed; the chess minigame has no engine.",
|
|
401
|
+
hint: "Verify the game files in Steam to restore StreamingAssets/nn-0000000000a0.nnue.",
|
|
402
|
+
seenIn: [LITERALS],
|
|
403
|
+
},
|
|
404
|
+
{
|
|
405
|
+
id: "nivalisnights.player.dev-token-rejected",
|
|
406
|
+
game: "nivalisnights",
|
|
407
|
+
sources: ["player", "player-prev"],
|
|
408
|
+
severity: "info",
|
|
409
|
+
category: "load",
|
|
410
|
+
pattern: /^ValidatePayload DateTime (?<what>expired|failed)/,
|
|
411
|
+
explain: "settings.ini holds a developer token that did not validate. The token is RSA-signed by the studio and cannot be made locally; a plugin forces dev mode instead.",
|
|
412
|
+
seenIn: [LITERALS],
|
|
413
|
+
extract: ["what"],
|
|
414
|
+
},
|
|
415
|
+
{
|
|
416
|
+
id: "nivalisnights.player.vanilla-chair",
|
|
417
|
+
game: "nivalisnights",
|
|
418
|
+
sources: ["player", "player-prev"],
|
|
419
|
+
severity: "info",
|
|
420
|
+
category: "script",
|
|
421
|
+
pattern: /can't stand from chair anywhere!$/,
|
|
422
|
+
explain: "Known vanilla noise (logged at error level by the unmodded game): an NPC could not find a place to stand up. Not caused by mods.",
|
|
423
|
+
seenIn: [LITERALS, REAL_PLAYER],
|
|
424
|
+
systemImpact: false,
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
id: "nivalisnights.player.vanilla-pooled-element",
|
|
428
|
+
game: "nivalisnights",
|
|
429
|
+
sources: ["player", "player-prev"],
|
|
430
|
+
severity: "info",
|
|
431
|
+
category: "script",
|
|
432
|
+
pattern: /^Pooled element .+ should not be destroyed, but released back to the pool instead!/,
|
|
433
|
+
explain: "Known vanilla noise (logged at error level by the unmodded game): an object-pool misuse inside the game. Not caused by mods.",
|
|
434
|
+
seenIn: [LITERALS],
|
|
435
|
+
systemImpact: false,
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
id: "nivalisnights.player.vanilla-venue-order",
|
|
439
|
+
game: "nivalisnights",
|
|
440
|
+
sources: ["player", "player-prev"],
|
|
441
|
+
severity: "info",
|
|
442
|
+
category: "script",
|
|
443
|
+
pattern: /VenueOrderReference[.:]get_Order\b/,
|
|
444
|
+
explain: "Known vanilla noise: a NullReferenceException from the staff task queue (VenueOrderReference.get_Order, during LateUpdate) seen in an unmodded launch-week log. Not caused by mods unless a mod changes staff tasks.",
|
|
445
|
+
seenIn: ["ModWright research"],
|
|
446
|
+
systemImpact: false,
|
|
447
|
+
},
|
|
448
|
+
{
|
|
449
|
+
id: "nivalisnights.player.singleton-after-quit",
|
|
450
|
+
game: "nivalisnights",
|
|
451
|
+
sources: ["player", "player-prev"],
|
|
452
|
+
severity: "info",
|
|
453
|
+
category: "load",
|
|
454
|
+
pattern: /^\[Singleton\] Instance '(?<type>[^']+)' already destroyed on application quit/,
|
|
455
|
+
explain: "Normal at quit: a manager was asked for after shutdown began.",
|
|
456
|
+
seenIn: [REAL_PLAYER],
|
|
457
|
+
extract: ["type"],
|
|
458
|
+
systemImpact: false,
|
|
459
|
+
},
|
|
460
|
+
{
|
|
461
|
+
id: "nivalisnights.player.dotween-safe-mode",
|
|
462
|
+
game: "nivalisnights",
|
|
463
|
+
sources: ["player", "player-prev"],
|
|
464
|
+
severity: "info",
|
|
465
|
+
category: "script",
|
|
466
|
+
pattern: /DOTween's safe mode captured (?<count>\d+) errors/,
|
|
467
|
+
explain: "DOTween's end-of-session summary of tween errors it swallowed; the unmodded game reports these too.",
|
|
468
|
+
seenIn: ["ModWright research"],
|
|
469
|
+
extract: ["count"],
|
|
470
|
+
systemImpact: false,
|
|
471
|
+
},
|
|
472
|
+
];
|
|
473
|
+
export const SIGNATURES = [...BEPINEX, ...PLAYER];
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
import { homePath, pathExists, readTextIfExists } from "../../core/fsutil.js";
|
|
3
|
+
import { findInSteam } from "../../core/steam.js";
|
|
4
|
+
import { dedupeByRoot, logs, roots } from "../../core/surfaceutil.js";
|
|
5
|
+
import { GAME_EXE, nivalisCompat } from "./compat.js";
|
|
6
|
+
import { nivalisIndex } from "./index/index.js";
|
|
7
|
+
import { SIGNATURES } from "./logs.js";
|
|
8
|
+
export const nivalisnights = {
|
|
9
|
+
id: "nivalisnights",
|
|
10
|
+
name: "Nivalis Nights",
|
|
11
|
+
aliases: ["nivalis", "nivalis nights", "nn"],
|
|
12
|
+
summary: "Unity IL2CPP with BepInEx 6 bleeding-edge (Unity.IL2CPP, #788): net6.0 plugin assemblies under " +
|
|
13
|
+
"BepInEx/plugins, HarmonyX patches against generated interop; MelonLoader builds also exist. No official mod support.",
|
|
14
|
+
async detect() {
|
|
15
|
+
const installs = [];
|
|
16
|
+
const override = process.env.MODWRIGHT_NIVALISNIGHTS_ROOT;
|
|
17
|
+
if (override && (await pathExists(override)))
|
|
18
|
+
installs.push({ gameId: "nivalisnights", root: override, source: "env" });
|
|
19
|
+
for (const root of await findInSteam(["Nivalis Nights"])) {
|
|
20
|
+
if (await isInstall(root))
|
|
21
|
+
installs.push({ gameId: "nivalisnights", root, source: "steam" });
|
|
22
|
+
}
|
|
23
|
+
return dedupeByRoot(installs);
|
|
24
|
+
},
|
|
25
|
+
modRoots(install) {
|
|
26
|
+
const bepinex = path.join(install.root, "BepInEx");
|
|
27
|
+
return roots([
|
|
28
|
+
{
|
|
29
|
+
id: "plugins",
|
|
30
|
+
label: "BepInEx plugins",
|
|
31
|
+
path: path.join(bepinex, "plugins"),
|
|
32
|
+
layout: "directory",
|
|
33
|
+
conflictScope: "isolated",
|
|
34
|
+
notes: "Each mod in its own subdirectory; loose .dlls directly in plugins/ load too, and most Nivalis " +
|
|
35
|
+
"Nights mods install that way. Collisions are on plugin GUID, not path: BepInEx 6 drops a " +
|
|
36
|
+
"duplicate or near-duplicate GUID with a 'Skipping [...]' line. Plugins must be built for the " +
|
|
37
|
+
"Unity.IL2CPP runtime (BasePlugin, net6.0); a BepInEx 5 or Mono plugin does not load.",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
id: "patchers",
|
|
41
|
+
label: "BepInEx preloader patchers",
|
|
42
|
+
path: path.join(bepinex, "patchers"),
|
|
43
|
+
layout: "directory",
|
|
44
|
+
conflictScope: "isolated",
|
|
45
|
+
notes: "Preloader patchers; none of the community mods seen so far ship one.",
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: "config",
|
|
49
|
+
label: "BepInEx config",
|
|
50
|
+
path: path.join(bepinex, "config"),
|
|
51
|
+
layout: "flat",
|
|
52
|
+
conflictScope: "merged",
|
|
53
|
+
notes: "One <GUID>.cfg per plugin plus BepInEx.cfg, written by BepInEx at runtime.",
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
id: "core",
|
|
57
|
+
label: "BepInEx core",
|
|
58
|
+
path: path.join(bepinex, "core"),
|
|
59
|
+
layout: "flat",
|
|
60
|
+
conflictScope: "merged",
|
|
61
|
+
notes: "BepInEx, HarmonyX and Il2CppInterop assemblies. Listed so a mod wrongly shipping into it is visible; never a deploy target.",
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: "interop",
|
|
65
|
+
label: "BepInEx generated interop",
|
|
66
|
+
path: path.join(bepinex, "interop"),
|
|
67
|
+
layout: "flat",
|
|
68
|
+
conflictScope: "merged",
|
|
69
|
+
notes: "Generated from GameAssembly.dll on the first launch and after each game update (about 25 s). " +
|
|
70
|
+
"Plugins compile against these; never a deploy target. Deleting the folder with BepInEx/cache " +
|
|
71
|
+
"forces a rebuild.",
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
id: "loader",
|
|
75
|
+
label: "Loader files beside the executable",
|
|
76
|
+
path: install.root,
|
|
77
|
+
layout: "flat",
|
|
78
|
+
conflictScope: "merged",
|
|
79
|
+
notes: "BepInEx's winhttp.dll, doorstop_config.ini, .doorstop_version and dotnet/ (its own .NET 6 " +
|
|
80
|
+
"runtime); MelonLoader's version.dll. Where 'which loader is installed' is answered.",
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
id: "melon-mods",
|
|
84
|
+
label: "MelonLoader mods",
|
|
85
|
+
path: path.join(install.root, "Mods"),
|
|
86
|
+
layout: "file",
|
|
87
|
+
extensions: [".dll"],
|
|
88
|
+
conflictScope: "isolated",
|
|
89
|
+
notes: "MelonLoader's mods folder, for mods that ship a MelonLoader build. Install one loader, not both.",
|
|
90
|
+
},
|
|
91
|
+
]);
|
|
92
|
+
},
|
|
93
|
+
logs(install) {
|
|
94
|
+
const userDir = (file) => homePath("AppData", "LocalLow", "ION LANDS", "Nivalis Nights", file);
|
|
95
|
+
return logs([
|
|
96
|
+
{
|
|
97
|
+
id: "bepinex",
|
|
98
|
+
label: "BepInEx LogOutput.log",
|
|
99
|
+
candidates: [path.join(install.root, "BepInEx", "LogOutput.log")],
|
|
100
|
+
rootId: "plugins",
|
|
101
|
+
notes: "One file per run, '[Level : Source] message' lines with no timestamp. Holds the chainloader's " +
|
|
102
|
+
"roll-call and plugin errors, plus interop generation on a first launch or after a game update. " +
|
|
103
|
+
"A plugin's runtime exceptions land in Player.log instead.",
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
id: "player",
|
|
107
|
+
label: "Unity Player.log",
|
|
108
|
+
candidates: [userDir("Player.log")],
|
|
109
|
+
notes: "The game's own log: scene loads, saves, the game's errors and plugin exceptions. Every message " +
|
|
110
|
+
"line is followed by its managed stack. Several error lines are vanilla noise and are tagged so.",
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
id: "player-prev",
|
|
114
|
+
label: "Unity Player-prev.log (the previous run)",
|
|
115
|
+
candidates: [userDir("Player-prev.log")],
|
|
116
|
+
notes: "Unity rotates Player.log on launch; after a crash the evidence is here once the game is restarted.",
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
id: "melonloader",
|
|
120
|
+
label: "MelonLoader Latest.log",
|
|
121
|
+
candidates: [path.join(install.root, "MelonLoader", "Latest.log")],
|
|
122
|
+
rootId: "melon-mods",
|
|
123
|
+
notes: "Only with MelonLoader installed. Its line format has not been seen on this machine, so no signatures read it yet.",
|
|
124
|
+
},
|
|
125
|
+
]);
|
|
126
|
+
},
|
|
127
|
+
async explainMissing(install) {
|
|
128
|
+
const reasons = {};
|
|
129
|
+
if (!(await pathExists(path.join(install.root, "winhttp.dll")))) {
|
|
130
|
+
reasons.bepinex = "winhttp.dll was not found beside the executable: BepInEx is not installed here, so no LogOutput.log can exist. The community's build is BepInEx 6 bleeding-edge #788, Unity.IL2CPP.";
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
const cfg = await readTextIfExists(path.join(install.root, "BepInEx", "config", "BepInEx.cfg"));
|
|
134
|
+
if (cfg === undefined)
|
|
135
|
+
reasons.bepinex = "BepInEx/config/BepInEx.cfg does not exist yet: BepInEx creates it on its first launch, so the loader has not run since it was installed.";
|
|
136
|
+
else if (diskLoggingDisabled(cfg))
|
|
137
|
+
reasons.bepinex = "[Logging.Disk] Enabled = false in BepInEx/config/BepInEx.cfg: the loader runs but writes no LogOutput.log. Set it to true.";
|
|
138
|
+
}
|
|
139
|
+
const userDir = homePath("AppData", "LocalLow", "ION LANDS", "Nivalis Nights");
|
|
140
|
+
if (!(await pathExists(userDir))) {
|
|
141
|
+
reasons.player = `${userDir} does not exist: the game has not been run under this Windows account.`;
|
|
142
|
+
reasons["player-prev"] = reasons.player;
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
reasons["player-prev"] = "Unity writes Player-prev.log only once the game has been launched a second time.";
|
|
146
|
+
}
|
|
147
|
+
if (!(await pathExists(path.join(install.root, "MelonLoader")))) {
|
|
148
|
+
reasons.melonloader = "MelonLoader is not installed (it is optional here; BepInEx is the community default).";
|
|
149
|
+
}
|
|
150
|
+
return reasons;
|
|
151
|
+
},
|
|
152
|
+
logSignatures: SIGNATURES,
|
|
153
|
+
compat: nivalisCompat,
|
|
154
|
+
index: nivalisIndex,
|
|
155
|
+
toolNeeds: [
|
|
156
|
+
{ feature: "index", tools: ["cpp2il", "unitypy-python"], note: "build_index rebuilds dummy assemblies with Cpp2IL and decodes Resources/ with a UnityPy Python." },
|
|
157
|
+
{ feature: "build", tools: ["dotnet"], note: "dotnet build compiles net6.0 BepInEx IL2CPP plugins." },
|
|
158
|
+
],
|
|
159
|
+
processNames: [GAME_EXE],
|
|
160
|
+
guidance: "A Unity IL2CPP game: mods are BepInEx 6 bleeding-edge plugins (the Unity.IL2CPP build; #788 is " +
|
|
161
|
+
"what the community and ModWright tested), net6.0 assemblies subclassing BasePlugin and patching " +
|
|
162
|
+
"with HarmonyX against BepInEx/interop. BepInEx 5 and Mono-style plugins do not load. Install " +
|
|
163
|
+
"order matters: install BepInEx, launch once to the main menu (interop generation, about 25 s, " +
|
|
164
|
+
"needs network for the Unity base libraries), close, then add plugins. Some mods ship a " +
|
|
165
|
+
"MelonLoader build instead; install one loader, not both. The game patches often, and each " +
|
|
166
|
+
"update regenerates interop and can break plugins, so check build ids before blaming a mod. " +
|
|
167
|
+
"Saves are Easy Save 2 binary files in %USERPROFILE%/AppData/LocalLow/ION LANDS/Nivalis Nights; " +
|
|
168
|
+
"the loader cannot skip an unknown packet, so a mod must keep its own state in a sidecar file " +
|
|
169
|
+
"beside the save, never as a new packet. Steam Cloud syncs only .sav and .png, so sidecars stay " +
|
|
170
|
+
"local. A plugin can force the studio's developer mode (DevMode.IsDevMode) and open its " +
|
|
171
|
+
"Developer Options window; Player.log's 'isDevMode:False' line is printed before that override " +
|
|
172
|
+
"and is not evidence it failed.",
|
|
173
|
+
};
|
|
174
|
+
export async function isInstall(root) {
|
|
175
|
+
return (await pathExists(path.join(root, GAME_EXE))) || (await pathExists(path.join(root, "Nivalis Nights_Data")));
|
|
176
|
+
}
|
|
177
|
+
export function diskLoggingDisabled(cfgText) {
|
|
178
|
+
let section = "";
|
|
179
|
+
for (const raw of cfgText.split(/\r?\n/)) {
|
|
180
|
+
const line = raw.trim();
|
|
181
|
+
if (!line || line.startsWith("#"))
|
|
182
|
+
continue;
|
|
183
|
+
const sec = /^\[(.+)\]$/.exec(line);
|
|
184
|
+
if (sec) {
|
|
185
|
+
section = sec[1].trim().toLowerCase();
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
if (section !== "logging.disk")
|
|
189
|
+
continue;
|
|
190
|
+
const m = /^enabled\s*=\s*(\w+)/i.exec(line);
|
|
191
|
+
if (m)
|
|
192
|
+
return m[1].toLowerCase() === "false";
|
|
193
|
+
}
|
|
194
|
+
return false;
|
|
195
|
+
}
|