Skip to content

Commit 8b0cedb

Browse files
feat: forced gamerules
1 parent cce9466 commit 8b0cedb

File tree

10 files changed

+247
-86
lines changed

10 files changed

+247
-86
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# Changelog
22

3+
## [21.1.12]
4+
5+
### Added
6+
7+
* Forced Game Rules mapping via `forced-game-rules` in the `ftbpc-common.snbt` config file.
8+
* This contains a mapping of `rules` that can accept the game rule name as the key and the value as the value to set it to.
9+
* This can only be set to either a boolean or an integer depending on the game rule type.
10+
* Incorrect game rule names or incorrect values will throw the game.
11+
312
## [21.1.11]
413

514
### Added

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ parchment_mappings_version=2024.11.17
99

1010
mod_name=FTB Pack Companion
1111
mod_id=ftbpc
12-
mod_version=12
12+
mod_version=13
1313

1414
minecraft_version=1.21.1
1515
# https://minecraft.fandom.com/wiki/Pack_format

src/main/java/dev/ftb/packcompanion/PackCompanion.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import dev.ftb.packcompanion.config.PCServerConfig;
77
import dev.ftb.packcompanion.core.Feature;
88
import dev.ftb.packcompanion.features.buffs.MobEntityBuffFeature;
9+
import dev.ftb.packcompanion.features.forcedgamerule.ForcedGameRulesFeature;
910
import dev.ftb.packcompanion.features.loot.RandomNameLootFeature;
1011
import dev.ftb.packcompanion.features.onboarding.shadernotice.ShaderNotice;
1112
import dev.ftb.packcompanion.features.spawners.SpawnerFeature;
@@ -59,7 +60,8 @@ public class PackCompanion {
5960
ShaderNotice::new,
6061
NoWanderingTraderInvisPotions::new,
6162
TriggerBlockFeature::new,
62-
ActionPadFeature::new
63+
ActionPadFeature::new,
64+
ForcedGameRulesFeature::new
6365
);
6466

6567
private final List<Feature> createdFeatures = new ArrayList<>();
Lines changed: 12 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
11
package dev.ftb.packcompanion.config;
22

33
import dev.ftb.mods.ftblibrary.config.manager.ConfigManager;
4-
import dev.ftb.mods.ftblibrary.snbt.SNBTCompoundTag;
5-
import dev.ftb.mods.ftblibrary.snbt.config.BaseValue;
64
import dev.ftb.mods.ftblibrary.snbt.config.BooleanValue;
75
import dev.ftb.mods.ftblibrary.snbt.config.SNBTConfig;
86
import dev.ftb.mods.ftblibrary.snbt.config.StringValue;
97
import dev.ftb.packcompanion.PackCompanion;
108
import dev.ftb.packcompanion.config.values.ChunkPosCustomYHashValue;
11-
import net.minecraft.nbt.ListTag;
12-
import net.minecraft.nbt.Tag;
13-
import org.jetbrains.annotations.Nullable;
9+
import dev.ftb.packcompanion.config.values.GameRuleMapping;
10+
import dev.ftb.packcompanion.config.values.SparseStructuresConfig;
11+
import dev.ftb.packcompanion.config.values.SparseStructuresValue;
1412

15-
import java.util.ArrayList;
16-
import java.util.List;
13+
import java.util.*;
1714

1815
public interface PCCommonConfig {
1916
SNBTConfig CONFIG = SNBTConfig.create(PackCompanion.MOD_ID + "-common");
@@ -48,82 +45,16 @@ public interface PCCommonConfig {
4845
new ArrayList<>()
4946
).comment("Custom min-y level list for specific block locations within a range from the center, per dimension."));
5047

51-
static void init() {
52-
ConfigManager.getInstance().registerServerConfig(CONFIG, PackCompanion.MOD_ID + ".common", true);
53-
}
48+
SNBTConfig FORCED_GAME_RULES = CONFIG.addGroup("forced-game-rules");
5449

55-
class SparseStructuresValue extends BaseValue<SparseStructuresConfig> {
56-
protected SparseStructuresValue(@Nullable SNBTConfig c, String n, SparseStructuresConfig def) {
57-
super(c, n, def);
58-
}
59-
60-
@Override
61-
public void write(SNBTCompoundTag compoundTag) {
62-
SNBTCompoundTag tag = new SNBTCompoundTag();
63-
64-
tag.comment("enabled", "Whether sparse structures are enabled.");
65-
tag.putBoolean("enabled", get().enabled);
66-
67-
tag.comment("global_spread_factor", "The global spread factor for all structures when no custom spread factor is defined.");
68-
tag.putDouble("global_spread_factor", get().globalSpreadFactor);
69-
70-
var list = new ListTag();
71-
for (var custom : get().customSpreadFactors) {
72-
var customTag = new SNBTCompoundTag();
73-
customTag.putString("structure", custom.structure);
74-
customTag.putDouble("spread_factor", custom.spreadFactor);
75-
list.add(customTag);
76-
}
77-
78-
tag.comment("custom_spread_factors", "Custom spread factors for specific structures.");
79-
tag.put("custom_spread_factors", list);
80-
81-
compoundTag.comment(this.key, "Sparse structures configuration. See https://github.com/MCTeamPotato/SparseStructuresReforged/tree/1201 for more information.");
82-
compoundTag.put(this.key, tag);
83-
}
84-
85-
@Override
86-
public void read(SNBTCompoundTag parent) {
87-
if (!parent.contains(this.key)) {
88-
set(SparseStructuresConfig.DEFAULT);
89-
return;
90-
}
91-
92-
var tag = (SNBTCompoundTag) parent.get(this.key);
93-
if (tag == null) {
94-
set(SparseStructuresConfig.DEFAULT);
95-
return;
96-
}
97-
98-
var enabled = tag.getBoolean("enabled");
99-
var globalSpreadFactor = tag.getDouble("global_spread_factor");
100-
var customSpreadFactors = new ArrayList<CustomSpreadFactors>();
101-
102-
if (tag.contains("custom_spread_factors")) {
103-
var listTag = tag.getList("custom_spread_factors", Tag.TAG_COMPOUND);
104-
for (var customTag : listTag) {
105-
var compound = (SNBTCompoundTag) customTag;
106-
customSpreadFactors.add(new CustomSpreadFactors(
107-
compound.getString("structure"),
108-
compound.getDouble("spread_factor")
109-
));
110-
}
111-
}
112-
113-
set(new SparseStructuresConfig(enabled, globalSpreadFactor, customSpreadFactors));
114-
}
115-
}
50+
GameRuleMapping GAME_RULE_MAPPING = FORCED_GAME_RULES.add(new GameRuleMapping(
51+
FORCED_GAME_RULES,
52+
"rules",
53+
Map.of()
54+
).comment("Game rules that are forced on the server. The keys must be valid game rule IDs."));
11655

117-
record SparseStructuresConfig(
118-
boolean enabled,
119-
double globalSpreadFactor,
120-
List<CustomSpreadFactors> customSpreadFactors
121-
) {
122-
public static final SparseStructuresConfig DEFAULT = new SparseStructuresConfig(false, 2D, new ArrayList<>());
56+
static void init() {
57+
ConfigManager.getInstance().registerServerConfig(CONFIG, PackCompanion.MOD_ID + ".common", true);
12358
}
12459

125-
record CustomSpreadFactors(
126-
String structure,
127-
double spreadFactor
128-
) {}
12960
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package dev.ftb.packcompanion.config.values;
2+
3+
public record CustomSpreadFactors(
4+
String structure,
5+
double spreadFactor
6+
) {
7+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package dev.ftb.packcompanion.config.values;
2+
3+
import dev.ftb.mods.ftblibrary.snbt.SNBTCompoundTag;
4+
import dev.ftb.mods.ftblibrary.snbt.config.BaseValue;
5+
import dev.ftb.mods.ftblibrary.snbt.config.SNBTConfig;
6+
import net.minecraft.nbt.Tag;
7+
import net.minecraft.world.level.GameRules;
8+
import org.jetbrains.annotations.NotNull;
9+
import org.jetbrains.annotations.Nullable;
10+
11+
import java.util.HashMap;
12+
import java.util.HashSet;
13+
import java.util.Map;
14+
15+
public class GameRuleMapping extends BaseValue<Map<String, Tag>> {
16+
public GameRuleMapping(@Nullable SNBTConfig c, String n, Map<String, Tag> def) {
17+
super(c, n, def);
18+
}
19+
20+
@Override
21+
public void write(SNBTCompoundTag compoundTag) {
22+
SNBTCompoundTag tag = new SNBTCompoundTag();
23+
24+
for (Map.Entry<String, Tag> entry : get().entrySet()) {
25+
tag.put(entry.getKey(), entry.getValue());
26+
}
27+
28+
compoundTag.comment(this.key, "Mapping of game rule keys to their values. Boolean game rules are stored as byte tags (0 or 1), integer game rules are stored as int tags.");
29+
compoundTag.put(this.key, tag);
30+
}
31+
32+
@Override
33+
public void read(SNBTCompoundTag compoundTag) {
34+
if (!compoundTag.contains(this.key)) {
35+
set(Map.of());
36+
return;
37+
}
38+
39+
var tag = compoundTag.getCompound(this.key);
40+
var keys = tag.getAllKeys();
41+
42+
var knownGameRuleKeys = new HashSet<String>();
43+
GameRules.visitGameRuleTypes(new GameRules.GameRuleTypeVisitor() {
44+
@Override
45+
public <T extends GameRules.Value<T>> void visit(GameRules.@NotNull Key<T> key, GameRules.@NotNull Type<T> type) {
46+
knownGameRuleKeys.add(key.getId());
47+
}
48+
});
49+
50+
for (String key : keys) {
51+
if (!knownGameRuleKeys.contains(key)) {
52+
throw new IllegalStateException("Unknown game rule key in config: " + key);
53+
}
54+
}
55+
56+
Map<String, Tag> map = new HashMap<>();
57+
for (String key : tag.getAllKeys()) {
58+
Tag valueTag = tag.get(key);
59+
if (valueTag == null) {
60+
continue;
61+
}
62+
63+
if (valueTag.getId() == Tag.TAG_BYTE) {
64+
map.put(key, valueTag);
65+
} else if (valueTag.getId() == Tag.TAG_INT) {
66+
map.put(key, valueTag);
67+
} else {
68+
throw new IllegalStateException("Invalid tag type for game rule key '" + key + "': " + valueTag.getId());
69+
}
70+
}
71+
72+
set(map);
73+
}
74+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package dev.ftb.packcompanion.config.values;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
public record SparseStructuresConfig(
7+
boolean enabled,
8+
double globalSpreadFactor,
9+
List<CustomSpreadFactors> customSpreadFactors
10+
) {
11+
public static final SparseStructuresConfig DEFAULT = new SparseStructuresConfig(false, 2D, new ArrayList<>());
12+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package dev.ftb.packcompanion.config.values;
2+
3+
import dev.ftb.mods.ftblibrary.snbt.SNBTCompoundTag;
4+
import dev.ftb.mods.ftblibrary.snbt.config.BaseValue;
5+
import dev.ftb.mods.ftblibrary.snbt.config.SNBTConfig;
6+
import net.minecraft.nbt.ListTag;
7+
import net.minecraft.nbt.Tag;
8+
import org.jetbrains.annotations.Nullable;
9+
10+
import java.util.ArrayList;
11+
12+
public class SparseStructuresValue extends BaseValue<SparseStructuresConfig> {
13+
public SparseStructuresValue(@Nullable SNBTConfig c, String n, SparseStructuresConfig def) {
14+
super(c, n, def);
15+
}
16+
17+
@Override
18+
public void write(SNBTCompoundTag compoundTag) {
19+
SNBTCompoundTag tag = new SNBTCompoundTag();
20+
21+
tag.comment("enabled", "Whether sparse structures are enabled.");
22+
tag.putBoolean("enabled", get().enabled());
23+
24+
tag.comment("global_spread_factor", "The global spread factor for all structures when no custom spread factor is defined.");
25+
tag.putDouble("global_spread_factor", get().globalSpreadFactor());
26+
27+
var list = new ListTag();
28+
for (var custom : get().customSpreadFactors()) {
29+
var customTag = new SNBTCompoundTag();
30+
customTag.putString("structure", custom.structure());
31+
customTag.putDouble("spread_factor", custom.spreadFactor());
32+
list.add(customTag);
33+
}
34+
35+
tag.comment("custom_spread_factors", "Custom spread factors for specific structures.");
36+
tag.put("custom_spread_factors", list);
37+
38+
compoundTag.comment(this.key, "Sparse structures configuration. See https://github.com/MCTeamPotato/SparseStructuresReforged/tree/1201 for more information.");
39+
compoundTag.put(this.key, tag);
40+
}
41+
42+
@Override
43+
public void read(SNBTCompoundTag parent) {
44+
if (!parent.contains(this.key)) {
45+
set(SparseStructuresConfig.DEFAULT);
46+
return;
47+
}
48+
49+
var tag = (SNBTCompoundTag) parent.get(this.key);
50+
if (tag == null) {
51+
set(SparseStructuresConfig.DEFAULT);
52+
return;
53+
}
54+
55+
var enabled = tag.getBoolean("enabled");
56+
var globalSpreadFactor = tag.getDouble("global_spread_factor");
57+
var customSpreadFactors = new ArrayList<CustomSpreadFactors>();
58+
59+
if (tag.contains("custom_spread_factors")) {
60+
var listTag = tag.getList("custom_spread_factors", Tag.TAG_COMPOUND);
61+
for (var customTag : listTag) {
62+
var compound = (SNBTCompoundTag) customTag;
63+
customSpreadFactors.add(new CustomSpreadFactors(
64+
compound.getString("structure"),
65+
compound.getDouble("spread_factor")
66+
));
67+
}
68+
}
69+
70+
set(new SparseStructuresConfig(enabled, globalSpreadFactor, customSpreadFactors));
71+
}
72+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package dev.ftb.packcompanion.features.forcedgamerule;
2+
3+
import dev.ftb.packcompanion.config.PCCommonConfig;
4+
import dev.ftb.packcompanion.core.Feature;
5+
import net.minecraft.nbt.ByteTag;
6+
import net.minecraft.nbt.IntTag;
7+
import net.minecraft.nbt.Tag;
8+
import net.minecraft.server.MinecraftServer;
9+
import net.minecraft.world.level.GameRules;
10+
import net.neoforged.bus.api.IEventBus;
11+
import net.neoforged.fml.ModContainer;
12+
import net.neoforged.neoforge.common.NeoForge;
13+
import net.neoforged.neoforge.event.server.ServerStartedEvent;
14+
import org.slf4j.Logger;
15+
import org.slf4j.LoggerFactory;
16+
17+
public class ForcedGameRulesFeature extends Feature.Common {
18+
private static final Logger LOGGER = LoggerFactory.getLogger(ForcedGameRulesFeature.class);
19+
20+
public ForcedGameRulesFeature(IEventBus modEventBus, ModContainer container) {
21+
super(modEventBus, container);
22+
23+
NeoForge.EVENT_BUS.addListener(this::onLevelLoad);
24+
}
25+
26+
public void onLevelLoad(ServerStartedEvent event) {
27+
var forcedGameRules = PCCommonConfig.GAME_RULE_MAPPING.get();
28+
29+
MinecraftServer server = event.getServer();
30+
GameRules.visitGameRuleTypes(new GameRules.GameRuleTypeVisitor() {
31+
@Override
32+
public <T extends GameRules.Value<T>> void visit(GameRules.Key<T> key, GameRules.Type<T> type) {
33+
if (forcedGameRules.containsKey(key.getId())) {
34+
Tag value = forcedGameRules.get(key.getId());
35+
if (value instanceof ByteTag byteTag) {
36+
GameRules.BooleanValue rule = (GameRules.BooleanValue) server.getGameRules().getRule(key);
37+
var asBoolean = byteTag.getAsByte() != 0;
38+
if (rule.get() != asBoolean) {
39+
LOGGER.info("Setting (bool) game rule '{}' to {}", key.getId(), asBoolean);
40+
rule.set(asBoolean, server);
41+
}
42+
} else if (value instanceof IntTag intTag) {
43+
GameRules.IntegerValue rule = (GameRules.IntegerValue) server.getGameRules().getRule(key);
44+
if (rule.get() != intTag.getAsInt()) {
45+
LOGGER.info("Setting (int) game rule '{}' to {}", key.getId(), intTag.getAsInt());
46+
rule.set(intTag.getAsInt(), server);
47+
}
48+
}
49+
}
50+
}
51+
});
52+
}
53+
}

0 commit comments

Comments
 (0)