Added Weapon Customization Mod
This commit is contained in:
parent
502af97377
commit
705b06bd03
Binary file not shown.
|
@ -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
|
|
@ -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"
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue