Added Weapon Customization Mod

This commit is contained in:
Rage 2025-01-06 19:33:42 -05:00
parent 502af97377
commit 705b06bd03
6 changed files with 163 additions and 1 deletions

View File

@ -0,0 +1,28 @@
[General]
gameName=spt
modid=0
version=d2025.1.6.0
newestVersion=
category="2,"
nexusFileStatus=1
installationFile=Tyfon-WeaponCustomizer-1.0.0.zip
repository=Nexus
ignoredVersion=
comments=
notes=
nexusDescription=
url=
hasCustomURL=false
lastNexusQuery=
lastNexusUpdate=
nexusLastModified=2025-01-07T00:12:11Z
nexusCategory=0
converted=false
validated=false
color=@Variant(\0\0\0\x43\0\xff\xff\0\0\0\0\0\0\0\0)
tracked=0
[installedFiles]
1\modid=0
1\fileid=0
size=1

View File

@ -0,0 +1,33 @@
{
"name": "weapon-customizer",
"version": "1.0.0",
"main": "src/mod.js",
"license": "MIT",
"author": "Tyfon",
"sptVersion": "~3.10",
"loadBefore": [],
"loadAfter": [],
"incompatibilities": [],
"contributors": [],
"isBundleMod": false,
"scripts": {
"setup": "npm i",
"build": "node ./build.mjs",
"buildinfo": "node ./build.mjs --verbose"
},
"devDependencies": {
"@types/node": "20.11",
"@typescript-eslint/eslint-plugin": "7.2",
"@typescript-eslint/parser": "7.2",
"archiver": "^6.0",
"eslint": "8.57",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"fs-extra": "11.2",
"ignore": "^5.2",
"os": "^0.1",
"tsyringe": "4.8.0",
"typescript": "5.4",
"winston": "3.12"
}
}

View File

@ -0,0 +1,100 @@
import type { DependencyContainer } from "tsyringe";
import type { IPreSptLoadMod } from "@spt/models/external/IPreSptLoadMod";
import { LogTextColor } from "@spt/models/spt/logging/LogTextColor";
import type { ILogger } from "@spt/models/spt/utils/ILogger";
import type { StaticRouterModService } from "@spt/services/mod/staticRouter/StaticRouterModService";
import { VFS } from "@spt/utils/VFS";
import fs from "node:fs";
import path from "node:path";
type Vector3 = {
x: number;
y: number;
z: number;
};
type CustomPosition = {
original: Vector3;
modified: Vector3;
};
type CustomizePayload = {
weaponId: string;
slots: Record<string, CustomPosition>;
};
type Customizations = Record<string, Record<string, CustomPosition>>;
class WeaponCustomizer implements IPreSptLoadMod {
private logger: ILogger;
private vfs: VFS;
private customizations: Customizations = null;
private filepath: string;
public preSptLoad(container: DependencyContainer): void {
this.logger = container.resolve<ILogger>("PrimaryLogger");
this.vfs = container.resolve<VFS>("VFS");
const staticRouterModService = container.resolve<StaticRouterModService>("StaticRouterModService");
this.filepath = path.resolve(__dirname, "../customizations.json");
this.load();
staticRouterModService.registerStaticRouter(
"WeaponCustomizerRoutes",
[
{
url: "/weaponcustomizer/save",
action: async (url, info: CustomizePayload, sessionId, output) => this.saveCustomization(info)
},
{
url: "/weaponcustomizer/load",
action: async (url, info, sessionId, output) => JSON.stringify(this.customizations)
}
],
"custom-static-weapon-customizer"
);
}
private async saveCustomization(payload: CustomizePayload): Promise<string> {
//this.logger.info(`WeaponCustomizer: Saving customization for weapon ${payload.weaponId}`);
if (Object.keys(payload.slots).length === 0) {
delete this.customizations[payload.weaponId];
} else {
this.customizations[payload.weaponId] = payload.slots;
}
await this.save();
return JSON.stringify({ success: true });
}
private load() {
try {
if (this.vfs.exists(this.filepath)) {
this.customizations = JSON.parse(this.vfs.readFile(this.filepath));
} else {
this.customizations = {};
// Create the file with fs - vfs.writeFile pukes on windows paths if it needs to create the file
fs.writeFileSync(this.filepath, JSON.stringify(this.customizations));
}
const count = Object.keys(this.customizations).length;
if (count > 0) {
this.logger.logWithColor(`WeaponCustomizer: ${count} weapon customizations loaded.`, LogTextColor.CYAN);
}
} catch (error) {
this.logger.error("WeaponCustomizer: Failed to load weapon customization! " + error);
this.customizations = {};
}
}
private async save() {
try {
await this.vfs.writeFileAsync(this.filepath, JSON.stringify(this.customizations, null, 2));
} catch (error) {
this.logger.error("WeaponCustomizer: Failed to save weapon customization! " + error);
}
}
}
export const mod = new WeaponCustomizer();

View File

@ -22,6 +22,7 @@
+SAIN - EpicRangeTimes Preset +SAIN - EpicRangeTimes Preset
+SAIN +SAIN
-AI & Combat Tweaks_separator -AI & Combat Tweaks_separator
+Weapon Customizer
+Little Drummer Boy +Little Drummer Boy
+SVD +SVD
+M249 +M249

View File

@ -1,4 +1,3 @@
# This file was automatically generated by Mod Organizer.
+Unsorted_separator +Unsorted_separator
-Visceral Combat -Visceral Combat
-SWAG + DONUTS -SWAG + DONUTS
@ -22,6 +21,7 @@
+SAIN - EpicRangeTimes Preset +SAIN - EpicRangeTimes Preset
+SAIN +SAIN
+AI & Combat Tweaks_separator +AI & Combat Tweaks_separator
-Weapon Customizer
+Little Drummer Boy +Little Drummer Boy
+SVD +SVD
+M249 +M249