@kradle/challenges 0.0.1

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.
Files changed (49) hide show
  1. package/README.md +1 -0
  2. package/biome.json +39 -0
  3. package/dist/actions.d.ts +203 -0
  4. package/dist/actions.d.ts.map +1 -0
  5. package/dist/actions.js +287 -0
  6. package/dist/actions.js.map +1 -0
  7. package/dist/api_utils.d.ts +5 -0
  8. package/dist/api_utils.d.ts.map +1 -0
  9. package/dist/api_utils.js +13 -0
  10. package/dist/api_utils.js.map +1 -0
  11. package/dist/challenge.d.ts +56 -0
  12. package/dist/challenge.d.ts.map +1 -0
  13. package/dist/challenge.js +462 -0
  14. package/dist/challenge.js.map +1 -0
  15. package/dist/commands.d.ts +38 -0
  16. package/dist/commands.d.ts.map +1 -0
  17. package/dist/commands.js +135 -0
  18. package/dist/commands.js.map +1 -0
  19. package/dist/constants.d.ts +70 -0
  20. package/dist/constants.d.ts.map +1 -0
  21. package/dist/constants.js +112 -0
  22. package/dist/constants.js.map +1 -0
  23. package/dist/index.d.ts +5 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +23 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/testmode.d.ts +3 -0
  28. package/dist/testmode.d.ts.map +1 -0
  29. package/dist/testmode.js +19 -0
  30. package/dist/testmode.js.map +1 -0
  31. package/dist/types.d.ts +103 -0
  32. package/dist/types.d.ts.map +1 -0
  33. package/dist/types.js +10 -0
  34. package/dist/types.js.map +1 -0
  35. package/dist/utils.d.ts +17 -0
  36. package/dist/utils.d.ts.map +1 -0
  37. package/dist/utils.js +22 -0
  38. package/dist/utils.js.map +1 -0
  39. package/package.json +27 -0
  40. package/src/actions.ts +388 -0
  41. package/src/api_utils.ts +10 -0
  42. package/src/challenge.ts +553 -0
  43. package/src/commands.ts +141 -0
  44. package/src/constants.ts +121 -0
  45. package/src/index.ts +4 -0
  46. package/src/testmode.ts +18 -0
  47. package/src/types.ts +136 -0
  48. package/src/utils.ts +22 -0
  49. package/tsconfig.json +38 -0
@@ -0,0 +1,121 @@
1
+ import { _, execute, Objective, type Score, Selector } from "sandstone";
2
+ import { type _InputCustomEventType, type _InputVariableType, Actions } from "./types";
3
+ import { getChildFunctionName } from "./utils";
4
+
5
+ /**
6
+ * All possible events that can be defined in a challenge.
7
+ */
8
+ export type POSSIBLE_SCENARIO_EVENTS = "start_challenge" | "init_participants" | "end_challenge" | "on_tick";
9
+
10
+ export const VISIBLE_OBJECTIVE = Objective.create("kradle.board", "dummy", [{ text: "Kradle Board", color: "gold" }]);
11
+ export const HIDDEN_OBJECTIVE = Objective.create("kradle.hidden");
12
+
13
+ export const WATCHER = "watcher";
14
+ export const WEB_VIEWER = "KradleWebViewer";
15
+ export const KRADLE_PARTICIPANT_TAG = "kradle_participant";
16
+ export const WINNER_TAG = "kradle_winner";
17
+ export const DISPLAY_TAG = "***KRADLE***";
18
+
19
+ export const MAX_DURATION = 5 * 60 * 20; // 5 minutes in ticks
20
+
21
+ /// The selector that targets all participants in the game.
22
+ export const ALL = Selector("@a", { tag: KRADLE_PARTICIPANT_TAG });
23
+ export const GAME_STATES = {
24
+ CREATED: 0,
25
+ ON: 2,
26
+ OFF: 1,
27
+ } as const;
28
+
29
+ /// The variables that are builtin by default in every challenge.
30
+ /// These variables are used to track the state of the game and the players.
31
+ /// They can be used in the challenge definition to create end conditions, win conditions, and events.
32
+ export const BUILTIN_VARIABLES = {
33
+ death_count: {
34
+ type: "individual",
35
+ objective_type: "deathCount",
36
+ default: 0,
37
+ },
38
+ has_never_died: {
39
+ type: "individual",
40
+ updater: (value: Score, { death_count }) => {
41
+ value.set(0);
42
+ _.if(death_count.equalTo(0), () => {
43
+ value.set(1);
44
+ });
45
+ },
46
+ },
47
+ alive_players: {
48
+ type: "global",
49
+ updater: (value: Score, { has_never_died }) => {
50
+ value.set(0);
51
+ execute.as(ALL).run(getChildFunctionName("alive_players"), () => {
52
+ _.if(has_never_died, () => {
53
+ value.add(1);
54
+ });
55
+ });
56
+ },
57
+ },
58
+ main_score: {
59
+ type: "individual",
60
+ default: 0,
61
+ updater: (value: Score) => {
62
+ VISIBLE_OBJECTIVE("@s").set(value);
63
+ },
64
+ },
65
+ game_timer: {
66
+ type: "global",
67
+ default: 0,
68
+ updater: (value: Score) => {
69
+ value.add(1);
70
+ },
71
+ },
72
+ game_state: {
73
+ type: "global",
74
+ default: GAME_STATES.CREATED,
75
+ },
76
+ player_count: {
77
+ type: "global",
78
+ default: 0,
79
+ },
80
+ /// This variable is used to assign a unique number to each player, starting from 1.
81
+ player_number: {
82
+ type: "individual",
83
+ objective_type: "dummy",
84
+ default: 0,
85
+ updater: (value: Score, { player_count }) => {
86
+ _.if(value.equalTo(0), () => {
87
+ player_count.add(1);
88
+ value.set(player_count);
89
+ //tellraw("@a", [`${DISPLAY_TAG}`, { selector: "@s" }, "@s is player number ", value]);
90
+ });
91
+ },
92
+ },
93
+ /// This variable is used to announce in-game deaths
94
+ death_event: {
95
+ type: "individual",
96
+ objective_type: "deathCount",
97
+ updater: (value: Score) => {
98
+ _.if(value.greaterThan(0), () => {
99
+ Actions.announce({
100
+ message: [Selector("@s"), " has died!"],
101
+ })();
102
+ value.set(0); // Reset the death count after announcing
103
+ });
104
+ },
105
+ },
106
+ } satisfies Record<string, _InputVariableType<string>>;
107
+
108
+ export type BUILTIN_VARIABLE_NAMES = keyof typeof BUILTIN_VARIABLES;
109
+
110
+ export const BUILTIN_SCORE_EVENTS = (variables: Record<BUILTIN_VARIABLE_NAMES, Score>) =>
111
+ [
112
+ {
113
+ mode: "repeatable",
114
+ score: variables.main_score,
115
+ actions: [
116
+ () => {
117
+ VISIBLE_OBJECTIVE("@s").set(variables.main_score);
118
+ },
119
+ ],
120
+ },
121
+ ] satisfies _InputCustomEventType[];
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export { Actions } from "./actions";
2
+ export * from "./api_utils";
3
+ export * from "./challenge";
4
+ export * from "./constants";
@@ -0,0 +1,18 @@
1
+ import { raw, tag } from "sandstone";
2
+ import { KRADLE_PARTICIPANT_TAG } from "./constants";
3
+
4
+ //set to true to enable test mode
5
+ export const test_mode_enabled = false;
6
+ //set the minecraft name of the tester player
7
+ const tester_minecraft_name = "";
8
+
9
+ export const set_up_test_mode = () => {
10
+ // 1. Tag the tester player if they're going to be participating
11
+ tag(tester_minecraft_name).add(KRADLE_PARTICIPANT_TAG);
12
+
13
+ // 2. Set the tester player's gamemode, e.g. survival
14
+ raw(`gamemode survival ${tester_minecraft_name}`);
15
+
16
+ // 3. Set the gamerule sendCommandFeedback to true
17
+ raw("gamerule sendCommandFeedback true");
18
+ };
package/src/types.ts ADDED
@@ -0,0 +1,136 @@
1
+ import type { Score } from "sandstone";
2
+ import type { OBJECTIVE_CRITERION } from "sandstone/arguments/generated";
3
+ import type { AdvancementTriggers } from "sandstone/arguments/resources/AdvancementTriggers";
4
+ import type { Action } from "./actions";
5
+ import type { BUILTIN_VARIABLE_NAMES, POSSIBLE_SCENARIO_EVENTS } from "./constants";
6
+
7
+ export { Actions } from "./actions";
8
+
9
+ // Variables that are defined for a specific objective type will be stored in the scoreboard
10
+ export type _SpecificObjectiveVariable<VARIABLE_NAMES extends string = string> = {
11
+ type: "individual";
12
+ objective_type: OBJECTIVE_CRITERION;
13
+ /** The default value for the variable. 0 if undefined. */
14
+ default?: number;
15
+ /** The updater function is used to dynamically compute the value of the variable. */
16
+ updater?: (value: Score, variables: Record<VARIABLE_NAMES, Score>) => void;
17
+ };
18
+
19
+ // Variables that do not specify an objective type are considered dummy variables.
20
+ // If the are "global", they will be directly stored in the Visible or Hidden scoreboard.
21
+ // Else, a specific objective will be created for them.
22
+ export type _DummyGlobalVariable<VARIABLE_NAMES extends string = string> = {
23
+ type: "global";
24
+ /** Whether the value should be displayed in-game. */
25
+ hidden?: boolean;
26
+ /** The default value for the variable. 0 if undefined. */
27
+ default?: number;
28
+ /** The updater function is used to dynamically compute the value of the variable. */
29
+ updater?: (value: Score, variables: Record<VARIABLE_NAMES, Score>) => void;
30
+ };
31
+
32
+ export type _DummyIndividualVariable<VARIABLE_NAMES extends string = string> = {
33
+ type: "individual";
34
+ /** The default value for the variable. 0 if undefined. */
35
+ default?: number;
36
+ /** The updater function is used to dynamically compute the value of the variable. */
37
+ updater?: (value: Score, variables: Record<VARIABLE_NAMES, Score>) => void;
38
+ };
39
+
40
+ /**
41
+ * A custom variable defined for the whole challenge.
42
+ */
43
+ export type _InputVariableType<VARIABLE_NAMES extends string = string> =
44
+ | _SpecificObjectiveVariable<VARIABLE_NAMES>
45
+ | _DummyGlobalVariable<VARIABLE_NAMES>
46
+ | _DummyIndividualVariable<VARIABLE_NAMES>;
47
+
48
+ export function isSpecificObjectiveVariable(
49
+ variable: _InputVariableType<string>,
50
+ ): variable is _SpecificObjectiveVariable<string> {
51
+ return variable.type === "individual" && !!(variable as any).objective_type;
52
+ }
53
+
54
+ /**
55
+ * The base configuration necessary to define events, end conditions, and win conditions for a challenge.
56
+ */
57
+ export type _BaseConfig<ROLE_NAMES extends string, VARIABLE_NAMES extends string> = {
58
+ /**
59
+ * Name of the datapack that will be created for this challenge.
60
+ */
61
+ name: string;
62
+
63
+ /**
64
+ * The path where the datapack will be created. It is expected to be `kradle-studio/challenges`.
65
+ */
66
+ kradle_challenge_path: string;
67
+
68
+ /**
69
+ * Game duration in ticks.
70
+ *
71
+ * Can be set to `INFINITY` (the default) to run without a time limit.
72
+ *
73
+ * @default INFINITY
74
+ */
75
+ GAME_DURATION?: number;
76
+ roles: ROLE_NAMES[];
77
+ custom_variables: Record<VARIABLE_NAMES, _InputVariableType<VARIABLE_NAMES | BUILTIN_VARIABLE_NAMES>>;
78
+ };
79
+
80
+ export type _ScenarioEvents = Partial<Record<POSSIBLE_SCENARIO_EVENTS, { actions: Action[] }>>;
81
+
82
+ export type Roles<ROLES_NAMES extends string = string> = {
83
+ [role in ROLES_NAMES]: role;
84
+ };
85
+
86
+ export type FullVariable<VARIABLE_NAMES extends string = string> = {
87
+ type: "individual" | "global";
88
+ score: Score;
89
+ default: number | undefined;
90
+ updater: ((value: Score, variables: Record<VARIABLE_NAMES, Score>) => void) | undefined;
91
+ };
92
+
93
+ /**
94
+ * "Full" variables are the variables the challenges passes to the user in events/other variable updaters.
95
+ */
96
+ export type FullVariables<VARIABLE_NAMES extends string = string> = Record<
97
+ VARIABLE_NAMES | BUILTIN_VARIABLE_NAMES,
98
+ FullVariable<VARIABLE_NAMES>
99
+ >;
100
+
101
+ export type Variables<VARIABLE_NAMES extends string = string> = Record<VARIABLE_NAMES | BUILTIN_VARIABLE_NAMES, Score>;
102
+
103
+ type _InputEventCommonProperties = {
104
+ /** The target score to reach to trigger the event */
105
+ target?: number | undefined;
106
+ /** The mode of the event, either fire once or fire every time the score reaches the target */
107
+ mode: "fire_once" | "repeatable";
108
+ /** Actions to execute when the event is triggered */
109
+ actions: Action[];
110
+ };
111
+
112
+ export type _InputScoreCustomEventType = {
113
+ /** The target score to reach to trigger the event */
114
+ score: Score;
115
+ } & _InputEventCommonProperties;
116
+
117
+ export type _InputAdvancementCustomEventType = {
118
+ /** A list of criteria that must be met to trigger the event */
119
+ criteria: AdvancementTriggers[];
120
+ } & _InputEventCommonProperties;
121
+
122
+ export type _InputCustomEventType = _InputScoreCustomEventType | _InputAdvancementCustomEventType;
123
+
124
+ export type CustomScoreEvent = {
125
+ /** The input event that defines the conditions for the custom event */
126
+ inputEvent: _InputScoreCustomEventType;
127
+
128
+ /** The score that counts how many times the event has been triggered */
129
+ counter: Score;
130
+
131
+ /** The type of the event */
132
+ type: "global" | "individual";
133
+
134
+ /** A name used for debugging purposes */
135
+ debugName: string;
136
+ };
package/src/utils.ts ADDED
@@ -0,0 +1,22 @@
1
+ import { dataPack } from "sandstone/init";
2
+
3
+ /// This is stolen from "type-fest" library - this allows us to get autocomplete on the "string" type
4
+ export type LiteralStringUnion<LiteralType> = LiteralType | (string & Record<never, never>);
5
+
6
+ /**
7
+ * Generates a unique child function name based on the given name & the current context.
8
+ *
9
+ * For example, if you're inside a MCFunction named "test",
10
+ * getChildFunctionName("myFunction") will return "test/myFunction".
11
+ *
12
+ * This is useful to get meaningful names for child functions, instead of the standard "execute_as_1/2/3...".
13
+ *
14
+ * 👉 This brings more clarity to the generated functions tree, without impacting the datapack behavior.
15
+ *
16
+ * @param name The base name for the child function.
17
+ *
18
+ * @returns A meaningful child function name that is unique within the current context.
19
+ */
20
+ export function getChildFunctionName(name: string): string {
21
+ return dataPack.getUniqueChildName(name).fullName;
22
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ // Visit https://aka.ms/tsconfig to read more about this file
3
+ "compilerOptions": {
4
+ // File Layout
5
+ "rootDir": "./src",
6
+ "outDir": "./dist",
7
+ // Environment Settings
8
+ // See also https://aka.ms/tsconfig/module
9
+ "module": "nodenext",
10
+ "target": "esnext",
11
+ "lib": [
12
+ "esnext"
13
+ ],
14
+ "types": [
15
+ "node"
16
+ ],
17
+ // Other Outputs
18
+ "sourceMap": true,
19
+ "declaration": true,
20
+ "declarationMap": true,
21
+ // Stricter Typechecking Options
22
+ // "noUncheckedIndexedAccess": true,
23
+ "exactOptionalPropertyTypes": true,
24
+ // Style Options
25
+ "noImplicitReturns": true,
26
+ "noImplicitOverride": true,
27
+ // "noUnusedLocals": true,
28
+ // "noUnusedParameters": true,
29
+ // "noFallthroughCasesInSwitch": true,
30
+ // "noPropertyAccessFromIndexSignature": true,
31
+ // Recommended Options
32
+ "strict": true,
33
+ "isolatedModules": true,
34
+ "noUncheckedSideEffectImports": true,
35
+ "moduleDetection": "force",
36
+ "skipLibCheck": true,
37
+ }
38
+ }