style: run format:apply

This commit is contained in:
2026-06-19 04:29:24 -03:00
parent f51a71a574
commit c2b94bec4a
36 changed files with 3251 additions and 2597 deletions
+244 -141
View File
@@ -2,161 +2,264 @@ import { create } from 'zustand';
import { persist } from 'zustand/middleware';
export interface InventoryState {
unlockedCharacters: string[];
unlockedCustomizations: string[];
unlockedDLCs: string[];
unlockedPerks: string[];
items: Record<string, number>;
offerings: Record<string, number>;
addons: Record<string, number>;
unlockedCharacters: string[];
unlockedCustomizations: string[];
unlockedDLCs: string[];
unlockedPerks: string[];
items: Record<string, number>;
offerings: Record<string, number>;
addons: Record<string, number>;
spoofItems: boolean;
spoofPerks: boolean;
spoofCatalog: boolean;
spoofDLCs: boolean;
spoofItems: boolean;
spoofPerks: boolean;
spoofCatalog: boolean;
spoofDLCs: boolean;
toggleItem: (id: string, category: 'characters' | 'customizations' | 'items' | 'offerings' | 'addons' | 'dlcs' | 'perks') => void;
setItemQuantity: (id: string, qty: number) => void;
setOfferingQuantity: (id: string, qty: number) => void;
setAddonQuantity: (id: string, qty: number) => void;
setToggle: (key: 'spoofItems' | 'spoofPerks' | 'spoofCatalog' | 'spoofDLCs', val: boolean) => void;
importToggles: (toggles: any) => void;
toggleItem: (
id: string,
category:
| 'characters'
| 'customizations'
| 'items'
| 'offerings'
| 'addons'
| 'dlcs'
| 'perks'
) => void;
setItemQuantity: (id: string, qty: number) => void;
setOfferingQuantity: (id: string, qty: number) => void;
setAddonQuantity: (id: string, qty: number) => void;
setToggle: (
key: 'spoofItems' | 'spoofPerks' | 'spoofCatalog' | 'spoofDLCs',
val: boolean
) => void;
importToggles: (toggles: any) => void;
unlockAllInCategory: (category: 'characters' | 'customizations' | 'items' | 'offerings' | 'addons' | 'dlcs' | 'perks', allIds: string[], qty?: number) => void;
clearCategory: (category: 'characters' | 'customizations' | 'items' | 'offerings' | 'addons' | 'dlcs' | 'perks') => void;
clearAll: () => void;
importProfile: (profile: any) => void;
unlockAllInCategory: (
category:
| 'characters'
| 'customizations'
| 'items'
| 'offerings'
| 'addons'
| 'dlcs'
| 'perks',
allIds: string[],
qty?: number
) => void;
clearCategory: (
category:
| 'characters'
| 'customizations'
| 'items'
| 'offerings'
| 'addons'
| 'dlcs'
| 'perks'
) => void;
clearAll: () => void;
importProfile: (profile: any) => void;
}
export const useInventoryStore = create<InventoryState>()(
persist(
(set) => ({
unlockedCharacters: [],
unlockedCustomizations: [],
unlockedDLCs: [],
unlockedPerks: [],
items: {},
offerings: {},
addons: {},
persist(
(set) => ({
unlockedCharacters: [],
unlockedCustomizations: [],
unlockedDLCs: [],
unlockedPerks: [],
items: {},
offerings: {},
addons: {},
spoofItems: false,
spoofPerks: false,
spoofCatalog: false,
spoofDLCs: false,
spoofItems: false,
spoofPerks: false,
spoofCatalog: false,
spoofDLCs: false,
setToggle: (key, val) => set({ [key]: val }),
setToggle: (key, val) => set({ [key]: val }),
importToggles: (toggles) => set((state) => {
if (!toggles) return {};
return {
spoofItems: typeof toggles.spoofItems === 'boolean' ? toggles.spoofItems : state.spoofItems,
spoofPerks: typeof toggles.spoofPerks === 'boolean' ? toggles.spoofPerks : state.spoofPerks,
spoofCatalog: typeof toggles.spoofCatalog === 'boolean' ? toggles.spoofCatalog : state.spoofCatalog,
spoofDLCs: typeof toggles.spoofDLCs === 'boolean' ? toggles.spoofDLCs : state.spoofDLCs,
};
}),
importToggles: (toggles) =>
set((state) => {
if (!toggles) return {};
return {
spoofItems:
typeof toggles.spoofItems === 'boolean'
? toggles.spoofItems
: state.spoofItems,
spoofPerks:
typeof toggles.spoofPerks === 'boolean'
? toggles.spoofPerks
: state.spoofPerks,
spoofCatalog:
typeof toggles.spoofCatalog === 'boolean'
? toggles.spoofCatalog
: state.spoofCatalog,
spoofDLCs:
typeof toggles.spoofDLCs === 'boolean'
? toggles.spoofDLCs
: state.spoofDLCs
};
}),
toggleItem: (id, category) => set((state) => {
if (category === 'characters') {
const arr = state.unlockedCharacters;
return { unlockedCharacters: arr.includes(id) ? arr.filter(i => i !== id) : [...arr, id] };
} else if (category === 'customizations') {
const arr = state.unlockedCustomizations;
return { unlockedCustomizations: arr.includes(id) ? arr.filter(i => i !== id) : [...arr, id] };
} else if (category === 'dlcs') {
const arr = state.unlockedDLCs;
return { unlockedDLCs: arr.includes(id) ? arr.filter(i => i !== id) : [...arr, id] };
} else if (category === 'perks') {
const arr = state.unlockedPerks;
return { unlockedPerks: arr.includes(id) ? arr.filter(i => i !== id) : [...arr, id] };
} else if (category === 'items') {
const newItems = { ...state.items };
if ((newItems[id] || 0) > 0) delete newItems[id]; else newItems[id] = 100;
return { items: newItems };
} else if (category === 'addons') {
const newAddons = { ...state.addons };
if ((newAddons[id] || 0) > 0) delete newAddons[id]; else newAddons[id] = 100;
return { addons: newAddons };
} else {
const newOfferings = { ...state.offerings };
if ((newOfferings[id] || 0) > 0) delete newOfferings[id]; else newOfferings[id] = 100;
return { offerings: newOfferings };
}
}),
toggleItem: (id, category) =>
set((state) => {
if (category === 'characters') {
const arr = state.unlockedCharacters;
return {
unlockedCharacters: arr.includes(id)
? arr.filter((i) => i !== id)
: [...arr, id]
};
} else if (category === 'customizations') {
const arr = state.unlockedCustomizations;
return {
unlockedCustomizations: arr.includes(id)
? arr.filter((i) => i !== id)
: [...arr, id]
};
} else if (category === 'dlcs') {
const arr = state.unlockedDLCs;
return {
unlockedDLCs: arr.includes(id)
? arr.filter((i) => i !== id)
: [...arr, id]
};
} else if (category === 'perks') {
const arr = state.unlockedPerks;
return {
unlockedPerks: arr.includes(id)
? arr.filter((i) => i !== id)
: [...arr, id]
};
} else if (category === 'items') {
const newItems = { ...state.items };
if ((newItems[id] || 0) > 0) delete newItems[id];
else newItems[id] = 100;
return { items: newItems };
} else if (category === 'addons') {
const newAddons = { ...state.addons };
if ((newAddons[id] || 0) > 0) delete newAddons[id];
else newAddons[id] = 100;
return { addons: newAddons };
} else {
const newOfferings = { ...state.offerings };
if ((newOfferings[id] || 0) > 0) delete newOfferings[id];
else newOfferings[id] = 100;
return { offerings: newOfferings };
}
}),
setItemQuantity: (id, qty) => set((state) => {
const newItems = { ...state.items };
if (qty <= 0) delete newItems[id]; else newItems[id] = Math.min(32767, Math.max(0, qty));
return { items: newItems };
}),
setItemQuantity: (id, qty) =>
set((state) => {
const newItems = { ...state.items };
if (qty <= 0) delete newItems[id];
else newItems[id] = Math.min(32767, Math.max(0, qty));
return { items: newItems };
}),
setOfferingQuantity: (id, qty) => set((state) => {
const newOfferings = { ...state.offerings };
if (qty <= 0) delete newOfferings[id]; else newOfferings[id] = Math.min(32767, Math.max(0, qty));
return { offerings: newOfferings };
}),
setOfferingQuantity: (id, qty) =>
set((state) => {
const newOfferings = { ...state.offerings };
if (qty <= 0) delete newOfferings[id];
else newOfferings[id] = Math.min(32767, Math.max(0, qty));
return { offerings: newOfferings };
}),
setAddonQuantity: (id, qty) => set((state) => {
const newAddons = { ...state.addons };
if (qty <= 0) delete newAddons[id]; else newAddons[id] = Math.min(32767, Math.max(0, qty));
return { addons: newAddons };
}),
setAddonQuantity: (id, qty) =>
set((state) => {
const newAddons = { ...state.addons };
if (qty <= 0) delete newAddons[id];
else newAddons[id] = Math.min(32767, Math.max(0, qty));
return { addons: newAddons };
}),
unlockAllInCategory: (category, allIds, qty = 100) => set((state) => {
if (category === 'characters') return { unlockedCharacters: allIds };
if (category === 'customizations') return { unlockedCustomizations: allIds };
if (category === 'dlcs') return { unlockedDLCs: allIds };
if (category === 'perks') return { unlockedPerks: allIds };
if (category === 'items') {
const newItems = { ...state.items };
allIds.forEach(id => { newItems[id] = qty; });
return { items: newItems };
} else if (category === 'addons') {
const newAddons = { ...state.addons };
allIds.forEach(id => { newAddons[id] = qty; });
return { addons: newAddons };
} else {
const newOfferings = { ...state.offerings };
allIds.forEach(id => { newOfferings[id] = qty; });
return { offerings: newOfferings };
}
}),
unlockAllInCategory: (category, allIds, qty = 100) =>
set((state) => {
if (category === 'characters') return { unlockedCharacters: allIds };
if (category === 'customizations')
return { unlockedCustomizations: allIds };
if (category === 'dlcs') return { unlockedDLCs: allIds };
if (category === 'perks') return { unlockedPerks: allIds };
if (category === 'items') {
const newItems = { ...state.items };
allIds.forEach((id) => {
newItems[id] = qty;
});
return { items: newItems };
} else if (category === 'addons') {
const newAddons = { ...state.addons };
allIds.forEach((id) => {
newAddons[id] = qty;
});
return { addons: newAddons };
} else {
const newOfferings = { ...state.offerings };
allIds.forEach((id) => {
newOfferings[id] = qty;
});
return { offerings: newOfferings };
}
}),
clearCategory: (category) => set(() => {
if (category === 'characters') return { unlockedCharacters: [] };
if (category === 'customizations') return { unlockedCustomizations: [] };
if (category === 'dlcs') return { unlockedDLCs: [] };
if (category === 'perks') return { unlockedPerks: [] };
if (category === 'items') return { items: {} };
if (category === 'addons') return { addons: {} };
return { offerings: {} };
}),
clearCategory: (category) =>
set(() => {
if (category === 'characters') return { unlockedCharacters: [] };
if (category === 'customizations')
return { unlockedCustomizations: [] };
if (category === 'dlcs') return { unlockedDLCs: [] };
if (category === 'perks') return { unlockedPerks: [] };
if (category === 'items') return { items: {} };
if (category === 'addons') return { addons: {} };
return { offerings: {} };
}),
clearAll: () => set({
unlockedCharacters: [],
unlockedCustomizations: [],
unlockedDLCs: [],
unlockedPerks: [],
items: {},
offerings: {},
addons: {},
}),
clearAll: () =>
set({
unlockedCharacters: [],
unlockedCustomizations: [],
unlockedDLCs: [],
unlockedPerks: [],
items: {},
offerings: {},
addons: {}
}),
importProfile: (profile) => set((state) => {
if (!profile) return {};
return {
unlockedCharacters: Array.isArray(profile.unlockedCharacters) ? profile.unlockedCharacters : state.unlockedCharacters,
unlockedCustomizations: Array.isArray(profile.unlockedCustomizations) ? profile.unlockedCustomizations : state.unlockedCustomizations,
unlockedDLCs: Array.isArray(profile.unlockedDLCs) ? profile.unlockedDLCs : state.unlockedDLCs,
unlockedPerks: Array.isArray(profile.unlockedPerks) ? profile.unlockedPerks : state.unlockedPerks,
items: (profile.items && typeof profile.items === 'object') ? profile.items : state.items,
offerings: (profile.offerings && typeof profile.offerings === 'object') ? profile.offerings : state.offerings,
addons: (profile.addons && typeof profile.addons === 'object') ? profile.addons : state.addons,
};
})
}),
{
name: 'hex-unlocked-inventory',
}
)
);
importProfile: (profile) =>
set((state) => {
if (!profile) return {};
return {
unlockedCharacters: Array.isArray(profile.unlockedCharacters)
? profile.unlockedCharacters
: state.unlockedCharacters,
unlockedCustomizations: Array.isArray(
profile.unlockedCustomizations
)
? profile.unlockedCustomizations
: state.unlockedCustomizations,
unlockedDLCs: Array.isArray(profile.unlockedDLCs)
? profile.unlockedDLCs
: state.unlockedDLCs,
unlockedPerks: Array.isArray(profile.unlockedPerks)
? profile.unlockedPerks
: state.unlockedPerks,
items:
profile.items && typeof profile.items === 'object'
? profile.items
: state.items,
offerings:
profile.offerings && typeof profile.offerings === 'object'
? profile.offerings
: state.offerings,
addons:
profile.addons && typeof profile.addons === 'object'
? profile.addons
: state.addons
};
})
}),
{
name: 'hex-unlocked-inventory'
}
)
);
+102 -40
View File
@@ -1,56 +1,118 @@
import { create } from 'zustand';
import { useInventoryStore } from './useInventoryStore';
import { mapStoreToSpooferConfig, mapSpooferConfigToStore } from './wsProtocol';
interface WebsocketState {
socket: WebSocket | null;
isConnected: boolean;
connect: () => void;
socket: WebSocket | null;
isConnected: boolean;
connect: () => void;
}
let lastTogglesJson = '';
let lastInventoryJson = '';
export const useWebsocketStore = create<WebsocketState>((set, get) => ({
socket: null,
isConnected: false,
socket: null,
isConnected: false,
connect: () => {
if (get().socket) return;
connect: () => {
if (get().socket) return;
const ws = new WebSocket('ws://localhost:4444');
const ws = new WebSocket('ws://localhost:4444');
ws.onopen = () => {
console.log('Connected to Spoofer Engine');
set({ socket: ws, isConnected: true });
};
ws.onopen = () => {
console.log('Connected to Spoofer Engine');
set({ socket: ws, isConnected: true });
};
ws.onclose = () => {
console.log('Disconnected. Retrying in 2s...');
set({ socket: null, isConnected: false });
setTimeout(() => get().connect(), 2000);
};
ws.onclose = () => {
console.log('Disconnected. Retrying in 2s...');
set({ socket: null, isConnected: false });
setTimeout(() => get().connect(), 2000);
};
ws.onerror = (err) => {
console.error('WS Error:', err);
ws.close();
};
ws.onerror = (err) => {
console.error('WS Error:', err);
ws.close();
};
ws.onmessage = (msg) => {
try {
const payload = JSON.parse(msg.data);
if (payload.action === 'init_config')
useInventoryStore.getState().importProfile(payload.data);
} catch (e) {
console.error("Failed to parse WS message", e);
}
};
}
ws.onmessage = async (msg) => {
try {
const payload = JSON.parse(msg.data);
// C++ sends action=0 (INIT_CONFIG) on WebSocket open
if (payload.action === 0) {
const mapped = await mapSpooferConfigToStore(payload.profile);
// Snapshot current state strings to prevent echo
lastInventoryJson = JSON.stringify({
unlockedCharacters: mapped.unlockedCharacters,
unlockedCustomizations: mapped.unlockedCustomizations,
unlockedDLCs: mapped.unlockedDLCs,
unlockedPerks: mapped.unlockedPerks,
items: mapped.items,
offerings: mapped.offerings,
addons: mapped.addons
});
lastTogglesJson = JSON.stringify({
spoofItems: payload.toggles?.spoofItems ?? false,
spoofPerks: payload.toggles?.spoofPerks ?? false,
spoofCatalog: payload.toggles?.spoofCatalog ?? false,
spoofDLCs: payload.toggles?.spoofDLCs ?? false
});
useInventoryStore.getState().importProfile(mapped);
useInventoryStore.getState().importToggles(payload.toggles);
}
} catch (e) {
console.error('Failed to parse WS message', e);
}
};
}
}));
useInventoryStore.subscribe((newState) => {
const { socket, isConnected } = useWebsocketStore.getState();
// Subscribe to store changes and sync to C++ client
useInventoryStore.subscribe((state) => {
const { socket, isConnected } = useWebsocketStore.getState();
if (!isConnected || !socket || socket.readyState !== WebSocket.OPEN) return;
if (isConnected && socket) {
socket.send(JSON.stringify({
action: "sync_inventory",
data: newState
}));
}
});
// --- Check toggles ---
const toggles = {
spoofItems: state.spoofItems,
spoofPerks: state.spoofPerks,
spoofCatalog: state.spoofCatalog,
spoofDLCs: state.spoofDLCs
};
const togglesJson = JSON.stringify(toggles);
if (togglesJson !== lastTogglesJson) {
lastTogglesJson = togglesJson;
socket.send(JSON.stringify({ action: 2, toggles }));
}
// --- Check inventory ---
const inventory = {
unlockedCharacters: state.unlockedCharacters,
unlockedCustomizations: state.unlockedCustomizations,
unlockedDLCs: state.unlockedDLCs,
unlockedPerks: state.unlockedPerks,
items: state.items,
offerings: state.offerings,
addons: state.addons
};
const inventoryJson = JSON.stringify(inventory);
if (inventoryJson !== lastInventoryJson) {
lastInventoryJson = inventoryJson;
mapStoreToSpooferConfig(state).then((profile) => {
// Re-check connection in case it dropped during async mapping
const ws = useWebsocketStore.getState();
if (
ws.isConnected &&
ws.socket &&
ws.socket.readyState === WebSocket.OPEN
) {
ws.socket.send(JSON.stringify({ action: 1, profile }));
}
});
}
});
+156 -132
View File
@@ -1,165 +1,189 @@
import { fetchDLCs, fetchItems, fetchOfferings, fetchAddons, fetchPerks } from '../lib/db';
import {
fetchDLCs,
fetchItems,
fetchOfferings,
fetchAddons,
fetchPerks
} from '../lib/db';
import { DLC } from '../lib/utils';
export interface SpooferConfig {
camperItems: Record<string, number>;
camperAddons: Record<string, number>;
slasherAddons: Record<string, number>;
camperOfferings: Record<string, number>;
slasherOfferings: Record<string, number>;
globalOfferings: Record<string, number>;
camperPerks: string[];
slasherPerks: string[];
catalogItemIds: string[];
dlcListGRDK: string[];
dlcListEGS: string[];
dlcListSteam: string[];
camperItems: Record<string, number>;
camperAddons: Record<string, number>;
slasherAddons: Record<string, number>;
camperOfferings: Record<string, number>;
slasherOfferings: Record<string, number>;
globalOfferings: Record<string, number>;
camperPerks: string[];
slasherPerks: string[];
catalogItemIds: string[];
dlcListGRDK: string[];
dlcListEGS: string[];
dlcListSteam: string[];
}
export interface Toggles {
spoofItems: boolean;
spoofPerks: boolean;
spoofCatalog: boolean;
spoofDLCs: boolean;
spoofItems: boolean;
spoofPerks: boolean;
spoofCatalog: boolean;
spoofDLCs: boolean;
}
export async function mapStoreToSpooferConfig(state: {
unlockedCharacters: string[];
unlockedCustomizations: string[];
unlockedDLCs: string[];
unlockedPerks: string[];
items: Record<string, number>;
offerings: Record<string, number>;
addons: Record<string, number>;
unlockedCharacters: string[];
unlockedCustomizations: string[];
unlockedDLCs: string[];
unlockedPerks: string[];
items: Record<string, number>;
offerings: Record<string, number>;
addons: Record<string, number>;
}): Promise<SpooferConfig> {
const [dlcs, allItems, allOfferings, allAddons, allPerks] = await Promise.all([
fetchDLCs(),
fetchItems(),
fetchOfferings(),
fetchAddons(),
fetchPerks()
]);
const [dlcs, allItems, allOfferings, allAddons, allPerks] = await Promise.all(
[fetchDLCs(), fetchItems(), fetchOfferings(), fetchAddons(), fetchPerks()]
);
const dlcMap = new Map<string, DLC>();
dlcs.forEach((d: DLC) => dlcMap.set(d.id, d));
const dlcMap = new Map<string, DLC>();
dlcs.forEach((d: DLC) => dlcMap.set(d.id, d));
const itemIdSet = new Set<string>();
allItems.forEach((i: { id: string }) => itemIdSet.add(i.id));
const itemIdSet = new Set<string>();
allItems.forEach((i: { id: string }) => itemIdSet.add(i.id));
const offeringMap = new Map<string, { role: number }>();
allOfferings.forEach((o: { id: string; role: number }) => offeringMap.set(o.id, o));
const offeringMap = new Map<string, { role: number }>();
allOfferings.forEach((o: { id: string; role: number }) =>
offeringMap.set(o.id, o)
);
const addonMap = new Map<string, { role: number }>();
allAddons.forEach((a: { id: string; role: number }) => addonMap.set(a.id, a));
const addonMap = new Map<string, { role: number }>();
allAddons.forEach((a: { id: string; role: number }) => addonMap.set(a.id, a));
const perkMap = new Map<string, { role: number }>();
allPerks.forEach((p: { id: string; role: number }) => perkMap.set(p.id, p));
const perkMap = new Map<string, { role: number }>();
allPerks.forEach((p: { id: string; role: number }) => perkMap.set(p.id, p));
const dlcListSteam: string[] = [];
const dlcListEGS: string[] = [];
const dlcListGRDK: string[] = [];
// --- DLCs ---
const dlcListSteam: string[] = [];
const dlcListEGS: string[] = [];
const dlcListGRDK: string[] = [];
for (const id of state.unlockedDLCs) {
const dlc = dlcMap.get(id);
if (!dlc?.dlcIds) continue;
if (dlc.dlcIds.steam && dlc.dlcIds.steam !== '0' && dlc.dlcIds.steam !== '-1')
dlcListSteam.push(dlc.dlcIds.steam);
if (dlc.dlcIds.epic && dlc.dlcIds.epic !== 'FFFFFFFFFFFFFFFF' && dlc.dlcIds.epic !== '0')
dlcListEGS.push(dlc.dlcIds.epic);
if (dlc.dlcIds.grdk && dlc.dlcIds.grdk !== '9ZZZZZZZZZZZ' && dlc.dlcIds.grdk !== '0')
dlcListGRDK.push(dlc.dlcIds.grdk);
}
for (const id of state.unlockedDLCs) {
const dlc = dlcMap.get(id);
if (!dlc?.dlcIds) continue;
if (
dlc.dlcIds.steam &&
dlc.dlcIds.steam !== '0' &&
dlc.dlcIds.steam !== '-1'
)
dlcListSteam.push(dlc.dlcIds.steam);
if (
dlc.dlcIds.epic &&
dlc.dlcIds.epic !== 'FFFFFFFFFFFFFFFF' &&
dlc.dlcIds.epic !== '0'
)
dlcListEGS.push(dlc.dlcIds.epic);
if (
dlc.dlcIds.grdk &&
dlc.dlcIds.grdk !== '9ZZZZZZZZZZZ' &&
dlc.dlcIds.grdk !== '0'
)
dlcListGRDK.push(dlc.dlcIds.grdk);
}
const camperItems: Record<string, number> = {};
for (const [id, qty] of Object.entries(state.items))
if (qty > 0 && itemIdSet.has(id)) camperItems[id] = qty;
// --- Items ---
const camperItems: Record<string, number> = {};
for (const [id, qty] of Object.entries(state.items)) {
if (qty > 0 && itemIdSet.has(id)) camperItems[id] = qty;
}
// --- Offerings ---
const camperOfferings: Record<string, number> = {};
const slasherOfferings: Record<string, number> = {};
const globalOfferings: Record<string, number> = {};
const camperOfferings: Record<string, number> = {};
const slasherOfferings: Record<string, number> = {};
const globalOfferings: Record<string, number> = {};
for (const [id, qty] of Object.entries(state.offerings)) {
if (qty <= 0) continue;
const offering = offeringMap.get(id);
if (!offering) continue;
if (offering.role === 2) camperOfferings[id] = qty;
else if (offering.role === 1) slasherOfferings[id] = qty;
else globalOfferings[id] = qty;
}
for (const [id, qty] of Object.entries(state.offerings)) {
if (qty <= 0) continue;
const offering = offeringMap.get(id);
if (!offering) continue;
if (offering.role === 2) camperOfferings[id] = qty;
else if (offering.role === 1) slasherOfferings[id] = qty;
else globalOfferings[id] = qty;
}
// --- Addons ---
const camperAddons: Record<string, number> = {};
const slasherAddons: Record<string, number> = {};
const camperAddons: Record<string, number> = {};
const slasherAddons: Record<string, number> = {};
for (const [id, qty] of Object.entries(state.addons)) {
if (qty <= 0) continue;
const addon = addonMap.get(id);
if (!addon) continue;
if (addon.role === 1) slasherAddons[id] = qty;
else camperAddons[id] = qty;
}
for (const [id, qty] of Object.entries(state.addons)) {
if (qty <= 0) continue;
const addon = addonMap.get(id);
if (!addon) continue;
if (addon.role === 1) slasherAddons[id] = qty;
else camperAddons[id] = qty;
}
// --- Perks ---
const camperPerks: string[] = [];
const slasherPerks: string[] = [];
const camperPerks: string[] = [];
const slasherPerks: string[] = [];
for (const id of state.unlockedPerks) {
const perk = perkMap.get(id);
if (!perk) continue;
if (perk.role === 1) slasherPerks.push(id);
else camperPerks.push(id);
}
for (const id of state.unlockedPerks) {
const perk = perkMap.get(id);
if (!perk) continue;
if (perk.role === 1) slasherPerks.push(id);
else camperPerks.push(id);
}
return {
camperItems,
camperAddons,
slasherAddons,
camperOfferings,
slasherOfferings,
globalOfferings,
camperPerks,
slasherPerks,
catalogItemIds: [...state.unlockedCustomizations],
dlcListSteam,
dlcListEGS,
dlcListGRDK,
};
return {
camperItems,
camperAddons,
slasherAddons,
camperOfferings,
slasherOfferings,
globalOfferings,
camperPerks,
slasherPerks,
catalogItemIds: [...state.unlockedCustomizations],
dlcListSteam,
dlcListEGS,
dlcListGRDK
};
}
export async function mapSpooferConfigToStore(profile: SpooferConfig) {
const dlcs = await fetchDLCs();
const dlcs = await fetchDLCs();
const unlockedDLCs: string[] = [];
for (const dlc of dlcs as DLC[]) {
if (!dlc.dlcIds) continue;
const hasSteam = dlc.dlcIds.steam && profile.dlcListSteam?.includes(dlc.dlcIds.steam);
const hasEpic = dlc.dlcIds.epic && profile.dlcListEGS?.includes(dlc.dlcIds.epic);
const hasGrdk = dlc.dlcIds.grdk && profile.dlcListGRDK?.includes(dlc.dlcIds.grdk);
if (hasSteam || hasEpic || hasGrdk) unlockedDLCs.push(dlc.id);
}
const unlockedDLCs: string[] = [];
for (const dlc of dlcs as DLC[]) {
if (!dlc.dlcIds) continue;
const hasSteam =
dlc.dlcIds.steam && profile.dlcListSteam?.includes(dlc.dlcIds.steam);
const hasEpic =
dlc.dlcIds.epic && profile.dlcListEGS?.includes(dlc.dlcIds.epic);
const hasGrdk =
dlc.dlcIds.grdk && profile.dlcListGRDK?.includes(dlc.dlcIds.grdk);
if (hasSteam || hasEpic || hasGrdk) unlockedDLCs.push(dlc.id);
}
const offerings: Record<string, number> = {
...(profile.globalOfferings || {}),
...(profile.camperOfferings || {}),
...(profile.slasherOfferings || {}),
};
const offerings: Record<string, number> = {
...(profile.globalOfferings || {}),
...(profile.camperOfferings || {}),
...(profile.slasherOfferings || {})
};
const addons: Record<string, number> = {
...(profile.camperAddons || {}),
...(profile.slasherAddons || {}),
};
const addons: Record<string, number> = {
...(profile.camperAddons || {}),
...(profile.slasherAddons || {})
};
const unlockedPerks: string[] = [
...(profile.camperPerks || []),
...(profile.slasherPerks || []),
];
const unlockedPerks: string[] = [
...(profile.camperPerks || []),
...(profile.slasherPerks || [])
];
return {
unlockedCharacters: [] as string[],
unlockedCustomizations: profile.catalogItemIds || [],
unlockedDLCs,
unlockedPerks,
items: profile.camperItems || {},
offerings,
addons,
};
}
return {
unlockedCharacters: [] as string[],
unlockedCustomizations: profile.catalogItemIds || [],
unlockedDLCs,
unlockedPerks,
items: profile.camperItems || {},
offerings,
addons
};
}