@adeficior/data-modifier-recipes 2.0.0-rc.20260814115618
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/.turbo/turbo-build.log +1 -0
- package/.turbo/turbo-check.log +1 -0
- package/.turbo/turbo-lint.log +1 -0
- package/@types/modules.d.ts +15 -0
- package/@types/registry.d.ts +20 -0
- package/CHANGELOG.md +14 -0
- package/dist/emitter.d.ts +48 -0
- package/dist/emitter.js +116 -0
- package/dist/emitter.js.map +1 -0
- package/dist/hooks.d.ts +6 -0
- package/dist/hooks.js +4 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/loader.d.ts +27 -0
- package/dist/loader.js +141 -0
- package/dist/loader.js.map +1 -0
- package/dist/module.d.ts +15 -0
- package/dist/module.js +38 -0
- package/dist/module.js.map +1 -0
- package/dist/rule.d.ts +15 -0
- package/dist/rule.js +31 -0
- package/dist/rule.js.map +1 -0
- package/dist/schema.d.ts +7 -0
- package/dist/schema.js +14 -0
- package/dist/schema.js.map +1 -0
- package/dist/serializer/abstract.d.ts +17 -0
- package/dist/serializer/abstract.js +19 -0
- package/dist/serializer/abstract.js.map +1 -0
- package/dist/serializer/context.d.ts +12 -0
- package/dist/serializer/context.js +4 -0
- package/dist/serializer/context.js.map +1 -0
- package/dist/serializer/forge/conditional.d.ts +25 -0
- package/dist/serializer/forge/conditional.js +45 -0
- package/dist/serializer/forge/conditional.js.map +1 -0
- package/dist/serializer/holder.d.ts +25 -0
- package/dist/serializer/holder.js +52 -0
- package/dist/serializer/holder.js.map +1 -0
- package/dist/serializer/manyToMany.d.ts +21 -0
- package/dist/serializer/manyToMany.js +37 -0
- package/dist/serializer/manyToMany.js.map +1 -0
- package/dist/serializer/manyToOne.d.ts +21 -0
- package/dist/serializer/manyToOne.js +37 -0
- package/dist/serializer/manyToOne.js.map +1 -0
- package/dist/serializer/modifier.d.ts +6 -0
- package/dist/serializer/modifier.js +3 -0
- package/dist/serializer/modifier.js.map +1 -0
- package/dist/serializer/oneToOne.d.ts +21 -0
- package/dist/serializer/oneToOne.js +37 -0
- package/dist/serializer/oneToOne.js.map +1 -0
- package/dist/serializer/vanilla/shaped.d.ts +22 -0
- package/dist/serializer/vanilla/shaped.js +37 -0
- package/dist/serializer/vanilla/shaped.js.map +1 -0
- package/dist/serializer/vanilla/shapeless.d.ts +4 -0
- package/dist/serializer/vanilla/shapeless.js +4 -0
- package/dist/serializer/vanilla/shapeless.js.map +1 -0
- package/dist/serializer/vanilla/smelting.d.ts +22 -0
- package/dist/serializer/vanilla/smelting.js +37 -0
- package/dist/serializer/vanilla/smelting.js.map +1 -0
- package/dist/serializer/vanilla/smithing.d.ts +25 -0
- package/dist/serializer/vanilla/smithing.js +46 -0
- package/dist/serializer/vanilla/smithing.js.map +1 -0
- package/dist/serializer/vanilla/stonecutting.d.ts +22 -0
- package/dist/serializer/vanilla/stonecutting.js +38 -0
- package/dist/serializer/vanilla/stonecutting.js.map +1 -0
- package/eslint.config.js +8 -0
- package/package.json +42 -0
- package/src/emitter.ts +239 -0
- package/src/hooks.ts +10 -0
- package/src/index.ts +18 -0
- package/src/loader.ts +219 -0
- package/src/module.ts +70 -0
- package/src/rule.ts +45 -0
- package/src/schema.ts +30 -0
- package/src/serializer/abstract.ts +41 -0
- package/src/serializer/context.ts +17 -0
- package/src/serializer/forge/conditional.ts +72 -0
- package/src/serializer/holder.ts +63 -0
- package/src/serializer/manyToMany.ts +62 -0
- package/src/serializer/manyToOne.ts +62 -0
- package/src/serializer/modifier.ts +10 -0
- package/src/serializer/oneToOne.ts +60 -0
- package/src/serializer/vanilla/shaped.ts +65 -0
- package/src/serializer/vanilla/shapeless.ts +8 -0
- package/src/serializer/vanilla/smelting.ts +62 -0
- package/src/serializer/vanilla/smithing.ts +74 -0
- package/src/serializer/vanilla/stonecutting.ts +63 -0
- package/src/testing/index.ts +1 -0
- package/src/testing/setup.ts +85 -0
- package/test/1.20.1/__snapshots__/emitter.test.ts.snap +122 -0
- package/test/1.20.1/__snapshots__/loader.test.ts.snap +215 -0
- package/test/1.20.1/emitter.test.ts +222 -0
- package/test/1.20.1/loader.test.ts +17 -0
- package/test/1.21.1/loader.test.ts +17 -0
- package/test/1.21.1/packFormat.test.ts +52 -0
- package/test/resources/1.20.1/default/custom/data/custom/recipes/conditional.json +25 -0
- package/tsconfig.build.json +14 -0
- package/tsconfig.json +34 -0
package/src/rule.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createId,
|
|
3
|
+
Rule,
|
|
4
|
+
type Id,
|
|
5
|
+
type Modifier,
|
|
6
|
+
} from "@adeficior/data-modifier-core";
|
|
7
|
+
import { type Predicate } from "@adeficior/data-modifier-core/serializer";
|
|
8
|
+
import {
|
|
9
|
+
type Ingredient,
|
|
10
|
+
type Result,
|
|
11
|
+
} from "@adeficior/data-modifier-ingredients";
|
|
12
|
+
import { type ContextLike, type Logger } from "@adeficior/pack-resolver";
|
|
13
|
+
import { type RecipeHolder } from "./serializer/holder";
|
|
14
|
+
|
|
15
|
+
export class RecipeRule extends Rule<RecipeHolder> {
|
|
16
|
+
constructor(
|
|
17
|
+
private readonly context: ContextLike,
|
|
18
|
+
private readonly idsTests: Predicate<Id>[],
|
|
19
|
+
private readonly typeTests: Predicate<Id>[],
|
|
20
|
+
private readonly ingredientTests: Predicate<Ingredient>[],
|
|
21
|
+
private readonly resultTests: Predicate<Result>[],
|
|
22
|
+
modifier: Modifier<RecipeHolder>,
|
|
23
|
+
) {
|
|
24
|
+
super(modifier);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
matches(id: Id, recipe: RecipeHolder): boolean {
|
|
28
|
+
const types = recipe.getTypes().map(createId);
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
this.idsTests.every((test) => test(id)) &&
|
|
32
|
+
this.typeTests.every((test) => types.some((it) => test(it))) &&
|
|
33
|
+
this.ingredientTests.every((test) =>
|
|
34
|
+
recipe.getIngredients().some((it) => test(it)),
|
|
35
|
+
) &&
|
|
36
|
+
this.resultTests.every((test) =>
|
|
37
|
+
recipe.getResults().some((it) => test(it)),
|
|
38
|
+
)
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
printWarning(logger: Logger) {
|
|
43
|
+
logger.trace("could not find any recipes matching", this.context);
|
|
44
|
+
}
|
|
45
|
+
}
|
package/src/schema.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createId,
|
|
3
|
+
isAtLeastVersion,
|
|
4
|
+
jsonFilePattern,
|
|
5
|
+
type IdInput,
|
|
6
|
+
type SemVerInput,
|
|
7
|
+
type WithConditions,
|
|
8
|
+
} from "@adeficior/data-modifier-core";
|
|
9
|
+
import { type RecipeSerializerId } from "@adeficior/data-modifier/generated";
|
|
10
|
+
|
|
11
|
+
export type RecipeDefinition = WithConditions<
|
|
12
|
+
Readonly<{
|
|
13
|
+
type: RecipeSerializerId;
|
|
14
|
+
// TODO add neoforge conditions
|
|
15
|
+
}>
|
|
16
|
+
>;
|
|
17
|
+
|
|
18
|
+
function recipeFolder(packFormat: SemVerInput) {
|
|
19
|
+
return isAtLeastVersion(packFormat, "44") ? "recipe" : "recipes";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function recipePath(packFormat: SemVerInput, id: IdInput) {
|
|
23
|
+
const folder = recipeFolder(packFormat);
|
|
24
|
+
const { namespace, path } = createId(id);
|
|
25
|
+
return `data/${namespace}/${folder}/${path}.json`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function recipePattern(packFormat: SemVerInput) {
|
|
29
|
+
return jsonFilePattern("data", recipeFolder(packFormat));
|
|
30
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type NormalizedId } from "@adeficior/data-modifier-core";
|
|
2
|
+
import {
|
|
3
|
+
type Ingredient,
|
|
4
|
+
type Result,
|
|
5
|
+
type WithSerializerModules,
|
|
6
|
+
} from "@adeficior/data-modifier-ingredients";
|
|
7
|
+
import { type RecipeDefinition } from "../schema";
|
|
8
|
+
import { type RecipeParseContext } from "./context";
|
|
9
|
+
import { type RecipeModifier } from "./modifier";
|
|
10
|
+
|
|
11
|
+
export abstract class Recipe {
|
|
12
|
+
abstract getIngredients(): Ingredient[];
|
|
13
|
+
|
|
14
|
+
abstract getResults(): Result[];
|
|
15
|
+
|
|
16
|
+
abstract modify(modifier: RecipeModifier): Recipe;
|
|
17
|
+
|
|
18
|
+
additionalTypes(): NormalizedId[] {
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
abstract serialize(context: RecipeParseContext): Partial<RecipeDefinition>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export abstract class RecipeParser<
|
|
26
|
+
TDefinition extends RecipeDefinition = RecipeDefinition,
|
|
27
|
+
TRecipe extends Recipe = Recipe,
|
|
28
|
+
> implements WithSerializerModules {
|
|
29
|
+
ingredientModules() {
|
|
30
|
+
return {};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
resultModules() {
|
|
34
|
+
return {};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
abstract deserialize(
|
|
38
|
+
definition: TDefinition,
|
|
39
|
+
context: RecipeParseContext,
|
|
40
|
+
): TRecipe;
|
|
41
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type IngredientSerializer,
|
|
3
|
+
type ResultSerializer,
|
|
4
|
+
} from "@adeficior/data-modifier-ingredients";
|
|
5
|
+
import { type RecipeDefinition } from "../schema";
|
|
6
|
+
import { type RecipeHolder } from "./holder";
|
|
7
|
+
|
|
8
|
+
export type RecipeSerializer = {
|
|
9
|
+
deserialize(definition: RecipeDefinition): RecipeHolder;
|
|
10
|
+
serialize(recipe: RecipeHolder): RecipeDefinition;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type RecipeParseContext = {
|
|
14
|
+
results: ResultSerializer;
|
|
15
|
+
ingredients: IngredientSerializer;
|
|
16
|
+
recipes: RecipeSerializer;
|
|
17
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { type RecipeDefinition } from "../../schema";
|
|
2
|
+
import { Recipe, RecipeParser } from "../abstract";
|
|
3
|
+
import { type RecipeParseContext } from "../context";
|
|
4
|
+
import { type RecipeHolder } from "../holder";
|
|
5
|
+
import { type RecipeModifier } from "../modifier";
|
|
6
|
+
|
|
7
|
+
type WithConditions<T> = {
|
|
8
|
+
conditions: unknown[];
|
|
9
|
+
recipe: T;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export type ForgeConditionalRecipeDefinition = RecipeDefinition &
|
|
13
|
+
Readonly<{
|
|
14
|
+
recipes: WithConditions<RecipeDefinition>[];
|
|
15
|
+
}>;
|
|
16
|
+
|
|
17
|
+
export class ForgeConditionalRecipe extends Recipe {
|
|
18
|
+
constructor(private readonly recipes: WithConditions<RecipeHolder>[]) {
|
|
19
|
+
super();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
getIngredients() {
|
|
23
|
+
return this.recipes.flatMap((it) => it.recipe.getIngredients());
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
getResults() {
|
|
27
|
+
return this.recipes.flatMap((it) => it.recipe.getResults());
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
override modify(modifier: RecipeModifier) {
|
|
31
|
+
return new ForgeConditionalRecipe(
|
|
32
|
+
this.recipes.map((it) => ({
|
|
33
|
+
...it,
|
|
34
|
+
recipe: it.recipe.modify(modifier),
|
|
35
|
+
})),
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
override serialize(
|
|
40
|
+
context: RecipeParseContext,
|
|
41
|
+
): Partial<ForgeConditionalRecipeDefinition> {
|
|
42
|
+
return {
|
|
43
|
+
recipes: this.recipes.map((it) => ({
|
|
44
|
+
...it,
|
|
45
|
+
recipe: context.recipes.serialize(it.recipe),
|
|
46
|
+
})),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
override additionalTypes() {
|
|
51
|
+
return this.recipes.flatMap((it) => it.recipe.getTypes());
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export class ForgeConditionalRecipeParser extends RecipeParser<
|
|
56
|
+
ForgeConditionalRecipeDefinition,
|
|
57
|
+
ForgeConditionalRecipe
|
|
58
|
+
> {
|
|
59
|
+
override deserialize(
|
|
60
|
+
definition: ForgeConditionalRecipeDefinition,
|
|
61
|
+
context: RecipeParseContext,
|
|
62
|
+
): ForgeConditionalRecipe {
|
|
63
|
+
const recipes = definition.recipes.map<WithConditions<RecipeHolder>>(
|
|
64
|
+
(it) => ({
|
|
65
|
+
conditions: it.conditions,
|
|
66
|
+
recipe: context.recipes.deserialize(it.recipe),
|
|
67
|
+
}),
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
return new ForgeConditionalRecipe(recipes);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { encodeId, type NormalizedId } from "@adeficior/data-modifier-core";
|
|
2
|
+
import { type Replacer } from "@adeficior/data-modifier-core/serializer";
|
|
3
|
+
import {
|
|
4
|
+
type Ingredient,
|
|
5
|
+
type Result,
|
|
6
|
+
} from "@adeficior/data-modifier-ingredients";
|
|
7
|
+
import { type RecipeDefinition } from "../schema";
|
|
8
|
+
import { type Recipe } from "./abstract";
|
|
9
|
+
import { type RecipeParseContext } from "./context";
|
|
10
|
+
import { type RecipeModifier } from "./modifier";
|
|
11
|
+
|
|
12
|
+
function keep<T>(): Replacer<T> {
|
|
13
|
+
return (it) => it;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class RecipeHolder {
|
|
17
|
+
readonly serializerType: NormalizedId;
|
|
18
|
+
|
|
19
|
+
constructor(
|
|
20
|
+
private readonly definition: RecipeDefinition,
|
|
21
|
+
private readonly recipe: Recipe,
|
|
22
|
+
) {
|
|
23
|
+
this.serializerType = encodeId(definition.type);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
serialize(context: RecipeParseContext) {
|
|
27
|
+
return {
|
|
28
|
+
...this.definition,
|
|
29
|
+
...this.recipe.serialize(context),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
getIngredients() {
|
|
34
|
+
return this.recipe.getIngredients();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
getResults() {
|
|
38
|
+
return this.recipe.getResults();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
modify(modifier: RecipeModifier): RecipeHolder {
|
|
42
|
+
const modified = this.recipe.modify(modifier);
|
|
43
|
+
return new RecipeHolder(this.definition, modified);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
replaceIngredient(replace: Replacer<Ingredient>): RecipeHolder {
|
|
47
|
+
return this.modify({
|
|
48
|
+
ingredient: replace,
|
|
49
|
+
result: keep(),
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
replaceResult(replace: Replacer<Result>): RecipeHolder {
|
|
54
|
+
return this.modify({
|
|
55
|
+
ingredient: keep(),
|
|
56
|
+
result: replace,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
getTypes(): NormalizedId[] {
|
|
61
|
+
return [this.serializerType, ...this.recipe.additionalTypes()];
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Ingredient,
|
|
3
|
+
type Result,
|
|
4
|
+
} from "@adeficior/data-modifier-ingredients";
|
|
5
|
+
import { type RecipeDefinition } from "../schema";
|
|
6
|
+
import { Recipe, RecipeParser } from "./abstract";
|
|
7
|
+
import { type RecipeParseContext } from "./context";
|
|
8
|
+
import { type RecipeModifier } from "./modifier";
|
|
9
|
+
|
|
10
|
+
export type ManyToManyRecipeDefinition = RecipeDefinition &
|
|
11
|
+
Readonly<{
|
|
12
|
+
ingredients: unknown[];
|
|
13
|
+
results: unknown[];
|
|
14
|
+
}>;
|
|
15
|
+
|
|
16
|
+
export class ManyToManyRecipe extends Recipe {
|
|
17
|
+
constructor(
|
|
18
|
+
protected readonly ingredients: Ingredient[],
|
|
19
|
+
protected readonly results: Result[],
|
|
20
|
+
) {
|
|
21
|
+
super();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
getIngredients() {
|
|
25
|
+
return this.ingredients;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
getResults() {
|
|
29
|
+
return this.results;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
override modify(modifier: RecipeModifier) {
|
|
33
|
+
return new ManyToManyRecipe(
|
|
34
|
+
this.ingredients.map(modifier.ingredient),
|
|
35
|
+
this.results.map(modifier.result),
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
override serialize(
|
|
40
|
+
context: RecipeParseContext,
|
|
41
|
+
): Partial<ManyToManyRecipeDefinition> {
|
|
42
|
+
return {
|
|
43
|
+
results: context.results.serializeList(this.results),
|
|
44
|
+
ingredients: context.ingredients.serializeList(this.ingredients),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export class ManyToManyRecipeParser<
|
|
50
|
+
TDefinition extends ManyToManyRecipeDefinition,
|
|
51
|
+
> extends RecipeParser<TDefinition, ManyToManyRecipe> {
|
|
52
|
+
deserialize(
|
|
53
|
+
definition: TDefinition,
|
|
54
|
+
context: RecipeParseContext,
|
|
55
|
+
): ManyToManyRecipe {
|
|
56
|
+
const ingredients = context.ingredients.deserializeList(
|
|
57
|
+
definition.ingredients,
|
|
58
|
+
);
|
|
59
|
+
const results = context.results.deserializeList(definition.results);
|
|
60
|
+
return new ManyToManyRecipe(ingredients, results);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Ingredient,
|
|
3
|
+
type Result,
|
|
4
|
+
} from "@adeficior/data-modifier-ingredients";
|
|
5
|
+
import { type RecipeDefinition } from "../schema";
|
|
6
|
+
import { Recipe, RecipeParser } from "./abstract";
|
|
7
|
+
import { type RecipeParseContext } from "./context";
|
|
8
|
+
import { type RecipeModifier } from "./modifier";
|
|
9
|
+
|
|
10
|
+
export type ManyToOneRecipeDefinition = RecipeDefinition &
|
|
11
|
+
Readonly<{
|
|
12
|
+
ingredients: unknown[];
|
|
13
|
+
result: unknown;
|
|
14
|
+
}>;
|
|
15
|
+
|
|
16
|
+
export class ManyToOneRecipe extends Recipe {
|
|
17
|
+
constructor(
|
|
18
|
+
protected readonly ingredients: Ingredient[],
|
|
19
|
+
protected readonly result: Result,
|
|
20
|
+
) {
|
|
21
|
+
super();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
getIngredients() {
|
|
25
|
+
return this.ingredients;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
getResults() {
|
|
29
|
+
return [this.result];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
override modify(modifier: RecipeModifier) {
|
|
33
|
+
return new ManyToOneRecipe(
|
|
34
|
+
this.ingredients.map(modifier.ingredient),
|
|
35
|
+
modifier.result(this.result),
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
override serialize(
|
|
40
|
+
context: RecipeParseContext,
|
|
41
|
+
): Partial<ManyToOneRecipeDefinition> {
|
|
42
|
+
return {
|
|
43
|
+
result: context.results.serialize(this.result),
|
|
44
|
+
ingredients: context.ingredients.serializeList(this.ingredients),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export class ManyToOneRecipeParser<
|
|
50
|
+
TDefinition extends ManyToOneRecipeDefinition,
|
|
51
|
+
> extends RecipeParser<TDefinition, ManyToOneRecipe> {
|
|
52
|
+
deserialize(
|
|
53
|
+
definition: TDefinition,
|
|
54
|
+
context: RecipeParseContext,
|
|
55
|
+
): ManyToOneRecipe {
|
|
56
|
+
const ingredients = context.ingredients.deserializeList(
|
|
57
|
+
definition.ingredients,
|
|
58
|
+
);
|
|
59
|
+
const result = context.results.deserialize(definition.result);
|
|
60
|
+
return new ManyToOneRecipe(ingredients, result);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Replacer } from "@adeficior/data-modifier-core/serializer";
|
|
2
|
+
import {
|
|
3
|
+
type Ingredient,
|
|
4
|
+
type Result,
|
|
5
|
+
} from "@adeficior/data-modifier-ingredients";
|
|
6
|
+
|
|
7
|
+
export type RecipeModifier = {
|
|
8
|
+
result: Replacer<Result>;
|
|
9
|
+
ingredient: Replacer<Ingredient>;
|
|
10
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Ingredient,
|
|
3
|
+
type Result,
|
|
4
|
+
} from "@adeficior/data-modifier-ingredients";
|
|
5
|
+
import { type RecipeDefinition } from "../schema";
|
|
6
|
+
import { Recipe, RecipeParser } from "./abstract";
|
|
7
|
+
import { type RecipeParseContext } from "./context";
|
|
8
|
+
import { type RecipeModifier } from "./modifier";
|
|
9
|
+
|
|
10
|
+
export type OneToOneRecipeDefinition = RecipeDefinition &
|
|
11
|
+
Readonly<{
|
|
12
|
+
ingredient: unknown;
|
|
13
|
+
result: unknown;
|
|
14
|
+
}>;
|
|
15
|
+
|
|
16
|
+
export class OneToOneRecipe extends Recipe {
|
|
17
|
+
constructor(
|
|
18
|
+
protected readonly ingredient: Ingredient,
|
|
19
|
+
protected readonly result: Result,
|
|
20
|
+
) {
|
|
21
|
+
super();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
getIngredients() {
|
|
25
|
+
return [this.ingredient];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
getResults() {
|
|
29
|
+
return [this.result];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
override modify(modifier: RecipeModifier) {
|
|
33
|
+
return new OneToOneRecipe(
|
|
34
|
+
modifier.ingredient(this.ingredient),
|
|
35
|
+
modifier.result(this.result),
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
override serialize(
|
|
40
|
+
context: RecipeParseContext,
|
|
41
|
+
): Partial<OneToOneRecipeDefinition> {
|
|
42
|
+
return {
|
|
43
|
+
result: context.results.serialize(this.result),
|
|
44
|
+
ingredient: context.ingredients.serialize(this.ingredient),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export class OneToOneRecipeParser<
|
|
50
|
+
TDefinition extends OneToOneRecipeDefinition,
|
|
51
|
+
> extends RecipeParser<TDefinition, OneToOneRecipe> {
|
|
52
|
+
deserialize(
|
|
53
|
+
definition: TDefinition,
|
|
54
|
+
context: RecipeParseContext,
|
|
55
|
+
): OneToOneRecipe {
|
|
56
|
+
const ingredient = context.ingredients.deserialize(definition.ingredient);
|
|
57
|
+
const result = context.results.deserialize(definition.result);
|
|
58
|
+
return new OneToOneRecipe(ingredient, result);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type IngredientMap,
|
|
3
|
+
type IngredientMapInput,
|
|
4
|
+
type Result,
|
|
5
|
+
} from "@adeficior/data-modifier-ingredients";
|
|
6
|
+
import { type RecipeDefinition } from "../../schema";
|
|
7
|
+
import { Recipe, RecipeParser } from "../abstract";
|
|
8
|
+
import { type RecipeParseContext } from "../context";
|
|
9
|
+
import { type RecipeModifier } from "../modifier";
|
|
10
|
+
|
|
11
|
+
export type ShapedRecipeDefinition = RecipeDefinition &
|
|
12
|
+
Readonly<{
|
|
13
|
+
key: IngredientMapInput;
|
|
14
|
+
pattern: string[];
|
|
15
|
+
result: unknown;
|
|
16
|
+
}>;
|
|
17
|
+
|
|
18
|
+
export class ShapedRecipe extends Recipe {
|
|
19
|
+
constructor(
|
|
20
|
+
private readonly ingredients: IngredientMap,
|
|
21
|
+
private readonly result: Result,
|
|
22
|
+
) {
|
|
23
|
+
super();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
getIngredients() {
|
|
27
|
+
return this.ingredients.list();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
getResults() {
|
|
31
|
+
return [this.result];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
override modify(modifier: RecipeModifier) {
|
|
35
|
+
return new ShapedRecipe(
|
|
36
|
+
this.ingredients.replace(modifier.ingredient),
|
|
37
|
+
modifier.result(this.result),
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
override serialize(
|
|
42
|
+
context: RecipeParseContext,
|
|
43
|
+
): Partial<ShapedRecipeDefinition> {
|
|
44
|
+
return {
|
|
45
|
+
key: context.ingredients.serializeIngredientMap(this.ingredients),
|
|
46
|
+
result: context.results.serialize(this.result),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export class ShapedParser extends RecipeParser<
|
|
52
|
+
ShapedRecipeDefinition,
|
|
53
|
+
ShapedRecipe
|
|
54
|
+
> {
|
|
55
|
+
deserialize(
|
|
56
|
+
definition: ShapedRecipeDefinition,
|
|
57
|
+
context: RecipeParseContext,
|
|
58
|
+
): ShapedRecipe {
|
|
59
|
+
const ingredients = context.ingredients.deserializeIngredientMap(
|
|
60
|
+
definition.key,
|
|
61
|
+
);
|
|
62
|
+
const result = context.results.deserialize(definition.result);
|
|
63
|
+
return new ShapedRecipe(ingredients, result);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Ingredient,
|
|
3
|
+
type Result,
|
|
4
|
+
} from "@adeficior/data-modifier-ingredients";
|
|
5
|
+
import { type RecipeDefinition } from "../../schema";
|
|
6
|
+
import { Recipe, RecipeParser } from "../abstract";
|
|
7
|
+
import { type RecipeParseContext } from "../context";
|
|
8
|
+
import { type RecipeModifier } from "../modifier";
|
|
9
|
+
|
|
10
|
+
export type SmeltingRecipeDefinition = RecipeDefinition &
|
|
11
|
+
Readonly<{
|
|
12
|
+
ingredient: unknown;
|
|
13
|
+
result: unknown;
|
|
14
|
+
experience?: number;
|
|
15
|
+
}>;
|
|
16
|
+
|
|
17
|
+
export class SmeltingRecipe extends Recipe {
|
|
18
|
+
constructor(
|
|
19
|
+
private readonly ingredient: Ingredient,
|
|
20
|
+
private readonly result: Result,
|
|
21
|
+
) {
|
|
22
|
+
super();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
getIngredients() {
|
|
26
|
+
return [this.ingredient];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
getResults() {
|
|
30
|
+
return [this.result];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
override modify(modifier: RecipeModifier) {
|
|
34
|
+
return new SmeltingRecipe(
|
|
35
|
+
modifier.ingredient(this.ingredient),
|
|
36
|
+
modifier.result(this.result),
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
override serialize(
|
|
41
|
+
context: RecipeParseContext,
|
|
42
|
+
): Partial<SmeltingRecipeDefinition> {
|
|
43
|
+
return {
|
|
44
|
+
ingredient: context.ingredients.serialize(this.ingredient),
|
|
45
|
+
result: context.results.serialize(this.result),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export class SmeltingParser extends RecipeParser<
|
|
51
|
+
SmeltingRecipeDefinition,
|
|
52
|
+
SmeltingRecipe
|
|
53
|
+
> {
|
|
54
|
+
deserialize(
|
|
55
|
+
definition: SmeltingRecipeDefinition,
|
|
56
|
+
context: RecipeParseContext,
|
|
57
|
+
): SmeltingRecipe {
|
|
58
|
+
const ingredient = context.ingredients.deserialize(definition.ingredient);
|
|
59
|
+
const result = context.results.deserialize(definition.result);
|
|
60
|
+
return new SmeltingRecipe(ingredient, result);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Ingredient,
|
|
3
|
+
type Result,
|
|
4
|
+
} from "@adeficior/data-modifier-ingredients";
|
|
5
|
+
import { notNull } from "@adeficior/pack-resolver";
|
|
6
|
+
import { type RecipeDefinition } from "../../schema";
|
|
7
|
+
import { Recipe, RecipeParser } from "../abstract";
|
|
8
|
+
import { type RecipeParseContext } from "../context";
|
|
9
|
+
import { type RecipeModifier } from "../modifier";
|
|
10
|
+
|
|
11
|
+
export type SmithingRecipeDefinition = RecipeDefinition &
|
|
12
|
+
Readonly<{
|
|
13
|
+
base: unknown;
|
|
14
|
+
addition: unknown;
|
|
15
|
+
result?: unknown;
|
|
16
|
+
template?: unknown;
|
|
17
|
+
}>;
|
|
18
|
+
|
|
19
|
+
export class SmithingRecipe extends Recipe {
|
|
20
|
+
constructor(
|
|
21
|
+
private readonly base: Ingredient,
|
|
22
|
+
private readonly addition: Ingredient,
|
|
23
|
+
private readonly result: Result | undefined,
|
|
24
|
+
private readonly template: Ingredient | undefined,
|
|
25
|
+
) {
|
|
26
|
+
super();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
getIngredients() {
|
|
30
|
+
return [this.base, this.addition, this.template].filter(notNull);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
getResults() {
|
|
34
|
+
return [this.result].filter(notNull);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
override modify(modifier: RecipeModifier) {
|
|
38
|
+
return new SmithingRecipe(
|
|
39
|
+
modifier.ingredient(this.base),
|
|
40
|
+
modifier.ingredient(this.addition),
|
|
41
|
+
this.result && modifier.result(this.result),
|
|
42
|
+
this.template && modifier.ingredient(this.template),
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
override serialize(
|
|
47
|
+
context: RecipeParseContext,
|
|
48
|
+
): Partial<SmithingRecipeDefinition> {
|
|
49
|
+
return {
|
|
50
|
+
base: context.ingredients.serialize(this.base),
|
|
51
|
+
addition: context.ingredients.serialize(this.addition),
|
|
52
|
+
result: context.results.serializeOptional(this.result),
|
|
53
|
+
template: context.ingredients.serializeOptional(this.template),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export class SmithingParser extends RecipeParser<
|
|
59
|
+
SmithingRecipeDefinition,
|
|
60
|
+
SmithingRecipe
|
|
61
|
+
> {
|
|
62
|
+
deserialize(
|
|
63
|
+
definition: SmithingRecipeDefinition,
|
|
64
|
+
context: RecipeParseContext,
|
|
65
|
+
): SmithingRecipe {
|
|
66
|
+
const base = context.ingredients.deserialize(definition.base);
|
|
67
|
+
const addition = context.ingredients.deserialize(definition.addition);
|
|
68
|
+
const result = context.results.deserializeOptional(definition.result);
|
|
69
|
+
const template = context.ingredients.deserializeOptional(
|
|
70
|
+
definition.addition,
|
|
71
|
+
);
|
|
72
|
+
return new SmithingRecipe(base, addition, result, template);
|
|
73
|
+
}
|
|
74
|
+
}
|