@evitcastudio/kit 2.1.2 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +123 -59
- package/lib/bundle/cli/cli.js +1398 -53
- package/lib/bundle/cli/kit-game-templates/multi/README.md +5 -0
- package/lib/bundle/cli/kit-game-templates/multi/bun-build.ts +109 -0
- package/lib/bundle/cli/kit-game-templates/multi/favicon.ico +0 -0
- package/lib/bundle/cli/kit-game-templates/multi/package.json +24 -0
- package/lib/bundle/cli/kit-game-templates/multi/src/client/c-network.ts +22 -0
- package/lib/bundle/cli/kit-game-templates/multi/src/client/index.html +9 -0
- package/lib/bundle/cli/kit-game-templates/multi/src/client/index.ts +45 -0
- package/lib/bundle/cli/kit-game-templates/multi/src/client/packets/s-packets.ts +5 -0
- package/lib/bundle/cli/kit-game-templates/multi/src/client/vendor/vylocity-game-engine/vylo.client.js +19 -0
- package/lib/bundle/cli/kit-game-templates/multi/src/map-types.ts +9 -0
- package/lib/bundle/cli/kit-game-templates/multi/src/resources/default-atlas.vyi +0 -0
- package/lib/bundle/cli/kit-game-templates/multi/src/resources/default-macro.vymac +27 -0
- package/lib/bundle/cli/kit-game-templates/multi/src/resources/main-map.vym +1 -0
- package/lib/bundle/cli/kit-game-templates/multi/src/server/index.ts +58 -0
- package/lib/bundle/cli/kit-game-templates/multi/src/server/packets/c-packets.ts +5 -0
- package/lib/bundle/cli/kit-game-templates/multi/src/server/s-network.ts +16 -0
- package/lib/bundle/cli/kit-game-templates/multi/src/server/settings.json +4 -0
- package/lib/bundle/cli/kit-game-templates/multi/src/server/vendor/vylocity-game-engine/vylo.server.js +1 -0
- package/lib/bundle/cli/kit-game-templates/multi/src/types/shared-types.ts +13 -0
- package/lib/bundle/cli/kit-game-templates/multi/src/vylo.d.ts +3850 -0
- package/lib/bundle/cli/kit-game-templates/multi/tsconfig.json +28 -0
- package/lib/bundle/cli/kit-game-templates/single/README.md +5 -0
- package/lib/bundle/cli/kit-game-templates/single/bun-build.ts +33 -0
- package/lib/bundle/cli/kit-game-templates/single/bun-serve.ts +28 -0
- package/lib/bundle/cli/kit-game-templates/single/favicon.ico +0 -0
- package/lib/bundle/cli/kit-game-templates/single/package.json +23 -0
- package/lib/bundle/cli/kit-game-templates/single/src/index.html +12 -0
- package/lib/bundle/cli/kit-game-templates/single/src/index.ts +37 -0
- package/lib/bundle/cli/kit-game-templates/single/src/map-types.ts +9 -0
- package/lib/bundle/cli/kit-game-templates/single/src/resources/default-atlas.vyi +0 -0
- package/lib/bundle/cli/kit-game-templates/single/src/resources/default-macro.vymac +27 -0
- package/lib/bundle/cli/kit-game-templates/single/src/resources/main-map.vym +1 -0
- package/lib/bundle/cli/kit-game-templates/single/src/style.css +0 -0
- package/lib/bundle/cli/kit-game-templates/single/src/types/vylo.d.ts +3850 -0
- package/lib/bundle/cli/kit-game-templates/single/src/vendor/vylocity-game-engine/vylo.client.js +19 -0
- package/lib/bundle/cli/kit-game-templates/single/tsconfig.json +28 -0
- package/lib/cli/init.d.ts +15 -0
- package/lib/cli/init.d.ts.map +1 -0
- package/lib/cli/init.js +190 -0
- package/lib/cli/main.d.ts +13 -0
- package/lib/cli/main.d.ts.map +1 -0
- package/lib/cli/main.js +16 -0
- package/lib/cli/resource-builder.d.ts +6 -0
- package/lib/cli/resource-builder.d.ts.map +1 -0
- package/lib/cli/resource-builder.js +191 -0
- package/lib/cli/types.d.ts +11 -0
- package/lib/cli/types.d.ts.map +1 -0
- package/lib/cli/types.js +1 -0
- package/lib/index.d.ts +2 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/plugins/network/index.d.ts +7 -0
- package/lib/plugins/network/index.d.ts.map +1 -1
- package/lib/plugins/network/index.js +18 -5
- package/lib/types/vylo.d.ts +3848 -3848
- package/package.json +13 -5
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
// Enable latest features
|
|
4
|
+
"lib": ["ESNext", "DOM"],
|
|
5
|
+
"target": "ESNext",
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"baseUrl": "./",
|
|
8
|
+
"moduleDetection": "force",
|
|
9
|
+
"allowJs": true,
|
|
10
|
+
"resolveJsonModule": true,
|
|
11
|
+
|
|
12
|
+
// Bundler mode
|
|
13
|
+
"moduleResolution": "bundler",
|
|
14
|
+
"allowImportingTsExtensions": true,
|
|
15
|
+
"verbatimModuleSyntax": true,
|
|
16
|
+
"noEmit": true,
|
|
17
|
+
|
|
18
|
+
// Best practices
|
|
19
|
+
"strict": true,
|
|
20
|
+
"skipLibCheck": true,
|
|
21
|
+
"noFallthroughCasesInSwitch": true,
|
|
22
|
+
|
|
23
|
+
// Some stricter flags (disabled by default)
|
|
24
|
+
"noUnusedLocals": false,
|
|
25
|
+
"noUnusedParameters": false,
|
|
26
|
+
"noPropertyAccessFromIndexSignature": false
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for the init command.
|
|
3
|
+
*/
|
|
4
|
+
export interface InitOptions {
|
|
5
|
+
projectName?: string;
|
|
6
|
+
single?: boolean;
|
|
7
|
+
multi?: boolean;
|
|
8
|
+
verbose?: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Process the initialization of a new project.
|
|
12
|
+
* @param pOptions - Options for initialization.
|
|
13
|
+
*/
|
|
14
|
+
export declare function processInit(pOptions: InitOptions): Promise<void>;
|
|
15
|
+
//# sourceMappingURL=init.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AAQA;;GAEG;AACH,MAAM,WAAW,WAAW;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAgED;;;GAGG;AACH,wBAAsB,WAAW,CAAC,QAAQ,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAoItE"}
|
package/lib/cli/init.js
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { intro, outro, text, select, confirm, spinner, note, isCancel, cancel } from '@clack/prompts';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { spawnSync } from 'node:child_process';
|
|
7
|
+
import packageJSON from '../../package.json';
|
|
8
|
+
/**
|
|
9
|
+
* Gets the git user name and email from the local system.
|
|
10
|
+
* @returns The formatted author string.
|
|
11
|
+
*/
|
|
12
|
+
function getGitUser() {
|
|
13
|
+
try {
|
|
14
|
+
const name = spawnSync('git', ['config', '--get', 'user.name'], { encoding: 'utf8' }).stdout.trim();
|
|
15
|
+
const email = spawnSync('git', ['config', '--get', 'user.email'], { encoding: 'utf8' }).stdout.trim();
|
|
16
|
+
if (name && email) {
|
|
17
|
+
return `${name} <${email}>`;
|
|
18
|
+
}
|
|
19
|
+
return name || 'Author';
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return 'Author';
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Recursively copy template files and replace placeholders.
|
|
27
|
+
* @param pSrc - Source template directory.
|
|
28
|
+
* @param pDest - Destination project directory.
|
|
29
|
+
* @param pProjectName - Project name for placeholder replacement.
|
|
30
|
+
* @param pVersion - Version number for placeholder replacement.
|
|
31
|
+
* @param pAuthor - Author for placeholder replacement.
|
|
32
|
+
*/
|
|
33
|
+
function copyTemplate(pSrc, pDest, pProjectName, pVersion, pAuthor) {
|
|
34
|
+
if (!fs.existsSync(pDest)) {
|
|
35
|
+
fs.mkdirSync(pDest, { recursive: true });
|
|
36
|
+
}
|
|
37
|
+
const files = fs.readdirSync(pSrc);
|
|
38
|
+
for (const file of files) {
|
|
39
|
+
const srcPath = path.join(pSrc, file);
|
|
40
|
+
const destPath = path.join(pDest, file);
|
|
41
|
+
const stats = fs.statSync(srcPath);
|
|
42
|
+
if (stats.isDirectory()) {
|
|
43
|
+
if (file === '.git')
|
|
44
|
+
continue; // Do not copy .git directories
|
|
45
|
+
copyTemplate(srcPath, destPath, pProjectName, pVersion, pAuthor);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
const ext = path.extname(file).toLowerCase();
|
|
49
|
+
const textExtensions = ['.ts', '.js', '.json', '.html', '.css', '.md', '.txt'];
|
|
50
|
+
if (textExtensions.includes(ext) || file === '.gitignore' || file.startsWith('.')) {
|
|
51
|
+
let content = fs.readFileSync(srcPath, 'utf8');
|
|
52
|
+
// Replace placeholders
|
|
53
|
+
content = content.replace(/{{PROJECT_NAME}}/g, pProjectName);
|
|
54
|
+
content = content.replace(/{{VERSION}}/g, pVersion);
|
|
55
|
+
content = content.replace(/{{PROJECT_AUTHOR}}/g, pAuthor);
|
|
56
|
+
fs.writeFileSync(destPath, content);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
// Binary-safe copy for other files (like .vyi, images, etc.)
|
|
60
|
+
fs.copyFileSync(srcPath, destPath);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Process the initialization of a new project.
|
|
67
|
+
* @param pOptions - Options for initialization.
|
|
68
|
+
*/
|
|
69
|
+
export async function processInit(pOptions) {
|
|
70
|
+
intro(chalk.cyan(`Kit CLI v${packageJSON.version}`));
|
|
71
|
+
let projectName = pOptions.projectName;
|
|
72
|
+
let gameType = 'single';
|
|
73
|
+
// Interactive Walkthrough
|
|
74
|
+
if (!pOptions.single && !pOptions.multi && !projectName) {
|
|
75
|
+
const name = await text({
|
|
76
|
+
message: 'What is the name of your project?',
|
|
77
|
+
placeholder: 'my-amazing-project',
|
|
78
|
+
validate(pValue) {
|
|
79
|
+
if (!pValue || pValue.length === 0)
|
|
80
|
+
return 'Project name is required';
|
|
81
|
+
if (!/^[a-z0-9-_]+$/i.test(pValue))
|
|
82
|
+
return 'Project name must be alphanumeric with dashes or underscores';
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
if (isCancel(name)) {
|
|
86
|
+
cancel('Operation cancelled.');
|
|
87
|
+
process.exit(0);
|
|
88
|
+
}
|
|
89
|
+
projectName = name;
|
|
90
|
+
const type = await select({
|
|
91
|
+
message: 'What type of game are you building?',
|
|
92
|
+
options: [
|
|
93
|
+
{ value: 'single', label: 'Single Player', hint: 'Legacy of Goku, Chrono Trigger, Final Fantasy, etc.' },
|
|
94
|
+
{ value: 'multi', label: 'Multiplayer', hint: 'APEX Legends, DBZ Squadra, Valorant, etc.' },
|
|
95
|
+
{ value: 'both', label: 'Single & Multiplayer', hint: 'Minecraft, Terraria, etc.' },
|
|
96
|
+
],
|
|
97
|
+
});
|
|
98
|
+
if (isCancel(type)) {
|
|
99
|
+
cancel('Operation cancelled.');
|
|
100
|
+
process.exit(0);
|
|
101
|
+
}
|
|
102
|
+
gameType = type;
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
// Handle flags
|
|
106
|
+
if (pOptions.single)
|
|
107
|
+
gameType = 'single';
|
|
108
|
+
if (pOptions.multi)
|
|
109
|
+
gameType = 'multi';
|
|
110
|
+
if (pOptions.single && pOptions.multi)
|
|
111
|
+
gameType = 'both';
|
|
112
|
+
if (!projectName)
|
|
113
|
+
projectName = 'kit-project';
|
|
114
|
+
}
|
|
115
|
+
const projectDir = path.join(process.cwd(), projectName);
|
|
116
|
+
if (fs.existsSync(projectDir)) {
|
|
117
|
+
const overwrite = await confirm({
|
|
118
|
+
message: `Directory ${chalk.cyan(projectName)} already exists. Overwrite?`,
|
|
119
|
+
initialValue: false,
|
|
120
|
+
});
|
|
121
|
+
if (isCancel(overwrite) || !overwrite) {
|
|
122
|
+
cancel('Installation aborted.');
|
|
123
|
+
process.exit(0);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const s = spinner();
|
|
127
|
+
s.start(`Scaffolding ${chalk.cyan(projectName)}...`);
|
|
128
|
+
try {
|
|
129
|
+
const projectPath = path.join(process.cwd(), projectName);
|
|
130
|
+
if (fs.existsSync(projectPath)) {
|
|
131
|
+
// This case should ideally be handled by the confirm prompt above,
|
|
132
|
+
// but good to have a fallback for non-interactive mode or race conditions.
|
|
133
|
+
fs.rmSync(projectPath, { recursive: true, force: true });
|
|
134
|
+
}
|
|
135
|
+
fs.mkdirSync(projectPath, { recursive: true });
|
|
136
|
+
// Determine the template type based on gameType
|
|
137
|
+
let templateType = gameType;
|
|
138
|
+
if (gameType === 'both')
|
|
139
|
+
templateType = 'multi'; // Use multi for both for now
|
|
140
|
+
// Resolve template path
|
|
141
|
+
// When running from lib/bundle/cli/cli.js, templates are in ./kit-game-templates/
|
|
142
|
+
const templatesDir = path.join(path.dirname(fileURLToPath(import.meta.url)), 'kit-game-templates', templateType);
|
|
143
|
+
const author = getGitUser();
|
|
144
|
+
if (!fs.existsSync(templatesDir)) {
|
|
145
|
+
// Fallback for local development (src/cli/init.ts)
|
|
146
|
+
// Go up to root then templates/pType
|
|
147
|
+
const localTemplatesDir = path.join(process.cwd(), 'kit-game-templates', templateType);
|
|
148
|
+
if (!fs.existsSync(localTemplatesDir)) {
|
|
149
|
+
console.error(chalk.red(`Error: Templates not found at ${templatesDir} or ${localTemplatesDir}`));
|
|
150
|
+
process.exit(1);
|
|
151
|
+
}
|
|
152
|
+
copyTemplate(localTemplatesDir, projectPath, projectName, packageJSON.version, author);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
copyTemplate(templatesDir, projectPath, projectName, packageJSON.version, author);
|
|
156
|
+
}
|
|
157
|
+
// Initialize git and create initial commit
|
|
158
|
+
try {
|
|
159
|
+
spawnSync('git', ['init'], { cwd: projectPath });
|
|
160
|
+
spawnSync('git', ['add', '.'], { cwd: projectPath });
|
|
161
|
+
spawnSync('git', ['commit', '-m', 'Initial commit from Kit CLI'], {
|
|
162
|
+
cwd: projectPath,
|
|
163
|
+
env: { ...process.env, GIT_AUTHOR_NAME: author.split(' <')[0], GIT_AUTHOR_EMAIL: author.split('<')[1]?.slice(0, -1) || '' }
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
// Silently fail if git is not installed or config is missing
|
|
168
|
+
}
|
|
169
|
+
s.stop(`Project ${chalk.green(projectName)} created!`);
|
|
170
|
+
console.log(`${chalk.cyan('│')}`);
|
|
171
|
+
console.log(`${chalk.cyan('│')} ${chalk.white.bold('Next steps:')}`);
|
|
172
|
+
console.log(`${chalk.cyan('│')} ${chalk.dim('1.')} cd ${chalk.cyan(projectName)}`);
|
|
173
|
+
console.log(`${chalk.cyan('│')} ${chalk.dim('2.')} bun install`);
|
|
174
|
+
console.log(`${chalk.cyan('│')} ${chalk.dim('3.')} bun run build`);
|
|
175
|
+
console.log(`${chalk.cyan('│')}`);
|
|
176
|
+
outro(chalk.green.bold('Happy coding!'));
|
|
177
|
+
}
|
|
178
|
+
catch (pError) {
|
|
179
|
+
s.stop(chalk.red('Scaffolding failed.'));
|
|
180
|
+
// Cleanup partially created directory
|
|
181
|
+
if (projectName) {
|
|
182
|
+
const projectPath = path.join(process.cwd(), projectName);
|
|
183
|
+
if (fs.existsSync(projectPath)) {
|
|
184
|
+
fs.rmSync(projectPath, { recursive: true, force: true });
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
console.error(pError);
|
|
188
|
+
process.exit(1);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ProcessOptions } from './types';
|
|
2
|
+
import { type InitOptions } from './init';
|
|
3
|
+
export declare class KitCLI {
|
|
4
|
+
/**
|
|
5
|
+
* Start resource builder.
|
|
6
|
+
*/
|
|
7
|
+
static processResources(pProcessOptions: ProcessOptions): Promise<void>;
|
|
8
|
+
/**
|
|
9
|
+
* Start project initialization.
|
|
10
|
+
*/
|
|
11
|
+
static init(pInitOptions: InitOptions): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=main.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,QAAQ,CAAC;AAEvD,qBAAa,MAAM;IACf;;OAEG;WACU,gBAAgB,CAAC,eAAe,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7E;;OAEG;WACU,IAAI,CAAC,YAAY,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CAG9D"}
|
package/lib/cli/main.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { processResources } from './resource-builder';
|
|
2
|
+
import { processInit } from './init';
|
|
3
|
+
export class KitCLI {
|
|
4
|
+
/**
|
|
5
|
+
* Start resource builder.
|
|
6
|
+
*/
|
|
7
|
+
static async processResources(pProcessOptions) {
|
|
8
|
+
await processResources(pProcessOptions);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Start project initialization.
|
|
12
|
+
*/
|
|
13
|
+
static async init(pInitOptions) {
|
|
14
|
+
await processInit(pInitOptions);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ProcessOptions } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Main entry point for building resources.
|
|
4
|
+
*/
|
|
5
|
+
export declare function processResources({ inDirectory, outDirectory, verbose, ignoreSound }: ProcessOptions): Promise<void>;
|
|
6
|
+
//# sourceMappingURL=resource-builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource-builder.d.ts","sourceRoot":"","sources":["../../src/cli/resource-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AA+K9C;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,EAAE,WAAW,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBzH"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { promises as fs } from 'fs';
|
|
2
|
+
import { join, extname, basename } from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
5
|
+
// Logging helpers
|
|
6
|
+
const log = console.log;
|
|
7
|
+
const info = chalk.hex('#ffa552');
|
|
8
|
+
const error = chalk.hex('#c42847');
|
|
9
|
+
const alert = chalk.hex('#EFF2C0');
|
|
10
|
+
// Resource types and valid file extensions
|
|
11
|
+
const RESOURCE_TYPES = ['interface', 'icon', 'map', 'sound', 'macros'];
|
|
12
|
+
const VALID_EXTENSIONS = ['vyint', 'vyi', 'vym', 'vymac', 'mp3', 'aac', 'wav', 'm4a', 'ogg', 'flac'];
|
|
13
|
+
// State variables
|
|
14
|
+
let resourceJSON = initializeResourceJSON();
|
|
15
|
+
let isVerbose = false;
|
|
16
|
+
let ignoringSound = false;
|
|
17
|
+
let resourceInDirectory = '';
|
|
18
|
+
let resourceOutDirectory = '';
|
|
19
|
+
const resourcesToProcess = [];
|
|
20
|
+
/**
|
|
21
|
+
* Initializes the resource JSON structure.
|
|
22
|
+
*/
|
|
23
|
+
function initializeResourceJSON() {
|
|
24
|
+
return RESOURCE_TYPES.reduce((acc, type) => {
|
|
25
|
+
acc[type] = [];
|
|
26
|
+
return acc;
|
|
27
|
+
}, {});
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Processes a single file and updates the resource JSON.
|
|
31
|
+
*/
|
|
32
|
+
function prepareFileForProcessing(pFilePath) {
|
|
33
|
+
const extension = extname(pFilePath).slice(1);
|
|
34
|
+
const fileName = basename(pFilePath);
|
|
35
|
+
const resourceIdentifier = `${uuidv4()}.vyr`;
|
|
36
|
+
const type = getResourceType(extension);
|
|
37
|
+
if (!type)
|
|
38
|
+
return;
|
|
39
|
+
if (type === 'sound' && ignoringSound) {
|
|
40
|
+
logVerbose(`[Ignored File] ${pFilePath} (ignoreSound flag enabled)`);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
resourcesToProcess.push({ filePath: pFilePath, type });
|
|
44
|
+
resourceJSON[type].push({ resourceIdentifier, fileName });
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Determines the resource type based on the file extension.
|
|
48
|
+
*/
|
|
49
|
+
function getResourceType(pExtension) {
|
|
50
|
+
switch (pExtension) {
|
|
51
|
+
case 'vyint': return 'interface';
|
|
52
|
+
case 'vyi': return 'icon';
|
|
53
|
+
case 'vym': return 'map';
|
|
54
|
+
case 'vymac': return 'macros';
|
|
55
|
+
case 'mp3':
|
|
56
|
+
case 'aac':
|
|
57
|
+
case 'wav':
|
|
58
|
+
case 'm4a':
|
|
59
|
+
case 'ogg':
|
|
60
|
+
case 'flac': return 'sound';
|
|
61
|
+
default: return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Processes a directory and its contents recursively.
|
|
66
|
+
*/
|
|
67
|
+
async function processDirectory(pDirectoryPath) {
|
|
68
|
+
try {
|
|
69
|
+
const contents = await fs.readdir(pDirectoryPath);
|
|
70
|
+
for (const item of contents) {
|
|
71
|
+
const itemPath = join(pDirectoryPath, item);
|
|
72
|
+
const stats = await fs.stat(itemPath);
|
|
73
|
+
if (stats.isDirectory()) {
|
|
74
|
+
await processDirectory(itemPath);
|
|
75
|
+
}
|
|
76
|
+
else if (isValidExtension(extname(itemPath).slice(1))) {
|
|
77
|
+
prepareFileForProcessing(itemPath);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch (pError) {
|
|
82
|
+
logError(`[Error] Processing directory: ${pError}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Checks if a file extension is valid.
|
|
87
|
+
*/
|
|
88
|
+
function isValidExtension(pExtension) {
|
|
89
|
+
return VALID_EXTENSIONS.includes(pExtension);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Executes all file copy operations in parallel after preparation.
|
|
93
|
+
*/
|
|
94
|
+
async function processAllFiles() {
|
|
95
|
+
try {
|
|
96
|
+
await clearResourceTypeDirectories(`${resourceOutDirectory}/resources`);
|
|
97
|
+
// Create copy operations for all files
|
|
98
|
+
const copyOperations = resourcesToProcess.map(({ filePath, type }) => {
|
|
99
|
+
const fileName = basename(filePath);
|
|
100
|
+
const resource = resourceJSON[type].find(res => res.fileName === fileName);
|
|
101
|
+
if (!resource) {
|
|
102
|
+
throw new Error(`Resource not found for file: ${fileName}`);
|
|
103
|
+
}
|
|
104
|
+
const destination = join(resourceOutDirectory, 'resources');
|
|
105
|
+
const resourceName = resource.resourceIdentifier;
|
|
106
|
+
return copyFile(filePath, destination, resourceName);
|
|
107
|
+
});
|
|
108
|
+
// Execute all copy operations concurrently
|
|
109
|
+
await Promise.all(copyOperations);
|
|
110
|
+
logVerbose(`[Kit CLI] All resources have been processed.`);
|
|
111
|
+
await saveResourceJSON();
|
|
112
|
+
}
|
|
113
|
+
catch (pError) {
|
|
114
|
+
const errorMessage = pError instanceof Error ? pError.message : String(pError);
|
|
115
|
+
logError(`[Error] Processing files in batch: ${errorMessage}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Clears specified directories within a base directory.
|
|
120
|
+
* @param pBaseDirectory - The path to the base directory.
|
|
121
|
+
*/
|
|
122
|
+
async function clearResourceTypeDirectories(pBaseDirectory) {
|
|
123
|
+
try {
|
|
124
|
+
const directoryExists = await fs.stat(pBaseDirectory).then(stat => stat.isDirectory()).catch(() => false);
|
|
125
|
+
if (directoryExists) {
|
|
126
|
+
await fs.rm(pBaseDirectory, { recursive: true });
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
catch (pError) {
|
|
130
|
+
log(`${error(`[Error]`)} clearing resource directory: ${pError}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Copies a file to the specified directory.
|
|
135
|
+
*/
|
|
136
|
+
async function copyFile(pSource, pDestinationDir, pNewName) {
|
|
137
|
+
try {
|
|
138
|
+
await fs.mkdir(pDestinationDir, { recursive: true });
|
|
139
|
+
await fs.copyFile(pSource, join(pDestinationDir, pNewName));
|
|
140
|
+
}
|
|
141
|
+
catch (pError) {
|
|
142
|
+
logError(`[Error] Copying file ${pSource}: ${pError}`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Saves the resource JSON to a file.
|
|
147
|
+
*/
|
|
148
|
+
async function saveResourceJSON() {
|
|
149
|
+
const filePath = 'resource.json';
|
|
150
|
+
try {
|
|
151
|
+
await fs.writeFile(filePath, JSON.stringify(resourceJSON, null, 4));
|
|
152
|
+
}
|
|
153
|
+
catch (pError) {
|
|
154
|
+
logError(`[Error] Saving resource JSON: ${pError}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Main entry point for building resources.
|
|
159
|
+
*/
|
|
160
|
+
export async function processResources({ inDirectory, outDirectory, verbose, ignoreSound }) {
|
|
161
|
+
// Initialize state
|
|
162
|
+
resourceInDirectory = inDirectory;
|
|
163
|
+
resourceOutDirectory = outDirectory;
|
|
164
|
+
isVerbose = verbose;
|
|
165
|
+
ignoringSound = ignoreSound;
|
|
166
|
+
resourceJSON = initializeResourceJSON();
|
|
167
|
+
// Validate inputs
|
|
168
|
+
if (!resourceInDirectory || !resourceOutDirectory) {
|
|
169
|
+
logError('[Error] Input and output directories must be specified');
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
// Process resources
|
|
173
|
+
await processDirectory(resourceInDirectory);
|
|
174
|
+
if (resourcesToProcess.length > 0) {
|
|
175
|
+
await processAllFiles();
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
logAlert('No resources found!');
|
|
179
|
+
await saveResourceJSON();
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function logVerbose(pMessage) {
|
|
183
|
+
if (isVerbose)
|
|
184
|
+
log(info(pMessage));
|
|
185
|
+
}
|
|
186
|
+
function logError(pMessage) {
|
|
187
|
+
log(error(pMessage));
|
|
188
|
+
}
|
|
189
|
+
function logAlert(pMessage) {
|
|
190
|
+
log(alert(pMessage));
|
|
191
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/cli/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,KAAK,cAAc,GAAG;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAA;CACxB,CAAA;AAED,YAAY,EAAE,cAAc,EAAE,CAAC"}
|
package/lib/cli/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/lib/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { Kit } from './kit';
|
|
2
2
|
export { EventEmitter } from './events/event-system';
|
|
3
|
-
export type { EmitterEvent, ResourceData, Listener } from './types/shared-types';
|
|
3
|
+
export type { EmitterEvent, ResourceData, Listener, KitPluginConstructor } from './types/shared-types';
|
|
4
|
+
export type { Client, Diob } from './types/vylo';
|
|
4
5
|
export { KitPlugin } from './plugins/kit-plugin';
|
|
5
6
|
export { Network } from './plugins/network';
|
|
6
7
|
export type { NetworkListener } from './plugins/network';
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACvG,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -25,6 +25,13 @@ export declare class Network extends KitPlugin {
|
|
|
25
25
|
* @param pPacketName - The name of the packet that will be listened to.
|
|
26
26
|
* @param pListener - The listener that will be called when the packet is received.
|
|
27
27
|
*/
|
|
28
|
+
onPacket<T extends unknown[]>(pPacketName: string, pListener: NetworkListener<T>): void;
|
|
29
|
+
/**
|
|
30
|
+
* Register a listener for a packet.
|
|
31
|
+
* @deprecated Use `onPacket` instead.
|
|
32
|
+
* @param pPacketName - The name of the packet that will be listened to.
|
|
33
|
+
* @param pListener - The listener that will be called when the packet is received.
|
|
34
|
+
*/
|
|
28
35
|
on<T extends unknown[]>(pPacketName: string, pListener: NetworkListener<T>): void;
|
|
29
36
|
/**
|
|
30
37
|
* API for receiving data from the server.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/network/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAEpD,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,OAAO,EAAE,GAAG,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;AAEtG,qBAAa,OAAQ,SAAQ,SAAS;IAClC,IAAI,SAAa;IACjB;;OAEG;IACH,OAAO,CAAC,SAAS,CAAkB;IACnC;;OAEG;IACH,OAAO,CAAC,OAAO,CAAkC;IACjD;;OAEG;IACH,OAAO,CAAC,iBAAiB,CAAkC;IAC3D,YAAY,IAAI,IAAI;IAGpB;;OAEG;IACH,OAAO,CAAC,SAAS,CAAiD;IAClE;;;;OAIG;IACH,EAAE,CAAC,CAAC,SAAS,OAAO,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/network/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAEpD,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,OAAO,EAAE,GAAG,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;AAEtG,qBAAa,OAAQ,SAAQ,SAAS;IAClC,IAAI,SAAa;IACjB;;OAEG;IACH,OAAO,CAAC,SAAS,CAAkB;IACnC;;OAEG;IACH,OAAO,CAAC,OAAO,CAAkC;IACjD;;OAEG;IACH,OAAO,CAAC,iBAAiB,CAAkC;IAC3D,YAAY,IAAI,IAAI;IAGpB;;OAEG;IACH,OAAO,CAAC,SAAS,CAAiD;IAClE;;;;OAIG;IACH,QAAQ,CAAC,CAAC,SAAS,OAAO,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,IAAI;IAOvF;;;;;OAKG;IACH,EAAE,CAAC,CAAC,SAAS,OAAO,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,IAAI;IAGjF;;;;;;OAMG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,GAAE,OAAO,EAAO,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAG,IAAI;IA+BzG;;;OAGG;IACH,eAAe,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI;IASlD;;;OAGG;IACH,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;CAOrD"}
|
|
@@ -25,12 +25,21 @@ export class Network extends KitPlugin {
|
|
|
25
25
|
* @param pPacketName - The name of the packet that will be listened to.
|
|
26
26
|
* @param pListener - The listener that will be called when the packet is received.
|
|
27
27
|
*/
|
|
28
|
-
|
|
28
|
+
onPacket(pPacketName, pListener) {
|
|
29
29
|
if (!this.packets.has(pPacketName)) {
|
|
30
30
|
throw new Error(`Packet name '${pPacketName}' is not registered.`);
|
|
31
31
|
}
|
|
32
32
|
this.listeners.set(pPacketName, pListener);
|
|
33
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Register a listener for a packet.
|
|
36
|
+
* @deprecated Use `onPacket` instead.
|
|
37
|
+
* @param pPacketName - The name of the packet that will be listened to.
|
|
38
|
+
* @param pListener - The listener that will be called when the packet is received.
|
|
39
|
+
*/
|
|
40
|
+
on(pPacketName, pListener) {
|
|
41
|
+
this.onPacket(pPacketName, pListener);
|
|
42
|
+
}
|
|
34
43
|
/**
|
|
35
44
|
* API for receiving data from the server.
|
|
36
45
|
* @param pClient - The client involved with this packet.
|
|
@@ -44,19 +53,23 @@ export class Network extends KitPlugin {
|
|
|
44
53
|
if (typeof pPacketName === 'number') {
|
|
45
54
|
const packetName = this.reversedPacketMap.get(pPacketName);
|
|
46
55
|
if (!packetName) {
|
|
47
|
-
|
|
56
|
+
if (pVerbose) {
|
|
57
|
+
console.group(`Kit.${this.name}Plugin.onNetwork`);
|
|
58
|
+
console.warn(`Unknown packet index: ${pPacketName}`);
|
|
59
|
+
console.groupEnd();
|
|
60
|
+
}
|
|
48
61
|
return;
|
|
49
62
|
}
|
|
50
63
|
const listener = this.listeners.get(packetName);
|
|
51
64
|
if (pVerbose) {
|
|
52
65
|
console.group(`Kit.${this.name}Plugin.onNetwork`);
|
|
66
|
+
if (!listener) {
|
|
67
|
+
console.warn(`No listener was registered for this packet: ${packetName}`);
|
|
68
|
+
}
|
|
53
69
|
console.log(`Packet name: ${pPacketName}`);
|
|
54
70
|
console.log(`Resolved packet name: ${packetName}`);
|
|
55
71
|
console.log(`Data:`, pData);
|
|
56
72
|
console.groupEnd();
|
|
57
|
-
if (!listener) {
|
|
58
|
-
console.warn(`No listener registered for packet: ${packetName}`);
|
|
59
|
-
}
|
|
60
73
|
}
|
|
61
74
|
listener?.(pClient, ...pData);
|
|
62
75
|
}
|