Compare commits
9 Commits
Author | SHA1 | Date |
---|---|---|
Hri7566 | add6749a51 | |
Hri7566 | bbce118370 | |
Hri7566 | 6a21aa0cbd | |
Hri7566 | 41d2330f28 | |
Hri7566 | 6a4021d5ae | |
Hri7566 | cdaba3c951 | |
Hri7566 | 99ccca2412 | |
Hri7566 | 6db28fd2bc | |
Hri7566 | 35ba9ea0cc |
|
@ -4,4 +4,3 @@ desiredUser:
|
|||
agents:
|
||||
wss://mppclone.com:
|
||||
- id: "✧𝓓𝓔𝓥 𝓡𝓸𝓸𝓶✧"
|
||||
- id: "test/awkward"
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
prefixes:
|
||||
- id: "*"
|
||||
- id: "**"
|
||||
spaced: false
|
||||
- id: cosmic
|
||||
- id: cdebug
|
||||
spaced: true
|
||||
- id: d
|
||||
spaced: false
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
debug: false
|
||||
enableConsole: false
|
||||
debug: true
|
||||
enableConsole: true
|
||||
enableMPP: true
|
||||
enableDiscord: true
|
||||
enableDiscord: false
|
||||
enableSwitchChat: false
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"module": "src/index.ts",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"bun-types": "latest"
|
||||
"bun-types": "^1.0.16"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5.0.0"
|
||||
|
|
|
@ -34,3 +34,8 @@ enum Role {
|
|||
ADMINISTRATOR
|
||||
OWNER
|
||||
}
|
||||
|
||||
model KeyValueStore {
|
||||
id Int @id @unique @default(1)
|
||||
data Json @default("{}")
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ export type BaseCommandMessage<T = unknown> = Omit<
|
|||
|
||||
export class CommandHandler {
|
||||
public static commandGroups = new Array<CommandGroup>();
|
||||
public static prefixes = new Array<Prefix>();
|
||||
public static prefixes = new Set<Prefix>();
|
||||
|
||||
public static logger = new Logger("Command Handler");
|
||||
|
||||
|
@ -172,5 +172,12 @@ export class CommandHandler {
|
|||
|
||||
// Add prefixes
|
||||
for (const prefix of prefixConfig.prefixes) {
|
||||
CommandHandler.prefixes.push(prefix);
|
||||
CommandHandler.prefixes.add(prefix);
|
||||
}
|
||||
|
||||
// Store commands for hot reload
|
||||
declare global {
|
||||
var commandHandler: any;
|
||||
}
|
||||
|
||||
globalThis.commandHandler ??= CommandHandler;
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
import { KekklefruitTree } from "../../../economy/kekkle";
|
||||
import { Command } from "../../Command";
|
||||
|
||||
export const grow = new Command(
|
||||
"grow",
|
||||
["grow"],
|
||||
"grow bozo's kekklefruit (forcefully)",
|
||||
"grow [number]",
|
||||
async msg => {
|
||||
let num: number;
|
||||
|
||||
if (msg.argv[1]) {
|
||||
num = parseInt(msg.argv[1]);
|
||||
if (isNaN(num)) return `Need number bozo`;
|
||||
} else {
|
||||
num = 1;
|
||||
}
|
||||
|
||||
await KekklefruitTree.growFruit(num);
|
||||
|
||||
return `You grew ${num} fruit.`;
|
||||
}
|
||||
);
|
|
@ -7,8 +7,9 @@ export const inventory = new Command(
|
|||
"get bozo's inventory",
|
||||
"inventory",
|
||||
msg => {
|
||||
const items = msg.inventory.items as unknown as Item[];
|
||||
const list = items
|
||||
const items = msg.inventory.items as string;
|
||||
console.log(items);
|
||||
const list = JSON.parse(items)
|
||||
.map(
|
||||
i =>
|
||||
`${i.name}${
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
import { JsonArray, JsonValue } from "@prisma/client/runtime/library";
|
||||
import { KekklefruitTree } from "../../../economy/kekkle";
|
||||
import { Command } from "../../Command";
|
||||
import { addItem, updateInventory } from "../../../data/inventory";
|
||||
|
||||
export const pick = new Command(
|
||||
"pick",
|
||||
["pick"],
|
||||
"bozo will pick fruit off the kekklefruit tree",
|
||||
"pick",
|
||||
async msg => {
|
||||
const fruit = await KekklefruitTree.pickFruit();
|
||||
|
||||
if (!fruit)
|
||||
return `There are not enough fruit on the kekklefruit tree.`;
|
||||
|
||||
addItem(msg.p._id, fruit);
|
||||
return `(insert random boring message about ${fruit.name} here)`;
|
||||
}
|
||||
);
|
|
@ -0,0 +1,12 @@
|
|||
import { KekklefruitTree } from "../../../economy/kekkle";
|
||||
import { Command } from "../../Command";
|
||||
|
||||
export const tree = new Command(
|
||||
"tree",
|
||||
["tree"],
|
||||
"bozo will get the amount of fruit on the kekklefruit tree",
|
||||
"tree",
|
||||
async msg => {
|
||||
return `There are ${KekklefruitTree.getFruitCount()} kekklefruit on the tree.`;
|
||||
}
|
||||
);
|
|
@ -0,0 +1,14 @@
|
|||
import { deleteInventory } from "../../../data/inventory";
|
||||
import { Command } from "../../Command";
|
||||
|
||||
export const delinv = new Command(
|
||||
"delinv",
|
||||
["delinv"],
|
||||
"delete a bozo's inventory",
|
||||
"delinv [id]",
|
||||
async (msg) => {
|
||||
let userId = msg.argv[1] ? msg.argv[1] : msg.p._id;
|
||||
await deleteInventory(userId);
|
||||
return `Inventory of \`${userId}\` deleted.`
|
||||
}
|
||||
);
|
|
@ -6,7 +6,7 @@ export const id = new Command(
|
|||
"get your id bozo",
|
||||
"id",
|
||||
(msg, agent) => {
|
||||
if (agent.platform == "mpp") {
|
||||
if (agent.platform === "mpp") {
|
||||
return `ID: \`${
|
||||
(msg.originalMessage as any).p._id
|
||||
}\` Cosmic ID: \`${msg.p._id}\``;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { CommandGroup } from "./CommandGroup";
|
||||
import { CommandHandler } from "./CommandHandler";
|
||||
import { about } from "./commands/general/about";
|
||||
import { help } from "./commands/general/help";
|
||||
import { id } from "./commands/utility/id";
|
||||
|
@ -16,20 +15,24 @@ import { uptime } from "./commands/utility/uptime";
|
|||
import { balance } from "./commands/economy/balance";
|
||||
import { permissions } from "./commands/utility/permissions";
|
||||
import { branch } from "./commands/utility/branch";
|
||||
import { tree } from "./commands/economy/tree";
|
||||
import { pick } from "./commands/economy/pick";
|
||||
import { grow } from "./commands/economy/grow";
|
||||
import { delinv } from "./commands/utility/delinv";
|
||||
|
||||
export function loadCommands() {
|
||||
// cringe
|
||||
const general = new CommandGroup("general", "⭐ General");
|
||||
general.addCommands([help, about]);
|
||||
CommandHandler.addCommandGroup(general);
|
||||
globalThis.commandHandler.addCommandGroup(general);
|
||||
|
||||
const economy = new CommandGroup("economy", "💸 Economy");
|
||||
economy.addCommands([inventory, balance]);
|
||||
CommandHandler.addCommandGroup(economy);
|
||||
economy.addCommands([inventory, balance, tree, pick, grow]);
|
||||
globalThis.commandHandler.addCommandGroup(economy);
|
||||
|
||||
const fun = new CommandGroup("fun", "✨ Fun");
|
||||
fun.addCommands([magic8ball]);
|
||||
CommandHandler.addCommandGroup(fun);
|
||||
globalThis.commandHandler.addCommandGroup(fun);
|
||||
|
||||
const utility = new CommandGroup("utility", "🔨 Utility");
|
||||
utility.addCommands([
|
||||
|
@ -43,7 +46,10 @@ export function loadCommands() {
|
|||
ic,
|
||||
uptime,
|
||||
permissions,
|
||||
branch
|
||||
branch,
|
||||
delinv
|
||||
]);
|
||||
CommandHandler.addCommandGroup(utility);
|
||||
globalThis.commandHandler.addCommandGroup(utility);
|
||||
}
|
||||
|
||||
export { CommandGroup };
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import { Inventory } from "@prisma/client";
|
||||
import { prisma } from "./prisma";
|
||||
import { JsonArray } from "@prisma/client/runtime/library";
|
||||
import { Item, StackableItem } from "../economy/Item";
|
||||
|
||||
export async function createInventory(data: Omit<Inventory, "id">) {
|
||||
await prisma.inventory.create({
|
||||
|
@ -14,13 +16,51 @@ export async function readInventory(userId: Inventory["userId"]) {
|
|||
return await prisma.inventory.findUnique({ where: { userId: userId } });
|
||||
}
|
||||
|
||||
export function collapseInventory(inventoryData: Item[]) {
|
||||
for (let i = 0; i < inventoryData.length; i++) {
|
||||
if (i <= 0) continue;
|
||||
|
||||
if (inventoryData[i].id === inventoryData[i - 1].id) {
|
||||
if (
|
||||
typeof (inventoryData[i - 1] as StackableItem).count ===
|
||||
"number" &&
|
||||
typeof (inventoryData[i] as StackableItem).count === "number"
|
||||
) {
|
||||
(inventoryData[i - 1] as StackableItem).count += (
|
||||
inventoryData[i] as StackableItem
|
||||
).count;
|
||||
inventoryData.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateInventory(data: Omit<Inventory, "id">) {
|
||||
collapseInventory(data.items as unknown as Item[]);
|
||||
return await prisma.inventory.update({
|
||||
where: { userId: data.userId },
|
||||
data: {}
|
||||
data: {
|
||||
balance: data.balance,
|
||||
items: JSON.stringify(data.items)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function deleteInventory(userId: Inventory["userId"]) {
|
||||
return await prisma.inventory.delete({ where: { userId } });
|
||||
}
|
||||
|
||||
export async function addItem<T extends Item>(userId: Inventory["userId"], item: T) {
|
||||
let inventory = await readInventory(userId);
|
||||
if (!inventory) return false;
|
||||
|
||||
console.log(inventory.items);
|
||||
|
||||
inventory.items = JSON.stringify(JSON.parse(inventory.items as string).push(item));
|
||||
collapseInventory(inventory.items as unknown as Item[]);
|
||||
|
||||
await updateInventory(inventory);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,51 @@
|
|||
import { PrismaClient } from "@prisma/client";
|
||||
import { JsonObject } from "@prisma/client/runtime/library";
|
||||
|
||||
export const prisma = new PrismaClient();
|
||||
declare global {
|
||||
var prisma: PrismaClient;
|
||||
}
|
||||
|
||||
globalThis.prisma ??= new PrismaClient();
|
||||
export const prisma = globalThis.prisma;
|
||||
|
||||
export async function set(key: string, value: any) {
|
||||
const store = await globalThis.prisma.keyValueStore.findUnique({
|
||||
where: { id: 1 }
|
||||
});
|
||||
|
||||
if (!store) {
|
||||
// throw new Error("Unable to access key-value store.");
|
||||
await prisma.keyValueStore.create({
|
||||
data: {}
|
||||
});
|
||||
|
||||
return set(key, value);
|
||||
}
|
||||
|
||||
const data = store.data as JsonObject;
|
||||
data[key] = value;
|
||||
|
||||
await globalThis.prisma.keyValueStore.update({
|
||||
where: { id: 1 },
|
||||
data: { data: data }
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
export async function get<T = unknown>(key: string) {
|
||||
const store = await globalThis.prisma.keyValueStore.findUnique({
|
||||
where: { id: 1 }
|
||||
});
|
||||
|
||||
if (!store) {
|
||||
// throw new Error("Unable to access key-value store.");
|
||||
await globalThis.prisma.keyValueStore.create({
|
||||
data: {}
|
||||
});
|
||||
|
||||
return get(key);
|
||||
}
|
||||
|
||||
const data = store.data as JsonObject;
|
||||
return data[key] as T;
|
||||
}
|
||||
|
|
|
@ -6,3 +6,22 @@ export interface Item {
|
|||
export interface StackableItem extends Item {
|
||||
count: number;
|
||||
}
|
||||
|
||||
export interface ConsumableItem extends Item {
|
||||
consumable: true;
|
||||
}
|
||||
|
||||
export interface FoodItem extends ConsumableItem {
|
||||
edible: true;
|
||||
}
|
||||
|
||||
export interface CakeItem extends FoodItem {
|
||||
emoji: string;
|
||||
icing: string;
|
||||
filling: string;
|
||||
}
|
||||
|
||||
export interface ShopItem extends Item {
|
||||
buyValue: number;
|
||||
sellValue: number;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
import { Item } from "./Item";
|
||||
|
||||
const items = new Map<string, Item>();
|
||||
|
||||
export function getItem(key: string) {
|
||||
return items.get(key);
|
||||
}
|
||||
|
||||
export function setItem(key: string, item: Item) {
|
||||
return items.set(key, item);
|
||||
}
|
||||
|
||||
export function deleteItem(key: string) {
|
||||
return items.delete(key);
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
import { get, set } from "../data/prisma";
|
||||
import { Logger } from "../util/Logger";
|
||||
import { FoodItem } from "./Item";
|
||||
|
||||
export class KekklefruitTree {
|
||||
protected static fruit: number = 0;
|
||||
public static logger = new Logger("Kekklefruit Tree");
|
||||
|
||||
public static async saveFruit() {
|
||||
return set("kekklefruit-tree", this.fruit);
|
||||
}
|
||||
|
||||
public static async loadFruit() {
|
||||
let fruit = await get<number>("kekklefruit-tree");
|
||||
let save = false;
|
||||
|
||||
if (!fruit) {
|
||||
fruit = 0;
|
||||
save = true;
|
||||
}
|
||||
|
||||
this.fruit = fruit;
|
||||
if (save) this.saveFruit();
|
||||
}
|
||||
|
||||
public static async growFruit(amount: number = 1) {
|
||||
this.fruit += amount;
|
||||
await this.saveFruit();
|
||||
}
|
||||
|
||||
public static getFruitCount() {
|
||||
return this.fruit;
|
||||
}
|
||||
|
||||
public static async pickFruit() {
|
||||
if (this.fruit > 0) {
|
||||
this.fruit--;
|
||||
await this.saveFruit();
|
||||
return this.randomFruit();
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
public static randomFruit() {
|
||||
return {
|
||||
id: "kekklefruit",
|
||||
name: "Kekklefruit",
|
||||
consumable: true,
|
||||
edible: true
|
||||
} as FoodItem;
|
||||
}
|
||||
}
|
||||
|
||||
await KekklefruitTree.loadFruit();
|
52
src/index.ts
52
src/index.ts
|
@ -1,12 +1,54 @@
|
|||
import { loadCommands } from "./commands";
|
||||
import { loadCommands, type CommandGroup } from "./commands";
|
||||
import { CommandHandler } from "./commands/CommandHandler";
|
||||
import { loadRoleConfig } from "./permissions";
|
||||
import { ServiceLoader } from "./services";
|
||||
import { ConsoleAgent } from "./services/console";
|
||||
import { printStartupASCII } from "./util/ascii";
|
||||
|
||||
printStartupASCII();
|
||||
loadRoleConfig();
|
||||
loadCommands();
|
||||
ServiceLoader.loadServices();
|
||||
// Hot reload persistence
|
||||
declare global {
|
||||
var loaded: boolean;
|
||||
var serviceLoader: any;
|
||||
}
|
||||
|
||||
globalThis.loaded ??= false;
|
||||
globalThis.serviceLoader ??= ServiceLoader;
|
||||
|
||||
function load() {
|
||||
printStartupASCII();
|
||||
loadRoleConfig();
|
||||
loadCommands();
|
||||
globalThis.serviceLoader.loadServices();
|
||||
|
||||
globalThis.loaded = true;
|
||||
}
|
||||
|
||||
function reload() {
|
||||
console.log("Reloading...");
|
||||
|
||||
// Reload commands
|
||||
globalThis.commandHandler.commandGroups = new Array<CommandGroup>();
|
||||
loadCommands();
|
||||
|
||||
// Reload services
|
||||
globalThis.serviceLoader.unloadServices();
|
||||
globalThis.serviceLoader.loadServices();
|
||||
|
||||
// Set console prompt
|
||||
globalThis.serviceLoader.agents.forEach(agent => {
|
||||
if (agent.platform === "console")
|
||||
(agent as ConsoleAgent).client.prompt();
|
||||
});
|
||||
}
|
||||
|
||||
// Check for hot reload
|
||||
if (!globalThis.loaded) {
|
||||
load();
|
||||
} else {
|
||||
console.clear();
|
||||
console.log("Hot reload triggered");
|
||||
reload();
|
||||
}
|
||||
|
||||
export function scopedEval(code: string) {
|
||||
return eval(code);
|
||||
|
|
|
@ -23,9 +23,9 @@ export function handlePermission(node1: string, node2: string) {
|
|||
|
||||
// Check nodes in order
|
||||
for (let i = 0; i < hierarchy1.length; i++) {
|
||||
if (hierarchy1[i] == hierarchy2[i]) {
|
||||
if (hierarchy1[i] === hierarchy2[i]) {
|
||||
// Last node?
|
||||
if (i == hierarchy1.length - 1 || i == hierarchy2.length - 1) {
|
||||
if (i === hierarchy1.length - 1 || i === hierarchy2.length - 1) {
|
||||
return true;
|
||||
} else {
|
||||
continue;
|
||||
|
@ -33,8 +33,8 @@ export function handlePermission(node1: string, node2: string) {
|
|||
}
|
||||
|
||||
// Wildcard?
|
||||
if (hierarchy1[i] == "*") return true;
|
||||
if (hierarchy2[i] == "*") return true;
|
||||
if (hierarchy1[i] === "*") return true;
|
||||
if (hierarchy2[i] === "*") return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -66,7 +66,12 @@ export function hasPermission(role: Role, permission: string) {
|
|||
return false;
|
||||
}
|
||||
|
||||
export const roles = new Map<Role, TRole>();
|
||||
declare global {
|
||||
var roles: Map<Role, TRole>;
|
||||
}
|
||||
|
||||
globalThis.roles ??= new Map<Role, TRole>();
|
||||
export const roles = globalThis.roles;
|
||||
|
||||
export type TRole = {
|
||||
displayName: string;
|
||||
|
|
|
@ -22,7 +22,7 @@ export interface ChatMessage<T = unknown> {
|
|||
|
||||
function onChildMessage(msg: ChatMessage) {
|
||||
const consoleAgent = ServiceLoader.agents.find(
|
||||
ag => ag.platform == "console"
|
||||
ag => ag.platform === "console"
|
||||
) as ConsoleAgent | undefined;
|
||||
|
||||
if (!consoleAgent) return;
|
||||
|
@ -34,7 +34,7 @@ function onChildMessage(msg: ChatMessage) {
|
|||
|
||||
function onConsoleMessage(text: string) {
|
||||
const consoleAgent = ServiceLoader.agents.find(
|
||||
ag => ag.platform == "console"
|
||||
ag => ag.platform === "console"
|
||||
) as ConsoleAgent | undefined;
|
||||
|
||||
if (!consoleAgent) return;
|
||||
|
@ -77,7 +77,7 @@ export class MicroHandler {
|
|||
|
||||
for (let i in ServiceLoader.agents) {
|
||||
const agent2 = ServiceLoader.agents[i];
|
||||
if (agent2.platform == "mpp") {
|
||||
if (agent2.platform === "mpp") {
|
||||
agent.emit(
|
||||
"log",
|
||||
`${i} - ${agent2.platform} - ${
|
||||
|
@ -101,7 +101,7 @@ export class MicroHandler {
|
|||
let walkie = agent as ConsoleAgent;
|
||||
let talky = ServiceLoader.agents[index];
|
||||
|
||||
if (index == ServiceLoader.agents.indexOf(walkie))
|
||||
if (index === ServiceLoader.agents.indexOf(walkie))
|
||||
return "Why would you want to chat with yourself?";
|
||||
|
||||
// Remove old listeners
|
||||
|
|
|
@ -37,7 +37,7 @@ export class ConsoleAgent extends ServiceAgent<readline.ReadLine> {
|
|||
public stop() {
|
||||
if (!this.started) return;
|
||||
this.started = false;
|
||||
this.client.setPrompt("");
|
||||
this.client.close();
|
||||
}
|
||||
|
||||
protected bindEventListeners(): void {
|
||||
|
@ -65,7 +65,10 @@ export class ConsoleAgent extends ServiceAgent<readline.ReadLine> {
|
|||
if (text.startsWith("/")) {
|
||||
out = await MicroHandler.handleMicroCommand(message, this);
|
||||
} else {
|
||||
out = await CommandHandler.handleCommand(message, this);
|
||||
out = await globalThis.commandHandler.handleCommand(
|
||||
message,
|
||||
this
|
||||
);
|
||||
}
|
||||
|
||||
if (out) {
|
||||
|
|
|
@ -56,7 +56,7 @@ export class DiscordAgent extends ServiceAgent<Discord.Client> {
|
|||
|
||||
let args = msg.content.split(" ");
|
||||
|
||||
const str = await CommandHandler.handleCommand(
|
||||
const str = await globalThis.commandHandler.handleCommand(
|
||||
{
|
||||
m: "command",
|
||||
a: msg.content,
|
||||
|
@ -74,7 +74,7 @@ export class DiscordAgent extends ServiceAgent<Discord.Client> {
|
|||
);
|
||||
|
||||
if (str) {
|
||||
if (typeof str == "string") {
|
||||
if (typeof str === "string") {
|
||||
const channel = await this.client.channels.fetch(
|
||||
msg.channelId
|
||||
);
|
||||
|
|
|
@ -50,6 +50,10 @@ export class ServiceLoader {
|
|||
this.agents.push(agent);
|
||||
}
|
||||
|
||||
public static getAgent(index: number) {
|
||||
return this.agents[index];
|
||||
}
|
||||
|
||||
public static loadServices() {
|
||||
if (config.enableMPP) {
|
||||
for (const uri of Object.keys(mppConfig.agents)) {
|
||||
|
@ -96,4 +100,11 @@ export class ServiceLoader {
|
|||
this.addAgent(consoleAgent);
|
||||
}
|
||||
}
|
||||
|
||||
public static unloadServices() {
|
||||
for (const agent of this.agents) {
|
||||
agent.stop();
|
||||
this.agents.splice(this.agents.indexOf(agent), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ export class MPPAgent extends ServiceAgent<Client> {
|
|||
let args = msg.a.split(" ");
|
||||
|
||||
// Run command and get output
|
||||
const str = await CommandHandler.handleCommand(
|
||||
const str = await globalThis.commandHandler.handleCommand(
|
||||
{
|
||||
m: "command",
|
||||
a: msg.a,
|
||||
|
@ -80,7 +80,7 @@ export class MPPAgent extends ServiceAgent<Client> {
|
|||
|
||||
// Send message in chat
|
||||
if (str) {
|
||||
if (typeof str == "string") {
|
||||
if (typeof str === "string") {
|
||||
if (str.includes("\n")) {
|
||||
let sp = str.split("\n");
|
||||
|
||||
|
|
|
@ -80,9 +80,9 @@ export class CosmicColor {
|
|||
let g = (~~this.g || 0).toString(16);
|
||||
let b = (~~this.b || 0).toString(16);
|
||||
|
||||
if (r.length == 1) r = "0" + r;
|
||||
if (g.length == 1) g = "0" + g;
|
||||
if (b.length == 1) b = "0" + b;
|
||||
if (r.length === 1) r = "0" + r;
|
||||
if (g.length === 1) g = "0" + g;
|
||||
if (b.length === 1) b = "0" + b;
|
||||
|
||||
return "#" + r + g + b;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import { parse as parsePath } from "path/posix";
|
|||
* @returns Parsed YAML config
|
||||
*/
|
||||
export function loadConfig<T>(configPath: string, defaultConfig: T): T {
|
||||
console.time(`Loading config ${configPath}`);
|
||||
// Config exists?
|
||||
if (existsSync(configPath)) {
|
||||
// Load config
|
||||
|
@ -30,12 +31,12 @@ export function loadConfig<T>(configPath: string, defaultConfig: T): T {
|
|||
obj2: Record<string, unknown>
|
||||
) {
|
||||
for (const key of Object.keys(obj2)) {
|
||||
if (typeof obj[key] == "undefined") {
|
||||
if (typeof obj[key] === "undefined") {
|
||||
obj[key] = obj2[key];
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (typeof obj[key] == "object" && !Array.isArray(obj[key])) {
|
||||
if (typeof obj[key] === "object" && !Array.isArray(obj[key])) {
|
||||
mix(
|
||||
obj[key] as Record<string, unknown>,
|
||||
obj2[key] as Record<string, unknown>
|
||||
|
@ -45,7 +46,7 @@ export function loadConfig<T>(configPath: string, defaultConfig: T): T {
|
|||
}
|
||||
|
||||
// Apply any missing default values
|
||||
mix(config, defRecord);
|
||||
// mix(config, defRecord);
|
||||
|
||||
// Save config if modified
|
||||
if (changed) writeConfig(configPath, config);
|
||||
|
@ -54,6 +55,7 @@ export function loadConfig<T>(configPath: string, defaultConfig: T): T {
|
|||
} else {
|
||||
// Write default config to disk and use that
|
||||
writeConfig(configPath, defaultConfig);
|
||||
|
||||
return defaultConfig as T;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
import { expect, test } from "bun:test";
|
||||
import { collapseInventory } from "../../src/data/inventory";
|
||||
import { StackableItem } from "../../src/economy/Item";
|
||||
|
||||
test("Collapse inventory", () => {
|
||||
let sampleData: StackableItem[] = [
|
||||
{
|
||||
id: "test_item",
|
||||
name: "Test Item",
|
||||
count: 10
|
||||
},
|
||||
{
|
||||
id: "test_item",
|
||||
name: "Test Item",
|
||||
count: 15
|
||||
}
|
||||
];
|
||||
|
||||
collapseInventory(sampleData);
|
||||
expect(sampleData[0].count).toBe(25);
|
||||
expect(sampleData[1]).toBe(undefined);
|
||||
console.log(sampleData);
|
||||
});
|
Loading…
Reference in New Issue