Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
MagicJinn committed May 13, 2024
0 parents commit e3f7fc4
Show file tree
Hide file tree
Showing 7 changed files with 883 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Sunless Sea Vortex Extension
Vortex Extension for the game Sunless Sea. Supports both BepInEx and JSON.
Binary file added game-sunlesssea/gameart.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added game-sunlesssea/gameicon.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
199 changes: 199 additions & 0 deletions game-sunlesssea/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
const GAME_ID = 'sunlesssea';
const STEAMAPP_ID = '304650';
const EPICAPP_ID = '2420b50453144c07b3b847fff941275d'
const GOGAPP_ID = '1421064427';

const LOCALLOW_PATH = "LocalLow/Failbetter Games/Sunless Sea/"

const JSON_MOD_PATH = (() => {
let cached;
return () => {
if (cached === undefined) {
cached = path.resolve(util.getVortexPath('appData'), '..', LOCALLOW_PATH);
}
return cached;
};
})();

const BEPINEX_MOD_EXT = ".dll";

var installPath
var modType

var namelessModInstalls = 0

var cont // Save context for later use

const path = require('path');
const {
fs,
log,
util
} = require('vortex-api');

function main(context) {
cont = context

context.registerGame({
id: GAME_ID,
name: 'Sunless Sea',
mergeMods: true,
queryPath: findGame,
supportedTools: [],
queryModPath: () => '',
logo: 'gameart.jpg',
executable: () => 'Sunless Sea.exe',
requiredFiles: ['Sunless Sea.exe'],
setup: prepareForModding,
environment: {
SteamAPPId: STEAMAPP_ID,
},
details: {
steamAppId: STEAMAPP_ID,
gogAppId: GOGAPP_ID,
epicAppId: EPICAPP_ID
},
});
// Create a seperate mod type for installing JSON mods to %localappdata%low
context.registerModType("JSON Addon Mod", 2, (gameId) => gameId === GAME_ID, JSON_MOD_PATH, () => Promise.resolve(false));

context.registerInstaller("Code Injection Mods", 1, isBepInExMod, installContent)
context.registerInstaller("JSON Addon Mods", 2, isJSONAddon, installContent)

return true
}

async function prepareForModding(discovery) { // Check whether these directories are writable so Vortex doesn't throw a hissy fit
const ensureDir = async (dirPath) => {
const createPath = path.isAbsolute(dirPath) ? dirPath : path.join(discovery.path, dirPath);
return fs.ensureDirWritableAsync(createPath);
}
return Promise.all(["BepInEx/plugins", "BepInEx/patchers", JSON_MOD_PATH()].map(dirPath => ensureDir(dirPath)));
}

function isBepInExMod(files) {
// Check if any of the files in the mod archive have a BepInEx mod
let hasBepInExMod = files.some(file => {
const ext = path.extname(file).toLowerCase();
return ext === BEPINEX_MOD_EXT;
});
if (hasBepInExMod) {
// Initial setup for loading BepInEx mods
modType = "bep"
installPath = checkBepInExDirectoryStructure(files)
}

let supported = hasBepInExMod
return Promise.resolve({
supported,
requiredFiles: [],
});
}

function isJSONAddon(files) {
// Initial setup for loading JSON mods
modType = "json"
installPath = checkJsonDirectoryStructure(files)
let supported = true
return Promise.resolve({
supported,
requiredFiles: [],
});
}



function checkBepInExDirectoryStructure(files) {
const hasBepInExFolder = files.some(file => file.toLowerCase() == 'bepinex\\');
if (hasBepInExFolder) {
return ""; // If the mod contains a BepInEx folder, install it to the base directory
}

const hasPluginsFolder = files.some(file => file.toLowerCase() == 'plugins\\');
if (hasPluginsFolder) {
// If the mod contains only a 'plugins' folder, install it to the BepInEx directory
return "/BepInEx";
}

// If none of the above conditions are met, install it to the 'plugins' directory
return "/BepInEx/plugins";
}

function installContent(files) {
const filtered = files.filter(file =>
(!file.endsWith(path.sep)));

let instructions = filtered.map(file => {
return {
type: 'copy',
source: file,
destination: path.join(installPath, file),
};

});

if (modType == "json") { // Change the install path if it's a json mod
const modTypeInstr = {
type: 'setmodtype',
value: 'JSON Addon Mod',
}
instructions.push(modTypeInstr)
}

return Promise.resolve({
instructions
});
}


function checkJsonDirectoryStructure(files) {
const baseFolders = ['addons\\', 'images\\'];
const subFolders = ['entities\\', 'encyclopaedia\\', 'geography\\']

// Check if it's a base mod
const isBaseMod = baseFolders.some(folder => files.includes(folder));

if (isBaseMod) {
return "";
}

// Checks whether the first entry in the files list is a folder that should be inside another folder
const isAModFolder = !subFolders.includes(files[0])
// If not, just install it as is to addon

if (isAModFolder) {
return '/addon';
}

namelessModInstalls++
cont.api.sendNotification({
type: "warning",
message: "Incorrect mod format, contact the mod author.",
actions: [{
title: "More",
action: () => {
cont.api.showDialog(
"warning",
"Incorrect mod format, contact the mod author.", {
text: "The Sunless Sea Vortex extension was coded in a way to still allow this mod to run, but it is undesirable and might break. Contact the mod author to fix the formatting error in the latest version. Mod shall be installed as Nameless Mod " + namelessModInstalls,
message: "Accepted formats for addons:\nARCHIVE > Mod Folder > entities/geography etc > JSON\nARCHIVE > addons > Mod Folder > entities/geography etc > JSON\nYour format:\nARCHIVE > entities/geography etc > JSON\nor other",
},
[{
label: "Close"
}]
)
}
}, ]
})

return path.join('/addon', "Nameless Mod " + namelessModInstalls);
}

function findGame() {
return util.GameStoreHelper.findByAppId([STEAMAPP_ID, EPICAPP_ID, GOGAPP_ID])
.then(game => game.gamePath);
}

module.exports = {
default: main,
};
6 changes: 6 additions & 0 deletions game-sunlesssea/info.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "Game: Sunless Sea",
"author": "MagicJinn",
"version": "1.0.0",
"description": "Support for Sunless Sea"
}

0 comments on commit e3f7fc4

Please sign in to comment.