init
This commit is contained in:
BIN
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
@@ -0,0 +1,203 @@
|
||||
const path = require('path');
|
||||
const { fs, log, util } = require('vortex-api');
|
||||
|
||||
const GAME_ID = 'retrorewindvideostoresimulator';
|
||||
const STEAM_APP_ID = '3552140';
|
||||
|
||||
// all relative to gamePath == <steamapps>/common/RetroRewind
|
||||
const REL_PAKS = path.join('RetroRewind', 'Content', 'Paks', '~mods');
|
||||
const REL_LOGICMODS = path.join('RetroRewind', 'Content', 'Paks', 'LogicMods');
|
||||
const REL_UE4SS = path.join('RetroRewind', 'Binaries', 'Win64', 'ue4ss', 'Mods');
|
||||
|
||||
const MODTYPE_LOGICMODS = 'retrorewind-logicmods';
|
||||
const MODTYPE_UE4SS = 'retrorewind-ue4ss';
|
||||
|
||||
const PAK_EXTS = ['.pak', '.ucas', '.utoc', '.sig'];
|
||||
|
||||
// archive paths come from Vortex with the host separator, normalise to '/'
|
||||
function norm(filePath) {
|
||||
return filePath.split(/[\\/]/).join('/');
|
||||
}
|
||||
|
||||
function isDirectory(filePath) {
|
||||
return filePath.endsWith(path.sep) || filePath.endsWith('/');
|
||||
}
|
||||
|
||||
let _api;
|
||||
|
||||
// under a wine/proton-hosted Vortex (steamtinkerlaunch) there is no Steam client
|
||||
// in the prefix, so the store lookup throws ENOENT on libraryfolders.vdf.
|
||||
// Swallow it - Vortex then keeps the manually browsed/stored discovery path.
|
||||
function findGame() {
|
||||
return util.GameStoreHelper.findByAppId([STEAM_APP_ID])
|
||||
.then(game => game.gamePath)
|
||||
.catch(err => {
|
||||
log('info', 'Retro Rewind: steam store lookup unavailable, using manual discovery',
|
||||
{ error: err.message });
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
// the game object handed to modType.getPath has no usable path while the game is
|
||||
// still being discovered/managed, so read the discovery from state instead
|
||||
function discoveryPath(game) {
|
||||
if (util.getSafe(game, ['path'], undefined) !== undefined) {
|
||||
return game.path;
|
||||
}
|
||||
return util.getSafe(_api.store.getState(),
|
||||
['settings', 'gameMode', 'discovered', GAME_ID, 'path'], undefined);
|
||||
}
|
||||
|
||||
function modTypePath(relPath) {
|
||||
return (game) => {
|
||||
const gamePath = discoveryPath(game);
|
||||
if (gamePath === undefined) {
|
||||
log('debug', 'Retro Rewind not discovered yet, modtype path unresolved', relPath);
|
||||
return undefined;
|
||||
}
|
||||
return path.join(gamePath, relPath);
|
||||
};
|
||||
}
|
||||
|
||||
function prepareForModding(discovery) {
|
||||
return Promise.all([REL_PAKS, REL_LOGICMODS, REL_UE4SS]
|
||||
.map(rel => fs.ensureDirWritableAsync(path.join(discovery.path, rel))));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- UE4SS mods
|
||||
// layout: <ModName>/Scripts/main.lua or <ModName>/dlls/main.dll
|
||||
const UE4SS_MARKER = /(^|\/)(scripts\/main\.lua|dlls\/main\.dll)$/i;
|
||||
|
||||
function testUe4ssMod(files, gameId) {
|
||||
const supported = (gameId === GAME_ID)
|
||||
&& files.some(file => UE4SS_MARKER.test(norm(file)));
|
||||
return Promise.resolve({ supported, requiredFiles: [] });
|
||||
}
|
||||
|
||||
function installUe4ssMod(files, destinationPath) {
|
||||
const marker = files.find(file => UE4SS_MARKER.test(norm(file)));
|
||||
// strip "Scripts/main.lua" (2 segments) to get the mod root inside the archive
|
||||
const markerSegments = norm(marker).split('/');
|
||||
const rootSegments = markerSegments.slice(0, markerSegments.length - 2);
|
||||
const rootPath = rootSegments.join('/');
|
||||
|
||||
// mod name: the folder holding Scripts/, else the staging folder name
|
||||
const modName = rootSegments.length > 0
|
||||
? rootSegments[rootSegments.length - 1]
|
||||
: path.basename(destinationPath).replace(/\.installing$/, '');
|
||||
|
||||
const filtered = files.filter(file => !isDirectory(file)
|
||||
&& (rootPath === '' || norm(file).startsWith(rootPath + '/')));
|
||||
|
||||
const instructions = filtered.map(file => ({
|
||||
type: 'copy',
|
||||
source: file,
|
||||
destination: path.join(modName,
|
||||
rootPath === '' ? norm(file) : norm(file).substr(rootPath.length + 1)),
|
||||
}));
|
||||
|
||||
// UE4SS 3.x activates a mod folder that contains enabled.txt - no mods.txt edit,
|
||||
// and the marker disappears again when Vortex purges the mod
|
||||
instructions.push({
|
||||
type: 'generatefile',
|
||||
data: Buffer.from(''),
|
||||
destination: path.join(modName, 'enabled.txt'),
|
||||
});
|
||||
|
||||
instructions.push({ type: 'setmodtype', value: MODTYPE_UE4SS });
|
||||
|
||||
log('info', 'installing Retro Rewind UE4SS mod', { modName, files: filtered.length });
|
||||
return Promise.resolve({ instructions });
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------ blueprint mods
|
||||
// blueprint (LogicMods) paks ship inside a folder called LogicMods
|
||||
const LOGICMODS_MARKER = /(^|\/)logicmods\//i;
|
||||
|
||||
function testLogicMod(files, gameId) {
|
||||
const supported = (gameId === GAME_ID)
|
||||
&& files.some(file => LOGICMODS_MARKER.test(norm(file))
|
||||
&& PAK_EXTS.includes(path.extname(file).toLowerCase()));
|
||||
return Promise.resolve({ supported, requiredFiles: [] });
|
||||
}
|
||||
|
||||
function installLogicMod(files) {
|
||||
const instructions = files
|
||||
.filter(file => !isDirectory(file)
|
||||
&& PAK_EXTS.includes(path.extname(file).toLowerCase()))
|
||||
.map(file => ({
|
||||
type: 'copy',
|
||||
source: file,
|
||||
destination: path.basename(file),
|
||||
}));
|
||||
|
||||
instructions.push({ type: 'setmodtype', value: MODTYPE_LOGICMODS });
|
||||
return Promise.resolve({ instructions });
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------ pak mods
|
||||
function testPakMod(files, gameId) {
|
||||
const supported = (gameId === GAME_ID)
|
||||
&& files.some(file => path.extname(file).toLowerCase() === '.pak');
|
||||
return Promise.resolve({ supported, requiredFiles: [] });
|
||||
}
|
||||
|
||||
// flatten into ~mods - archives commonly wrap the pak in one or more folders
|
||||
function installPakMod(files) {
|
||||
const instructions = files
|
||||
.filter(file => !isDirectory(file)
|
||||
&& PAK_EXTS.includes(path.extname(file).toLowerCase()))
|
||||
.map(file => ({
|
||||
type: 'copy',
|
||||
source: file,
|
||||
destination: path.basename(file),
|
||||
}));
|
||||
|
||||
return Promise.resolve({ instructions });
|
||||
}
|
||||
|
||||
function main(context) {
|
||||
_api = context.api;
|
||||
|
||||
context.registerGame({
|
||||
id: GAME_ID,
|
||||
name: 'Retro Rewind - Video Store Simulator',
|
||||
mergeMods: true,
|
||||
queryPath: findGame,
|
||||
queryModPath: () => REL_PAKS,
|
||||
logo: 'gameart.jpg',
|
||||
executable: () => 'RetroRewind.exe',
|
||||
requiredFiles: ['RetroRewind.exe'],
|
||||
setup: prepareForModding,
|
||||
supportedTools: [],
|
||||
environment: {
|
||||
SteamAPPId: STEAM_APP_ID,
|
||||
},
|
||||
details: {
|
||||
steamAppId: parseInt(STEAM_APP_ID, 10),
|
||||
},
|
||||
});
|
||||
|
||||
context.registerModType(MODTYPE_UE4SS, 25,
|
||||
gameId => gameId === GAME_ID,
|
||||
modTypePath(REL_UE4SS),
|
||||
() => Promise.resolve(false),
|
||||
{ name: 'UE4SS Mod' });
|
||||
|
||||
context.registerModType(MODTYPE_LOGICMODS, 25,
|
||||
gameId => gameId === GAME_ID,
|
||||
modTypePath(REL_LOGICMODS),
|
||||
() => Promise.resolve(false),
|
||||
{ name: 'Blueprint Mod (LogicMods)' });
|
||||
|
||||
// lower number == higher priority, so UE4SS wins over the generic pak installer
|
||||
context.registerInstaller('retrorewind-ue4ss', 25, testUe4ssMod, installUe4ssMod);
|
||||
context.registerInstaller('retrorewind-logicmods', 26, testLogicMod, installLogicMod);
|
||||
context.registerInstaller('retrorewind-pak', 27, testPakMod, installPakMod);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
default: main,
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "game-retro-rewind",
|
||||
"author": "Interstellarcodes",
|
||||
"version": "1.1.2",
|
||||
"description": "Vortex support for Retro Rewind - Video Store Simulator (pak, LogicMods and UE4SS mods)",
|
||||
"url": "https://www.nexusmods.com/retrorewindvideostoresimulator/mods/66"
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "game-retro-rewind",
|
||||
"version": "1.1.2",
|
||||
"description": "Vortex support for Retro Rewind - Video Store Simulator",
|
||||
"main": "index.js",
|
||||
"author": "Interstellarcodes",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"vortex-api": "^1.0.0"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user