refactor: architecture base

- Moved NodeCG context management to a dedicated context module.
- Introduced message handling utilities for better message listening and sending.
- Updated startgg integration to use new message handling methods.
- Removed deprecated replicant utilities and replaced them with a new structure.
- Refactored replicant imports in graphics components to align with new structure.
- Added new pack-related types and schemas for better type safety.
- Cleaned up unused files and consolidated pack configuration into a single module.
- Updated TypeScript configurations to reflect new directory structure.
This commit is contained in:
2026-05-23 21:52:07 +02:00
parent 225b2b36a2
commit 02a108f983
67 changed files with 687 additions and 482 deletions
+25
View File
@@ -0,0 +1,25 @@
export const GITEA_BASE_URL = 'http://10.0.0.10:3002';
export const GITEA_OWNER = 'Pandipipas';
export const GITEA_REPO = 'fighting-game-packs';
export const GITEA_BRANCH = 'main';
export const BUNDLE_NAME = 'scoreko-dev';
export const getGiteaRawUrl = (repoPath: string): string =>
`${GITEA_BASE_URL}/${GITEA_OWNER}/${GITEA_REPO}/raw/branch/${GITEA_BRANCH}/${repoPath}`;
export const REGISTRY_URL = getGiteaRawUrl('registry.json');
export const getManifestUrl = (packId: string): string =>
getGiteaRawUrl(`${packId}/manifest.json`);
export const getPackLogoUrl = (packId: string): string =>
getGiteaRawUrl(`${packId}/logo.png`);
export const getCharacterImageRepoUrl = (packId: string, slug: string, ext: string): string =>
getGiteaRawUrl(`${packId}/characters/${slug}.${ext}`);
export const getInstalledCharacterImageUrl = (
packId: string,
slug: string,
ext = 'png',
): string => `/packs/${packId}/characters/${slug}.${ext}`;
+2
View File
@@ -0,0 +1,2 @@
export * from './config';
export * from './types';
+59
View File
@@ -0,0 +1,59 @@
export interface PackCharacter {
name: string;
slug: string;
dlc?: boolean;
sizeBytes: number;
}
export interface PackPalette {
start: string;
end: string;
}
export interface PackRegistryEntry {
id: string;
name: string;
version: string;
totalSizeBytes: number;
logoPath: string;
characterCount: number;
palette: PackPalette;
bundled: boolean;
}
export interface PackManifest {
id: string;
name: string;
version: string;
palette: PackPalette;
defaultPair?: {
left: string;
right: string;
};
characters: PackCharacter[];
}
export interface PackRegistry {
schemaVersion: number;
updatedAt: string;
packs: PackRegistryEntry[];
}
export interface PackDownloadState {
status: 'idle' | 'fetching-manifest' | 'downloading' | 'done' | 'error';
progress: number;
error?: string;
}
export interface PackUpdateInfo {
installedVersion: string;
latestVersion: string;
}
export interface GameSelectOption {
label: string;
value: string;
available: boolean;
registryEntry: PackRegistryEntry;
updateInfo?: PackUpdateInfo;
}
@@ -41,7 +41,7 @@ const countryByName = new Map(
baseCountries.map((country) => [country.name.toLowerCase(), country.code]),
);
export const resolveCountryCode = (value?: string) => {
export const resolveCountryCode = (value?: string): string => {
if (!value) {
return '';
}
@@ -57,7 +57,7 @@ export const resolveCountryCode = (value?: string) => {
return byName ?? '';
};
export const getCountryLabel = (value?: string, locale = 'en') => {
export const getCountryLabel = (value?: string, locale = 'en'): string => {
if (!value) {
return '';
}
+1 -1
View File
@@ -5,7 +5,7 @@
// ─────────────────────────────────────────────────────────────────────────────
import { ref } from 'vue';
import type { PackManifest } from './pack-types';
import type { PackManifest } from './domain/packs/types';
export interface FightingCharacterOption {
label: string;
-37
View File
@@ -1,37 +0,0 @@
// src/shared/pack-config.ts
// ─────────────────────────────────────────────────────────────────────────────
// Edit ONLY this file to point the pack system at your Gitea instance.
// All other files import their Gitea/NodeCG constants from here.
// ─────────────────────────────────────────────────────────────────────────────
/** Base URL of your Gitea instance — no trailing slash. */
export const GITEA_BASE_URL = 'http://10.0.0.10:3002';
/** Gitea owner (user or organisation) that owns the packs repository. */
export const GITEA_OWNER = 'Pandipipas';
/** Name of the repository that contains all game packs. */
export const GITEA_REPO = 'fighting-game-packs';
/** Branch to pull assets from. */
export const GITEA_BRANCH = 'main';
/**
* NodeCG bundle name.
* Must match the "name" field in your package.json / nodecg config.
*/
export const BUNDLE_NAME = 'scoreko-dev';
// ── Derived URL helpers (do not edit below this line) ────────────────────────
/** Returns the Gitea raw-file URL for any repo-relative path. */
export const getGiteaRawUrl = (repoPath) => `${GITEA_BASE_URL}/${GITEA_OWNER}/${GITEA_REPO}/raw/branch/${GITEA_BRANCH}/${repoPath}`;
/** URL of the master registry file that lists every available pack. */
export const REGISTRY_URL = getGiteaRawUrl('registry.json');
/** Returns the URL for a specific pack's manifest.json. */
export const getManifestUrl = (packId) => getGiteaRawUrl(`${packId}/manifest.json`);
/** Returns the URL for a pack's logo. */
export const getPackLogoUrl = (packId) => getGiteaRawUrl(`${packId}/logo.png`);
/**
* Returns the URL for a specific character image stored in the Gitea repo.
* Used during download; at runtime installed packs are served by NodeCG.
*/
export const getCharacterImageRepoUrl = (packId, slug, ext) => getGiteaRawUrl(`${packId}/characters/${slug}.${ext}`);
/**
* Returns the runtime URL for a character image from an *installed* (downloaded) pack.
* NodeCG serves everything under assets/ at /assets/<bundleName>/.
*/
export const getInstalledCharacterImageUrl = (packId, slug, ext = 'png') => `/assets/${BUNDLE_NAME}/packs/${packId}/characters/${slug}.${ext}`;
-54
View File
@@ -1,54 +0,0 @@
// src/shared/pack-config.ts
// ─────────────────────────────────────────────────────────────────────────────
// Edit ONLY this file to point the pack system at your Gitea instance.
// All other files import their Gitea/NodeCG constants from here.
// ─────────────────────────────────────────────────────────────────────────────
/** Base URL of your Gitea instance — no trailing slash. */
export const GITEA_BASE_URL = 'http://10.0.0.10:3002';
/** Gitea owner (user or organisation) that owns the packs repository. */
export const GITEA_OWNER = 'Pandipipas';
/** Name of the repository that contains all game packs. */
export const GITEA_REPO = 'fighting-game-packs';
/** Branch to pull assets from. */
export const GITEA_BRANCH = 'main';
/**
* NodeCG bundle name.
* Must match the "name" field in your package.json / nodecg config.
*/
export const BUNDLE_NAME = 'scoreko-dev';
// ── Derived URL helpers (do not edit below this line) ────────────────────────
/** Returns the Gitea raw-file URL for any repo-relative path. */
export const getGiteaRawUrl = (repoPath: string): string =>
`${GITEA_BASE_URL}/${GITEA_OWNER}/${GITEA_REPO}/raw/branch/${GITEA_BRANCH}/${repoPath}`;
/** URL of the master registry file that lists every available pack. */
export const REGISTRY_URL = getGiteaRawUrl('registry.json');
/** Returns the URL for a specific pack's manifest.json. */
export const getManifestUrl = (packId: string): string =>
getGiteaRawUrl(`${packId}/manifest.json`);
/** Returns the URL for a pack's logo. */
export const getPackLogoUrl = (packId: string): string =>
getGiteaRawUrl(`${packId}/logo.png`);
/**
* Returns the URL for a specific character image stored in the Gitea repo.
* Used during download; at runtime installed packs are served by NodeCG.
*/
export const getCharacterImageRepoUrl = (packId: string, slug: string, ext: string): string =>
getGiteaRawUrl(`${packId}/characters/${slug}.${ext}`);
/**
* Returns the runtime URL for a character image from an *installed* (downloaded) pack.
* NodeCG serves everything under assets/ at /assets/<bundleName>/.
*/
export const getInstalledCharacterImageUrl = (packId: string, slug: string, ext = 'png'): string =>
`/packs/${packId}/characters/${slug}.${ext}`;
-6
View File
@@ -1,6 +0,0 @@
// src/shared/pack-types.ts
// ─────────────────────────────────────────────────────────────────────────────
// Shared between the NodeCG extension (Node.js) and the dashboard (browser).
// Do NOT import anything that is browser-only or Node-only from this file.
// ─────────────────────────────────────────────────────────────────────────────
export {};
-89
View File
@@ -1,89 +0,0 @@
// src/shared/pack-types.ts
// ─────────────────────────────────────────────────────────────────────────────
// Shared between the NodeCG extension (Node.js) and the dashboard (browser).
// Do NOT import anything that is browser-only or Node-only from this file.
// ─────────────────────────────────────────────────────────────────────────────
/** A single character entry inside a pack manifest. */
export interface PackCharacter {
/** Display name, e.g. "Chun-Li" */
name: string;
/** URL-safe slug that matches the image filename, e.g. "chun-li" */
slug: string;
/** True when the character is paid DLC (shown with the DLC badge in the UI). */
dlc?: boolean;
/** Approximate compressed size of the character image file in bytes. */
sizeBytes: number;
}
/**
* Lightweight entry in the top-level registry.json.
* Enough for the UI to render the game list and the download dialog preview
* without having to fetch the full manifest.
*/
export interface PackRegistryEntry {
/** Unique identifier — must match the folder name in the repo, e.g. "street-fighter-6". */
id: string;
/** Human-readable game title shown in the selector, e.g. "Street Fighter 6". */
name: string;
/** Semantic version of this pack, e.g. "1.0.0". Bump when adding/updating characters. */
version: string;
/** Total download size (sum of all character images + logo) in bytes. */
totalSizeBytes: number;
/** Repo-relative path to the game's logo image, e.g. "street-fighter-6/logo.png". */
logoPath: string;
/** Pre-computed character count so the dialog can show it without loading the manifest. */
characterCount: number;
/** Gradient used for placeholder images when a character has no artwork. */
palette: { start: string; end: string };
/**
* True when the pack ships inside the application bundle (bundled via Vite's
* import.meta.glob). Bundled packs are always "installed" and never show the
* download button, but they still appear in the registry so the app can detect
* updates (version mismatch between bundle and registry).
*/
bundled: boolean;
}
/** Full pack data — lives at <packId>/manifest.json in the repo. */
export interface PackManifest {
/** Must match PackRegistryEntry.id and the folder name. */
id: string;
/** Must match PackRegistryEntry.name. */
name: string;
version: string;
palette: { start: string; end: string };
/** Default characters pre-selected when this game is first chosen. */
defaultPair?: { left: string; right: string };
/** Full character roster, in the order they should appear in the selector. */
characters: PackCharacter[];
}
/** Top-level registry.json structure. */
export interface PackRegistry {
schemaVersion: number;
updatedAt: string;
packs: PackRegistryEntry[];
}
/** Tracks the download lifecycle of a single pack. */
export interface PackDownloadState {
status: 'idle' | 'fetching-manifest' | 'downloading' | 'done' | 'error';
/** Progress percentage 0100. */
progress: number;
error?: string;
}
/** Shape of the option objects surfaced by usePackRegistry.allGameOptions. */
export interface GameSelectOption {
/** Display label for the QSelect. */
label: string;
/** Value stored in the scoreboard (equals PackRegistryEntry.name for installed games). */
value: string;
/** Whether the pack can be used right now (bundled or already downloaded). */
available: boolean;
/** Mirrors PackRegistryEntry so the download dialog can be populated inline. */
registryEntry: PackRegistryEntry;
/** Present when there is a newer version of this pack available in the registry. */
updateInfo?: { installedVersion: string; latestVersion: string };
}