Skip to content

Commit e48d48f

Browse files
Wind292ekulxamits-miromacassiancc
authored
Game Rule documentation (FabricMC#527)
Co-authored-by: SkyNotTheLimit <159592458+ekulxam@users.noreply.github.com> Co-authored-by: Miroma <its.miroma@proton.me> Co-authored-by: Cassian <cassian@godsted.com>
1 parent ea0a477 commit e48d48f

File tree

8 files changed

+170
-1
lines changed

8 files changed

+170
-1
lines changed

.vitepress/sidebars/develop.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,10 @@ export default [
387387
text: "develop.misc.events",
388388
link: "/develop/events",
389389
},
390+
{
391+
text: "develop.misc.game_rules",
392+
link: "/develop/game-rules",
393+
},
390394
{
391395
text: "develop.misc.text_and_translations",
392396
link: "/develop/text-and-translations",

develop/game-rules.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
---
2+
title: Game Rules
3+
description: A guide for adding custom game rules.
4+
authors:
5+
- cassiancc
6+
- Jummit
7+
- modmuss50
8+
- Wind292
9+
authors-nogithub:
10+
- mysterious_dev
11+
- solacekairos
12+
---
13+
14+
<!---->
15+
16+
::: info PREREQUISITES
17+
18+
You might want to have completed the [translation generation](./data-generation/translations) first, but it is not required.
19+
20+
:::
21+
22+
Game rules act as world-specific configuration options that the player can change in-game with a command. These variables usually control some function of the world, for example `pvp`, `spawn_monsters`, and `advance_time` control whether PvP is enabled, monster spawning, and time passing.
23+
24+
## Creating a Game Rule {#creating-a-game-rule}
25+
26+
To create a custom game rule, first create a `GameRules` class; this is where we are going to declare our game rules. Inside this class, declare two constants: a game rule identifier and the rule itself.
27+
28+
@[code lang=java transcludeWith=:::gameruleClass](@/reference/latest/src/main/java/com/example/docs/gamerule/ExampleModGameRules.java)
29+
30+
The category argument (`.category(GameRuleCategory.MISC)`) determines which category the gamerule falls under in the world creation screen. This example uses the Miscellaneous category provided by vanilla, but additional categories can be added via `GameRuleCategory.register`. In this example, we have created a boolean game rule with a default value of `false` and an id of `bad_vision`. The stored values in game rules are not limited to booleans; other valid types include `Double`s, `Integer`s, and `Enum`s.
31+
32+
Example of a game rule storing a double:
33+
34+
@[code lang=java transcludeWith=:::double](@/reference/latest/src/main/java/com/example/docs/gamerule/ExampleModGameRules.java)
35+
36+
## Accessing a Game Rule {#accessing-a-game-rule}
37+
38+
Now that we have a game rule and its `Identifier`, you can access it anywhere with the `serverLevel.getGameRules().get(GAMERULE)` method, where the argument to the `.get()` is your game rule constant and not the game rule id.
39+
40+
@[code lang=java transclude={44-44}](@/reference/latest/src/main/java/com/example/docs/gamerule/ExampleModGameRules.java)
41+
42+
You can also use this to access the values of vanilla game rules:
43+
44+
@[code lang=java transcludeWith=:::vanilla](@/reference/latest/src/main/java/com/example/docs/gamerule/ExampleModGameRules.java)
45+
46+
For example, for a rule that applies blindness to every player when true, the implementation would be:
47+
48+
@[code lang=java transcludeWith=:::badvision](@/reference/latest/src/main/java/com/example/docs/gamerule/ExampleModGameRules.java)
49+
50+
## Translations {#translations}
51+
52+
Now, we need to give our game rule a display name so it can be easily understood from the Game Rules screen. To do this via data generation, add the following lines to your language provider:
53+
54+
@[code lang=java transcludeWith=:::gamerule-name](@/reference/latest/src/client/java/com/example/docs/datagen/ExampleModEnglishLangProvider.java)
55+
56+
Lastly we need to give our gamerule a description. To do this via data generation, add the following lines to your language provider:
57+
58+
@[code lang=java transcludeWith=:::gamerule-description](@/reference/latest/src/client/java/com/example/docs/datagen/ExampleModEnglishLangProvider.java)
59+
60+
::: info
61+
62+
These translation keys are used when displaying text in the game rules screen. If you do not use data generation, you can also write them by hand in your `assets/example-mod/lang/en_us.json`.
63+
64+
```json
65+
"example-mod.bad_vision": "Bad Vision",
66+
"gamerule.example-mod.bad_vision": "Gives every player the blindness effect",
67+
```
68+
69+
:::
70+
71+
## Changing Game Rules In-Game {#changing-game-rules-in-game}
72+
73+
Now, you should be able to change the value of your rule in-game with the `/gamerule` command as such:
74+
75+
```mcfunction
76+
/gamerule example-mod:bad_vision true
77+
```
78+
79+
The game rule also now shows up in the Miscellaneous category in the Edit Game Rules screen.
80+
81+
![The world creation screen showing the Bad Vision game rule](/assets/develop/game-rules/world-creation.png)
712 KB
Loading

reference/latest/src/client/java/com/example/docs/datagen/ExampleModEnglishLangProvider.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,16 @@ public void generateTranslations(HolderLookup.Provider holderLookup, Translation
7171
translationBuilder.add(ExampleModAppearance.WAXCAP_BLOCK_ITEM, "Waxcap");
7272
translationBuilder.add("key.category.example-mod.custom_category", "Example Mod Custom Category");
7373
translationBuilder.add("key.example-mod.send_to_chat", "Send to Chat");
74+
75+
// :::gamerule-description
76+
translationBuilder.add(
77+
Util.makeDescriptionId("gamerule", Identifier.fromNamespaceAndPath(ExampleMod.MOD_ID, "bad_vision")),
78+
"Gives every player the blindness effect" // A short description of the game rule
79+
);
80+
// :::gamerule-description
81+
// :::gamerule-name
82+
translationBuilder.add(Identifier.fromNamespaceAndPath(ExampleMod.MOD_ID, "bad_vision"), "Bad Vision");
83+
// :::gamerule-name
7484
// :::datagen-translations:provider
7585
}
7686
}

reference/latest/src/main/generated/assets/example-mod/lang/en_us.json

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package com.example.docs.gamerule;
2+
3+
import net.minecraft.resources.Identifier;
4+
import net.minecraft.world.effect.MobEffectInstance;
5+
import net.minecraft.world.effect.MobEffects;
6+
import net.minecraft.world.entity.player.Player;
7+
import net.minecraft.world.level.gamerules.GameRule;
8+
import net.minecraft.world.level.gamerules.GameRuleCategory;
9+
import net.minecraft.world.level.gamerules.GameRules;
10+
11+
import net.fabricmc.api.ModInitializer;
12+
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
13+
import net.fabricmc.fabric.api.gamerule.v1.GameRuleBuilder;
14+
15+
import com.example.docs.ExampleMod;
16+
17+
// :::gameruleClass
18+
public class ExampleModGameRules implements ModInitializer {
19+
// Create and register a boolean gamerule, disabled by default
20+
public static final GameRule<Boolean> BAD_VISION_BOOLEAN_GAMERULE = GameRuleBuilder
21+
.forBoolean(false) // Default value declaration
22+
.category(GameRuleCategory.MISC)
23+
.buildAndRegister(Identifier.fromNamespaceAndPath(ExampleMod.MOD_ID, "bad_vision"));
24+
// :::gameruleClass
25+
26+
// :::double
27+
public static final GameRule<Double> DOUBLE_GAMERULE = GameRuleBuilder
28+
.forDouble(6.7) // Default value declaration
29+
.category(GameRuleCategory.MISC)
30+
.buildAndRegister(Identifier.fromNamespaceAndPath(ExampleMod.MOD_ID, "double_example"));
31+
// :::double
32+
33+
private static void initializeBadVision() {
34+
// :::badvision
35+
// In your mod's onInitialize():
36+
ServerTickEvents.END_WORLD_TICK.register(serverLevel -> {
37+
// Runs every tick on the server
38+
// :::badvision
39+
// :::vanilla
40+
boolean doMobGriefing = serverLevel.getGameRules().get(GameRules.MOB_GRIEFING);
41+
// :::vanilla
42+
// :::badvision
43+
// Check for the state of the gamerule
44+
boolean badVisionEnabled = serverLevel.getGameRules().get(ExampleModGameRules.BAD_VISION_BOOLEAN_GAMERULE);
45+
46+
if (badVisionEnabled) {
47+
// If the gamerule is true
48+
for (Player player : serverLevel.getPlayers(p -> true)) {
49+
// Apply blindness to every player
50+
player.addEffect(new MobEffectInstance(
51+
MobEffects.BLINDNESS,
52+
40,
53+
1,
54+
false,
55+
false,
56+
false
57+
));
58+
}
59+
}
60+
});
61+
// :::badvision
62+
}
63+
64+
@Override
65+
public void onInitialize() {
66+
initializeBadVision();
67+
}
68+
// :::gameruleClass
69+
}
70+
// :::gameruleClass

reference/latest/src/main/resources/fabric.mod.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
"com.example.docs.debug.ExampleModDebug",
2727
"com.example.docs.saveddata.ExampleModSavedData",
2828
"com.example.docs.appearance.ExampleModAppearance",
29-
"com.example.docs.entity.attribute.ExampleModAttributes"
29+
"com.example.docs.entity.attribute.ExampleModAttributes",
30+
"com.example.docs.gamerule.ExampleModGameRules"
3031
],
3132
"client": [
3233
"com.example.docs.client.command.ExampleModClientCommands",

sidebar_translations.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
"develop.misc.codecs": "Codecs",
7373
"develop.misc.data_attachments": "Data Attachments",
7474
"develop.misc.events": "Events",
75+
"develop.misc.game_rules": "Game Rules",
7576
"develop.misc.networking": "Networking",
7677
"develop.misc.key_mappings": "Key Mappings",
7778
"develop.misc.saved_data": "Saved Data",

0 commit comments

Comments
 (0)