@terrafirmagreg-team/game 0.0.0-stage → 0.1.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/package.json +58 -3
- package/src/components/entry/atlas-sprite.tsx +57 -0
- package/src/components/entry/copy-id-menu.tsx +55 -0
- package/src/components/entry/entry.tsx +229 -0
- package/src/components/entry/frame.tsx +32 -0
- package/src/components/entry/group.tsx +180 -0
- package/src/components/entry/icon/tabs.tsx +118 -0
- package/src/components/entry/icon.tsx +187 -0
- package/src/components/entry/list.tsx +70 -0
- package/src/components/entry/mc-text.tsx +92 -0
- package/src/components/entry/stack-count.tsx +14 -0
- package/src/components/entry/tooltip.tsx +129 -0
- package/src/components/mdx/item-icon.tsx +69 -0
- package/src/components/preview-icon.tsx +25 -0
- package/src/hooks/use-dump-location.ts +18 -0
- package/src/hooks/use-entry-context.ts +35 -0
- package/src/hooks/use-icon-source.ts +297 -0
- package/src/hooks/use-lang-map.ts +18 -0
- package/src/lib/dump/assets/atlas/dto.ts +49 -0
- package/src/lib/dump/assets/atlas/lookup.ts +206 -0
- package/src/lib/dump/assets/atlas/sprites.ts +130 -0
- package/src/lib/dump/assets/lang/load.ts +17 -0
- package/src/lib/dump/assets/lang/names.ts +244 -0
- package/src/lib/dump/assets/urls.ts +143 -0
- package/src/lib/dump/client/atlases.ts +83 -0
- package/src/lib/dump/client/dump.ts +188 -0
- package/src/lib/dump/client/groups.ts +31 -0
- package/src/lib/dump/client/keybinds.ts +11 -0
- package/src/lib/dump/client/mods.ts +16 -0
- package/src/lib/dump/client/registry.ts +125 -0
- package/src/lib/dump/client/tabs.ts +27 -0
- package/src/lib/dump/client/tags.ts +64 -0
- package/src/lib/dump/contract/kind.ts +61 -0
- package/src/lib/dump/contract/read.ts +77 -0
- package/src/lib/dump/contract/ref.ts +262 -0
- package/src/lib/dump/contract/text.ts +86 -0
- package/src/lib/dump/data/registry/dto.ts +56 -0
- package/src/lib/dump/data/registry/parse.ts +291 -0
- package/src/lib/dump/data/tab/dto.ts +13 -0
- package/src/lib/dump/data/tab/parse.ts +26 -0
- package/src/lib/dump/data/tag/dto.ts +7 -0
- package/src/lib/dump/data/tag/parse.ts +57 -0
- package/src/lib/dump/gen/data/guides/book.ts +56 -0
- package/src/lib/dump/gen/data/guides/category.ts +30 -0
- package/src/lib/dump/gen/data/guides/entry.ts +48 -0
- package/src/lib/dump/gen/data/models/model.ts +3 -0
- package/src/lib/dump/gen/data/quests/chapter.ts +126 -0
- package/src/lib/dump/gen/data/quests/chapter_groups.ts +11 -0
- package/src/lib/dump/gen/data/quests/data.ts +40 -0
- package/src/lib/dump/gen/data/recipes/recipe.ts +78 -0
- package/src/lib/dump/gen/index.ts +20 -0
- package/src/lib/dump/gen/keybinds.ts +3 -0
- package/src/lib/dump/gen/lang.ts +3 -0
- package/src/lib/dump/gen/manifest.ts +59 -0
- package/src/lib/dump/gen/registry/blocks.ts +60 -0
- package/src/lib/dump/gen/registry/entities.ts +49 -0
- package/src/lib/dump/gen/registry/fluids.ts +48 -0
- package/src/lib/dump/gen/registry/groups.ts +14 -0
- package/src/lib/dump/gen/registry/items.ts +51 -0
- package/src/lib/dump/gen/registry/recipe_categories.ts +64 -0
- package/src/lib/dump/gen/registry/recipes.ts +3 -0
- package/src/lib/dump/gen/registry/tabs.ts +46 -0
- package/src/lib/dump/gen/registry/tags.ts +11 -0
- package/src/lib/dump/json-reader.ts +231 -0
- package/src/lib/dump/manifest/dto.ts +11 -0
- package/src/lib/dump/manifest/parse.ts +167 -0
- package/src/lib/dump/mods/dto.ts +40 -0
- package/src/lib/dump/mods/index.ts +81 -0
- package/src/lib/dump/mods/load.ts +61 -0
- package/src/lib/dump/paths.ts +171 -0
- package/src/lib/dump/reader.ts +15 -0
- package/src/lib/entry/display.ts +4 -0
- package/src/lib/entry/entry.ts +57 -0
- package/src/lib/entry/formula.ts +226 -0
- package/src/lib/entry/href.ts +148 -0
- package/src/lib/entry/icon-load.ts +195 -0
- package/src/lib/entry/icon.ts +10 -0
- package/src/lib/entry/tooltip.ts +60 -0
- package/src/lib/preview.ts +18 -0
- package/src/lib/search.ts +31 -0
- package/src/lib/snbt.ts +246 -0
- package/src/locales/en_us.json +9 -0
- package/src/locales/ru_ru.json +9 -0
- package/src/locales.ts +5 -0
- package/src/types/entry.ts +52 -0
- package/styles/fonts.css +15 -0
- package/styles/tokens.css +15 -0
- package/styles.css +2 -0
- package/README.md +0 -3
package/src/lib/snbt.ts
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
const WS = /[ \t\n\r]/;
|
|
2
|
+
|
|
3
|
+
const SAFE_KEY = /^[A-Za-z0-9_.\-+]+$/;
|
|
4
|
+
const SAFE_VALUE = /^[A-Za-z_][A-Za-z0-9_.\-+]*$/;
|
|
5
|
+
const LITERAL_WORD = /^(true|false|null|nan|infinity)$/i;
|
|
6
|
+
const MAX_SAFE = 2 ** 53;
|
|
7
|
+
|
|
8
|
+
export function formatNbt(value: unknown): string | undefined {
|
|
9
|
+
if (value === undefined) return undefined;
|
|
10
|
+
return writeNbtValue(value);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function writeNbtValue(value: unknown): string {
|
|
14
|
+
if (value === null || value === undefined) return 'null';
|
|
15
|
+
if (typeof value === 'boolean') return value ? 'true' : 'false';
|
|
16
|
+
if (typeof value === 'number') return writeNbtNumber(value);
|
|
17
|
+
if (typeof value === 'string') return writeNbtString(value);
|
|
18
|
+
if (Array.isArray(value)) return `[${value.map(writeNbtValue).join(',')}]`;
|
|
19
|
+
if (typeof value === 'object') {
|
|
20
|
+
const entries = Object.entries(value as Record<string, unknown>).sort(([a], [b]) =>
|
|
21
|
+
a < b ? -1 : a > b ? 1 : 0,
|
|
22
|
+
);
|
|
23
|
+
return `{${entries.map(([k, v]) => `${writeNbtKey(k)}:${writeNbtValue(v)}`).join(',')}}`;
|
|
24
|
+
}
|
|
25
|
+
return 'null';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function writeNbtKey(key: string): string {
|
|
29
|
+
return SAFE_KEY.test(key) ? key : JSON.stringify(key);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function writeNbtString(value: string): string {
|
|
33
|
+
return SAFE_VALUE.test(value) && !LITERAL_WORD.test(value)
|
|
34
|
+
? value
|
|
35
|
+
: JSON.stringify(value);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function writeNbtNumber(value: number): string {
|
|
39
|
+
if (!Number.isFinite(value)) return '0';
|
|
40
|
+
if (Number.isInteger(value) && Math.abs(value) <= MAX_SAFE) return value.toFixed(0);
|
|
41
|
+
return String(value);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function formatNbtPretty(value: unknown): string | undefined {
|
|
45
|
+
if (value === undefined) return undefined;
|
|
46
|
+
return prettyNbtValue(value, 0);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function prettyNbtValue(value: unknown, depth: number): string {
|
|
50
|
+
const pad = ' '.repeat(depth);
|
|
51
|
+
const padIn = `${pad} `;
|
|
52
|
+
if (value !== null && typeof value === 'object') {
|
|
53
|
+
if (Array.isArray(value)) {
|
|
54
|
+
if (!value.length) return '[]';
|
|
55
|
+
if (value.every((v) => v === null || typeof v !== 'object')) {
|
|
56
|
+
return `[${value.map(writeNbtValue).join(', ')}]`;
|
|
57
|
+
}
|
|
58
|
+
return `[\n${value
|
|
59
|
+
.map((v) => `${padIn}${prettyNbtValue(v, depth + 1)}`)
|
|
60
|
+
.join(',\n')}\n${pad}]`;
|
|
61
|
+
}
|
|
62
|
+
const entries = Object.entries(value as Record<string, unknown>).sort(([a], [b]) =>
|
|
63
|
+
a < b ? -1 : a > b ? 1 : 0,
|
|
64
|
+
);
|
|
65
|
+
if (!entries.length) return '{}';
|
|
66
|
+
return `{\n${entries
|
|
67
|
+
.map(([k, v]) => `${padIn}${writeNbtKey(k)}: ${prettyNbtValue(v, depth + 1)}`)
|
|
68
|
+
.join(',\n')}\n${pad}}`;
|
|
69
|
+
}
|
|
70
|
+
return writeNbtValue(value);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function parseSnbt(text: string): unknown {
|
|
74
|
+
const src = text.charCodeAt(0) === 0xfeff ? text.slice(1) : text;
|
|
75
|
+
const parser = { src, i: 0 };
|
|
76
|
+
const value = readValue(parser);
|
|
77
|
+
skip(parser);
|
|
78
|
+
if (parser.i < parser.src.length) {
|
|
79
|
+
throw new Error(`SNBT trailing data at ${parser.i}`);
|
|
80
|
+
}
|
|
81
|
+
return value;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
type Parser = { src: string; i: number };
|
|
85
|
+
|
|
86
|
+
function peek(p: Parser): string {
|
|
87
|
+
return p.src[p.i] ?? '';
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function eof(p: Parser): boolean {
|
|
91
|
+
return p.i >= p.src.length;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function skip(p: Parser): void {
|
|
95
|
+
while (!eof(p)) {
|
|
96
|
+
const c = peek(p);
|
|
97
|
+
if (WS.test(c) || c === ',') {
|
|
98
|
+
p.i++;
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if (c === '/' && p.src[p.i + 1] === '/') {
|
|
102
|
+
p.i += 2;
|
|
103
|
+
while (!eof(p) && peek(p) !== '\n') p.i++;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function readValue(p: Parser): unknown {
|
|
111
|
+
skip(p);
|
|
112
|
+
const c = peek(p);
|
|
113
|
+
if (!c) throw new Error('SNBT unexpected end');
|
|
114
|
+
if (c === '{') return readCompound(p);
|
|
115
|
+
if (c === '[') return readList(p);
|
|
116
|
+
if (c === '"') return readString(p);
|
|
117
|
+
return readBare(p);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function readCompound(p: Parser): Record<string, unknown> {
|
|
121
|
+
p.i++;
|
|
122
|
+
const out: Record<string, unknown> = {};
|
|
123
|
+
while (true) {
|
|
124
|
+
skip(p);
|
|
125
|
+
if (peek(p) === '}') {
|
|
126
|
+
p.i++;
|
|
127
|
+
return out;
|
|
128
|
+
}
|
|
129
|
+
if (eof(p)) throw new Error('SNBT unclosed compound');
|
|
130
|
+
const key = peek(p) === '"' ? readString(p) : readUnquoted(p);
|
|
131
|
+
skip(p);
|
|
132
|
+
if (peek(p) !== ':') throw new Error(`SNBT expected ':' after key ${key}`);
|
|
133
|
+
p.i++;
|
|
134
|
+
out[key] = readValue(p);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function readList(p: Parser): unknown[] {
|
|
139
|
+
p.i++;
|
|
140
|
+
skip(p);
|
|
141
|
+
if (/^[BILbils][ \t]*;/.test(p.src.slice(p.i, p.i + 8))) {
|
|
142
|
+
p.i++;
|
|
143
|
+
skip(p);
|
|
144
|
+
if (peek(p) === ';') p.i++;
|
|
145
|
+
}
|
|
146
|
+
const out: unknown[] = [];
|
|
147
|
+
while (true) {
|
|
148
|
+
skip(p);
|
|
149
|
+
if (peek(p) === ']') {
|
|
150
|
+
p.i++;
|
|
151
|
+
return out;
|
|
152
|
+
}
|
|
153
|
+
if (eof(p)) throw new Error('SNBT unclosed list');
|
|
154
|
+
out.push(readValue(p));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function readString(p: Parser): string {
|
|
159
|
+
p.i++;
|
|
160
|
+
let out = '';
|
|
161
|
+
while (!eof(p)) {
|
|
162
|
+
const c = peek(p);
|
|
163
|
+
p.i++;
|
|
164
|
+
if (c === '"') return out;
|
|
165
|
+
if (c !== '\\') {
|
|
166
|
+
out += c;
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
const next = peek(p);
|
|
170
|
+
p.i++;
|
|
171
|
+
switch (next) {
|
|
172
|
+
case 'n':
|
|
173
|
+
out += '\n';
|
|
174
|
+
break;
|
|
175
|
+
case 't':
|
|
176
|
+
out += '\t';
|
|
177
|
+
break;
|
|
178
|
+
case 'r':
|
|
179
|
+
out += '\r';
|
|
180
|
+
break;
|
|
181
|
+
case 'b':
|
|
182
|
+
out += '\b';
|
|
183
|
+
break;
|
|
184
|
+
case 'f':
|
|
185
|
+
out += '\f';
|
|
186
|
+
break;
|
|
187
|
+
case 'u': {
|
|
188
|
+
const hex = p.src.slice(p.i, p.i + 4);
|
|
189
|
+
if (/^[0-9a-fA-F]{4}$/.test(hex)) {
|
|
190
|
+
out += String.fromCharCode(Number.parseInt(hex, 16));
|
|
191
|
+
p.i += 4;
|
|
192
|
+
} else {
|
|
193
|
+
out += 'u';
|
|
194
|
+
}
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
case '"':
|
|
198
|
+
case '\\':
|
|
199
|
+
out += next;
|
|
200
|
+
break;
|
|
201
|
+
default:
|
|
202
|
+
out += next;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
throw new Error('SNBT unclosed string');
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function readUnquoted(p: Parser): string {
|
|
209
|
+
const start = p.i;
|
|
210
|
+
while (!eof(p)) {
|
|
211
|
+
const c = peek(p);
|
|
212
|
+
if (
|
|
213
|
+
c === ':' ||
|
|
214
|
+
c === '{' ||
|
|
215
|
+
c === '}' ||
|
|
216
|
+
c === '[' ||
|
|
217
|
+
c === ']' ||
|
|
218
|
+
c === ',' ||
|
|
219
|
+
WS.test(c)
|
|
220
|
+
) {
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
p.i++;
|
|
224
|
+
}
|
|
225
|
+
if (p.i === start) throw new Error(`SNBT expected key at ${p.i}`);
|
|
226
|
+
return p.src.slice(start, p.i);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function readBare(p: Parser): string | number | boolean {
|
|
230
|
+
const raw = readUnquoted(p);
|
|
231
|
+
if (raw === 'true') return true;
|
|
232
|
+
if (raw === 'false') return false;
|
|
233
|
+
const num = parseSnbtNumber(raw);
|
|
234
|
+
return num === undefined ? raw : num;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const NUM = /^-?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?[bBsSlLfFdD]?$/;
|
|
238
|
+
|
|
239
|
+
function parseSnbtNumber(raw: string): number | undefined {
|
|
240
|
+
if (!NUM.test(raw)) return undefined;
|
|
241
|
+
const last = raw[raw.length - 1];
|
|
242
|
+
const core =
|
|
243
|
+
last && /[bBsSlLfFdD]/.test(last) && !/\d/.test(last) ? raw.slice(0, -1) : raw;
|
|
244
|
+
const value = Number(core);
|
|
245
|
+
return Number.isFinite(value) ? value : undefined;
|
|
246
|
+
}
|
package/src/locales.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { Lang } from '@terrafirmagreg-team/translate/types/locale';
|
|
3
|
+
import type { DumpNbt, ReferenceKind, TaggedReference } from '@terrafirmagreg-team/game/lib/dump/contract/ref';
|
|
4
|
+
|
|
5
|
+
export type EntrySize = 'sm' | 'md' | 'lg' | 'xl' | number;
|
|
6
|
+
|
|
7
|
+
export type EntryHrefOpts = {
|
|
8
|
+
tab?: string;
|
|
9
|
+
type?: string;
|
|
10
|
+
search?: string;
|
|
11
|
+
rpage?: number;
|
|
12
|
+
filename?: string;
|
|
13
|
+
modId?: string;
|
|
14
|
+
bookPath?: string;
|
|
15
|
+
entry?: string;
|
|
16
|
+
hash?: string;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type EntryProps = {
|
|
20
|
+
|
|
21
|
+
reference?: TaggedReference;
|
|
22
|
+
kind?: ReferenceKind;
|
|
23
|
+
id?: string;
|
|
24
|
+
dataset?: string;
|
|
25
|
+
|
|
26
|
+
name?: string;
|
|
27
|
+
|
|
28
|
+
tag?: DumpNbt;
|
|
29
|
+
|
|
30
|
+
lang?: Lang;
|
|
31
|
+
langMap?: Record<string, string>;
|
|
32
|
+
size?: EntrySize;
|
|
33
|
+
|
|
34
|
+
variant?: 'plain' | 'chip';
|
|
35
|
+
|
|
36
|
+
badge?: ReactNode;
|
|
37
|
+
badgeClassName?: string;
|
|
38
|
+
labeled?: boolean;
|
|
39
|
+
label?: string;
|
|
40
|
+
|
|
41
|
+
href?: string | false;
|
|
42
|
+
|
|
43
|
+
copy?: boolean;
|
|
44
|
+
tab?: string;
|
|
45
|
+
className?: string;
|
|
46
|
+
missing?: 'placeholder' | 'item' | 'hide';
|
|
47
|
+
|
|
48
|
+
tooltip?: boolean | 'compact' | 'extended' | 'full' | 'adaptive';
|
|
49
|
+
children?: ReactNode;
|
|
50
|
+
} & Omit<EntryHrefOpts, 'tab'>;
|
|
51
|
+
|
|
52
|
+
export type KindEntryProps = Omit<EntryProps, 'kind'>;
|
package/styles/fonts.css
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
@font-face {
|
|
2
|
+
font-family: 'Minecraft';
|
|
3
|
+
src: url('/fonts/minecraft.otf') format('opentype');
|
|
4
|
+
font-display: swap;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
@font-face {
|
|
8
|
+
font-family: 'Unifont';
|
|
9
|
+
src: url('/fonts/unifont.otf') format('opentype');
|
|
10
|
+
font-display: swap;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.font-mc {
|
|
14
|
+
font-family: 'Unifont', 'Minecraft', 'Courier New', monospace;
|
|
15
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
@theme {
|
|
2
|
+
--color-mc-panel: #c6c6c6;
|
|
3
|
+
--color-mc-bright: #dcdcdc;
|
|
4
|
+
--color-mc-dim: #b5b5b5;
|
|
5
|
+
--color-mc-inset: #8b8b8b;
|
|
6
|
+
--color-mc-edge: #a0a0a0;
|
|
7
|
+
--color-mc-arrow: #3f3f3f;
|
|
8
|
+
--color-mc-arrow-dark: #1f1f1f;
|
|
9
|
+
--color-mc-bevel-dark: #363636;
|
|
10
|
+
--color-mc-bevel-light: #ffffff;
|
|
11
|
+
--color-mc-paper: #f6f6f6;
|
|
12
|
+
--color-mc-shadow: #101010;
|
|
13
|
+
--color-mc-done: #2f7d32;
|
|
14
|
+
--color-mc-enchant: #5555ff;
|
|
15
|
+
}
|
package/styles.css
ADDED
package/README.md
DELETED