rename file

This commit is contained in:
2024-06-09 14:50:21 +08:00
parent 138a16c289
commit 0e22d8dbce
376 changed files with 3 additions and 3 deletions
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 DrakiaXYZ
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -0,0 +1,4 @@
{
"nextUpdate": 1717917796,
"maxIncreaseMult": 10
}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,26 @@
{
"name": "LiveFleaPrices",
"version": "1.1.1",
"main": "src/mod.js",
"license": "MIT",
"author": "DrakiaXYZ",
"akiVersion": "~3.8",
"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",
"fs-extra": "11.2",
"ignore": "^5.2",
"os": "^0.1",
"tsyringe": "4.8.0",
"typescript": "5.4",
"winston": "3.12"
}
}
@@ -0,0 +1,110 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs = __importStar(require("node:fs"));
const path = __importStar(require("node:path"));
class Mod {
static container;
static updateTimer;
static config;
static configPath = path.resolve(__dirname, "../config/config.json");
static pricesPath = path.resolve(__dirname, "../config/prices.json");
static originalPrices;
async postDBLoadAsync(container) {
Mod.container = container;
Mod.config = JSON.parse(fs.readFileSync(Mod.configPath, "utf-8"));
// Store a clone of the original prices table, so we can make sure things don't go too crazy
const databaseServer = Mod.container.resolve("DatabaseServer");
const priceTable = databaseServer.getTables().templates.prices;
Mod.originalPrices = structuredClone(priceTable);
// Update prices on startup
const currentTime = Math.floor(Date.now() / 1000);
let fetchPrices = false;
if (currentTime > Mod.config.nextUpdate) {
fetchPrices = true;
}
if (!await Mod.updatePrices(fetchPrices)) {
return;
}
// Setup a refresh interval to update once every hour
Mod.updateTimer = setInterval(Mod.updatePrices, (60 * 60 * 1000));
}
static async updatePrices(fetchPrices = true) {
const logger = Mod.container.resolve("WinstonLogger");
const databaseServer = Mod.container.resolve("DatabaseServer");
const ragfairPriceService = Mod.container.resolve("RagfairPriceService");
const priceTable = databaseServer.getTables().templates.prices;
const itemTable = databaseServer.getTables().templates.items;
const handbookTable = databaseServer.getTables().templates.handbook;
let prices;
// Fetch the latest prices.json if we're triggered with fetch enabled, or the prices file doesn't exist
if (fetchPrices || !fs.existsSync(Mod.pricesPath)) {
logger.info("Fetching Flea Prices...");
const response = await fetch("https://raw.githubusercontent.com/DrakiaXYZ/SPT-LiveFleaPriceDB/main/prices.json");
// If the request failed, disable future updating
if (!response?.ok) {
logger.error(`Error fetching flea prices: ${response.status} (${response.statusText})`);
clearInterval(Mod.updateTimer);
return false;
}
prices = await response.json();
// Store the prices to disk for next time
fs.writeFileSync(Mod.pricesPath, JSON.stringify(prices));
// Update config file with the next update time
Mod.config.nextUpdate = Math.floor(Date.now() / 1000) + 3600;
fs.writeFileSync(Mod.configPath, JSON.stringify(Mod.config, null, 4));
}
// Otherwise, read the file from disk
else {
prices = JSON.parse(fs.readFileSync(Mod.pricesPath, "utf-8"));
}
// Loop through the new prices file, updating all prices present
for (const itemId in prices) {
if (!itemTable[itemId]) {
continue;
}
let basePrice = Mod.originalPrices[itemId];
if (!basePrice) {
basePrice = handbookTable.Items.find(x => x.Id === itemId)?.Price ?? 0;
}
const maxPrice = basePrice * Mod.config.maxIncreaseMult;
if (maxPrice !== 0 && prices[itemId] <= maxPrice) {
priceTable[itemId] = prices[itemId];
}
else {
logger.debug(`Setting ${itemId} to ${maxPrice} instead of ${prices[itemId]} due to over inflation`);
priceTable[itemId] = maxPrice;
}
}
// Update dynamic price cache.
// Note: We currently cast to `any` to bypass the protected state of the generateDynamicPrices method
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
ragfairPriceService.generateDynamicPrices();
logger.info("Flea Prices Updated!");
return true;
}
}
module.exports = { mod: new Mod() };
//# sourceMappingURL=mod.js.map
@@ -0,0 +1 @@
{"version":3,"file":"mod.js","sourceRoot":"","sources":["mod.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,128 @@
import type { DependencyContainer } from "tsyringe";
import type { ILogger } from "@spt-aki/models/spt/utils/ILogger";
import type { IPostDBLoadModAsync } from "@spt-aki/models/external/IPostDBLoadModAsync";
import type { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
import type { RagfairPriceService } from "@spt-aki/services/RagfairPriceService";
import * as fs from "node:fs";
import * as path from "node:path";
class Mod implements IPostDBLoadModAsync
{
private static container: DependencyContainer;
private static updateTimer: NodeJS.Timeout;
private static config: Config;
private static configPath = path.resolve(__dirname, "../config/config.json");
private static pricesPath = path.resolve(__dirname, "../config/prices.json");
private static originalPrices;
public async postDBLoadAsync(container: DependencyContainer): Promise<void>
{
Mod.container = container;
Mod.config = JSON.parse(fs.readFileSync(Mod.configPath, "utf-8"));
// Store a clone of the original prices table, so we can make sure things don't go too crazy
const databaseServer = Mod.container.resolve<DatabaseServer>("DatabaseServer");
const priceTable = databaseServer.getTables().templates.prices;
Mod.originalPrices = structuredClone(priceTable);
// Update prices on startup
const currentTime = Math.floor(Date.now() / 1000);
let fetchPrices = false;
if (currentTime > Mod.config.nextUpdate)
{
fetchPrices = true;
}
if (!await Mod.updatePrices(fetchPrices))
{
return;
}
// Setup a refresh interval to update once every hour
Mod.updateTimer = setInterval(Mod.updatePrices, (60 * 60 * 1000));
}
static async updatePrices(fetchPrices = true): Promise<boolean>
{
const logger = Mod.container.resolve<ILogger>("WinstonLogger");
const databaseServer = Mod.container.resolve<DatabaseServer>("DatabaseServer");
const ragfairPriceService = Mod.container.resolve<RagfairPriceService>("RagfairPriceService");
const priceTable = databaseServer.getTables().templates.prices;
const itemTable = databaseServer.getTables().templates.items;
const handbookTable = databaseServer.getTables().templates.handbook;
let prices: Record<string, number>;
// Fetch the latest prices.json if we're triggered with fetch enabled, or the prices file doesn't exist
if (fetchPrices || !fs.existsSync(Mod.pricesPath))
{
logger.info("Fetching Flea Prices...");
const response = await fetch("https://raw.githubusercontent.com/DrakiaXYZ/SPT-LiveFleaPriceDB/main/prices.json");
// If the request failed, disable future updating
if (!response?.ok)
{
logger.error(`Error fetching flea prices: ${response.status} (${response.statusText})`);
clearInterval(Mod.updateTimer);
return false;
}
prices = await response.json();
// Store the prices to disk for next time
fs.writeFileSync(Mod.pricesPath, JSON.stringify(prices));
// Update config file with the next update time
Mod.config.nextUpdate = Math.floor(Date.now() / 1000) + 3600;
fs.writeFileSync(Mod.configPath, JSON.stringify(Mod.config, null, 4));
}
// Otherwise, read the file from disk
else
{
prices = JSON.parse(fs.readFileSync(Mod.pricesPath, "utf-8"));
}
// Loop through the new prices file, updating all prices present
for (const itemId in prices)
{
if (!itemTable[itemId])
{
continue;
}
let basePrice = Mod.originalPrices[itemId];
if (!basePrice)
{
basePrice = handbookTable.Items.find(x => x.Id === itemId)?.Price ?? 0;
}
const maxPrice = basePrice * Mod.config.maxIncreaseMult;
if (maxPrice !== 0 && prices[itemId] <= maxPrice)
{
priceTable[itemId] = prices[itemId];
}
else
{
logger.debug(`Setting ${itemId} to ${maxPrice} instead of ${prices[itemId]} due to over inflation`);
priceTable[itemId] = maxPrice;
}
}
// Update dynamic price cache.
// Note: We currently cast to `any` to bypass the protected state of the generateDynamicPrices method
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
(ragfairPriceService as any).generateDynamicPrices();
logger.info("Flea Prices Updated!");
return true;
}
}
interface Config
{
nextUpdate: number,
maxIncreaseMult: number,
}
module.exports = { mod: new Mod() }