@quakejs/dedicated 1.0.25 → 1.0.26
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/dist/ioq3ded.js +0 -0
- package/package.json +3 -2
- package/server.js +27 -62
package/dist/ioq3ded.js
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quakejs/dedicated",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.26",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"quakejs-dedicated": "server.js"
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"@fails-components/webtransport": "^1.5.1",
|
|
10
10
|
"@fails-components/webtransport-transport-http3-quiche": "^1.5.1",
|
|
11
11
|
"@quakejs/demoq3": "^1.0.4",
|
|
12
|
-
"@quakejs/formats": "^1.0.0"
|
|
12
|
+
"@quakejs/formats": "^1.0.0",
|
|
13
|
+
"glob": "^13.0.0"
|
|
13
14
|
}
|
|
14
15
|
}
|
package/server.js
CHANGED
|
@@ -6,6 +6,7 @@ import util from 'node:util';
|
|
|
6
6
|
|
|
7
7
|
import demoq3 from '@quakejs/demoq3';
|
|
8
8
|
import formats from '@quakejs/formats';
|
|
9
|
+
import { glob } from 'glob';
|
|
9
10
|
|
|
10
11
|
import dedicated from './dist/ioq3ded.js';
|
|
11
12
|
|
|
@@ -54,16 +55,32 @@ try {
|
|
|
54
55
|
/* setup server */
|
|
55
56
|
const ioq3 = await dedicated({
|
|
56
57
|
cert: await fs.readFile(args.values.cert),
|
|
57
|
-
key: await fs.readFile(args.values.key)
|
|
58
|
+
key: await fs.readFile(args.values.key),
|
|
59
|
+
ASAN_OPTIONS: 'help=1:verbosity=3:print_stats=1:symbolize=1:malloc_context_size=20:quarantine_size_mb=8'
|
|
58
60
|
});
|
|
59
61
|
|
|
60
|
-
/*
|
|
61
|
-
const
|
|
62
|
-
const
|
|
63
|
-
|
|
62
|
+
/* synchronize local filesystem */
|
|
63
|
+
const contentBaseUrl = args.values.content;
|
|
64
|
+
const game = path.basename(args.values.game);
|
|
65
|
+
|
|
66
|
+
const localGamePath = path.resolve(args.values.game);
|
|
67
|
+
const localHomePath = path.dirname(localGamePath);
|
|
68
|
+
const localBasePath = path.join(localHomePath, 'baseq3');
|
|
69
|
+
|
|
70
|
+
await demoq3.install(contentBaseUrl, async (pakName) => {
|
|
71
|
+
const pakPath = path.join(localBasePath, pakName);
|
|
72
|
+
return await fs.readFile(pakPath);
|
|
73
|
+
}, async (pakName, data) => {
|
|
74
|
+
const pakPath = path.join(localBasePath, pakName);
|
|
75
|
+
await fs.mkdir(path.dirname(pakPath), { recursive: true });
|
|
76
|
+
await fs.writeFile(pakPath, data);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
/* setup virtual filesystem */
|
|
80
|
+
const virtualHomePath = '/quakejs';
|
|
64
81
|
|
|
65
82
|
try {
|
|
66
|
-
ioq3.FS.mkdirTree(
|
|
83
|
+
ioq3.FS.mkdirTree(virtualHomePath, 0o777);
|
|
67
84
|
} catch (e) {
|
|
68
85
|
if (e.errno !== ioq3.ERRNO_CODES.EEXIST) {
|
|
69
86
|
console.error(e);
|
|
@@ -72,7 +89,7 @@ try {
|
|
|
72
89
|
}
|
|
73
90
|
|
|
74
91
|
try {
|
|
75
|
-
ioq3.FS.mount(ioq3.FS.filesystems.NODEFS, { root:
|
|
92
|
+
ioq3.FS.mount(ioq3.FS.filesystems.NODEFS, { root: localHomePath }, virtualHomePath);
|
|
76
93
|
} catch (e) {
|
|
77
94
|
if (e.errno !== ioq3.ERRNO_CODES.EBUSY) {
|
|
78
95
|
console.error(e);
|
|
@@ -80,65 +97,13 @@ try {
|
|
|
80
97
|
}
|
|
81
98
|
}
|
|
82
99
|
|
|
83
|
-
/* download demo assets */
|
|
84
|
-
const contentBaseUrl = args.values.content;
|
|
85
|
-
|
|
86
|
-
await demoq3.install(contentBaseUrl, async (pakname) => {
|
|
87
|
-
const filename = path.join(homepath, 'baseq3', pakname);
|
|
88
|
-
return ioq3.FS.readFile(filename);
|
|
89
|
-
}, async (pakname, data) => {
|
|
90
|
-
const filename = path.join(homepath, 'baseq3', pakname);
|
|
91
|
-
ioq3.FS.mkdirTree(path.dirname(filename), 0o777);
|
|
92
|
-
ioq3.FS.writeFile(filename, data);
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
/* download mod-specific assets */
|
|
96
|
-
const game = path.basename(gamepath);
|
|
97
|
-
const manifest = await fetch(`${contentBaseUrl}/${game}/manifest.json`).then((res) => {
|
|
98
|
-
if (!res.ok) {
|
|
99
|
-
throw new Error(`Manifest request returned a ${res.status} status`);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return res.json();
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
for (const [pakname, paksum] of Object.entries(manifest)) {
|
|
106
|
-
const pakpath = path.join(homepath, game, pakname);
|
|
107
|
-
const paksumRemote = parseInt(paksum, 16);
|
|
108
|
-
|
|
109
|
-
try {
|
|
110
|
-
const pakdata = ioq3.FS.readFile(pakpath);
|
|
111
|
-
const paksumLocal = formats.pak.checksum(pakdata);
|
|
112
|
-
|
|
113
|
-
if (paksumLocal === paksumRemote) {
|
|
114
|
-
continue;
|
|
115
|
-
}
|
|
116
|
-
} catch (e) {
|
|
117
|
-
/* ignore */
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const pakprint = pakname.replace('.pk3', `.${paksum}.pk3`);
|
|
121
|
-
const pakurl = `${contentBaseUrl}/${game}/${pakprint}`;
|
|
122
|
-
|
|
123
|
-
console.log(`downloading ${pakurl}`);
|
|
124
|
-
|
|
125
|
-
const data = await fetch(pakurl).then((res) => {
|
|
126
|
-
if (!res.ok) {
|
|
127
|
-
throw new Error(`Pak request returned a ${res.status} status`);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return res.bytes();
|
|
131
|
-
});
|
|
132
|
-
ioq3.FS.mkdirTree(path.dirname(pakpath), 0o777);
|
|
133
|
-
ioq3.FS.writeFile(pakpath, data);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
100
|
/* startup the server */
|
|
137
101
|
const port = parseInt(args.values.port);
|
|
138
|
-
const cmdline = `+set
|
|
102
|
+
const cmdline = `+set fs_contentURL "${contentBaseUrl}" ` +
|
|
103
|
+
`+set fs_homepath ${virtualHomePath} ` +
|
|
139
104
|
`+set fs_game ${game} ` +
|
|
140
105
|
'+set dedicated 2 ' +
|
|
141
106
|
`+set net_port ${port} ` +
|
|
142
|
-
`+set
|
|
107
|
+
`+set com_hunkmegs 150`;
|
|
143
108
|
|
|
144
109
|
ioq3.callMain([...cmdline.split(/\s+/), ...args.positionals]);
|