mirror of
https://github.com/FabricMC/fabric.git
synced 2025-04-21 11:20:55 -04:00
Create Game Rule API (#641)
* Create GameRule API * Some tweaks * gamerule -> game-rule * Fix translation keys and update to 20w22a * Command results and remove unnessecary factory method * Update to 1.16-pre1 * Update fabric-game-rule-api-v1/src/main/java/net/fabricmc/fabric/api/gamerule/v1/FabricRuleTypeConsumer.java Co-authored-by: liach <7806504+liach@users.noreply.github.com> * I like final things * Update to 1.16-pre3, change enum button style * checkstyle * use right min values * Document ValidatableRule * Document LiteralRule, clarify generics * Update to 20w27a * Rename some parts to compensate for future yarn renames. Flatten some logic related to EnumRules * forgot one * javadoc galore * finish javadoc * Start things * Update to 20w29a, drop float rule * Make cycle naming more accurate * Convert colors to hex Co-authored-by: Erlend Åmdal <erlend@aamdal.com> * Update to 20w30a * imports again Co-authored-by: liach <7806504+liach@users.noreply.github.com> Co-authored-by: Prospector <6166773+Prospector@users.noreply.github.com> Co-authored-by: Erlend Åmdal <erlend@aamdal.com>
This commit is contained in:
parent
d21d463561
commit
d532d74b83
31 changed files with 1864 additions and 0 deletions
fabric-game-rule-api-v1
build.gradle
settings.gradlesrc
main
java/net/fabricmc/fabric
api/gamerule/v1
impl/gamerule
mixin/gamerule
resources
assets/fabric-gamerule-api-v1
fabric-game-rule-api-v1.accesswidenerfabric-game-rule-api-v1.mixins.jsonfabric.mod.jsontestmod
java/net/fabricmc/fabric/test/gamerule
resources
16
fabric-game-rule-api-v1/build.gradle
Normal file
16
fabric-game-rule-api-v1/build.gradle
Normal file
|
@ -0,0 +1,16 @@
|
|||
archivesBaseName = "fabric-game-rule-api-v1"
|
||||
version = getSubprojectVersion(project, "1.0.0")
|
||||
|
||||
minecraft {
|
||||
accessWidener = file("src/main/resources/fabric-game-rule-api-v1.accesswidener")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// MUST BE A DEPENDENCY, OTHERWISE COMPILE WILL FAIL IN "RuleListWidgetMixin"
|
||||
// YOU'VE BEEN WARNED
|
||||
compileOnly 'com.google.code.findbugs:jsr305:3.0.2'
|
||||
|
||||
testmodCompile project(path: ':fabric-api-base', configuration: 'dev')
|
||||
testmodCompile project(path: ':fabric-lifecycle-events-v1', configuration: 'dev')
|
||||
testmodCompile project(path: ':fabric-resource-loader-v0', configuration: 'dev')
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.gamerule.v1;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.world.GameRules;
|
||||
|
||||
import net.fabricmc.fabric.impl.gamerule.RuleKeyExtensions;
|
||||
|
||||
/**
|
||||
* Utility class for creating custom game rule categories outside of the categories {@link GameRules.Category Minecraft provides}.
|
||||
*/
|
||||
public final class CustomGameRuleCategory {
|
||||
private final Identifier id;
|
||||
private final Text name;
|
||||
|
||||
/**
|
||||
* Creates a custom game rule category.
|
||||
*
|
||||
* @param id the id of this category
|
||||
* @param name the name of this category
|
||||
*/
|
||||
public CustomGameRuleCategory(Identifier id, Text name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Identifier getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public Text getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
CustomGameRuleCategory that = (CustomGameRuleCategory) o;
|
||||
|
||||
return this.id.equals(that.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.id.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the custom category a {@link GameRules.Key game rule key} is registered to.
|
||||
*
|
||||
* @param key the rule key
|
||||
* @param <T> the type of value the rule holds
|
||||
* @return the custom category this rule belongs to. Otherwise {@link Optional#empty() empty}
|
||||
*/
|
||||
public static <T extends GameRules.Rule<T>> Optional<CustomGameRuleCategory> getCategory(GameRules.Key<T> key) {
|
||||
return Optional.ofNullable(((RuleKeyExtensions) (Object) key).fabric_getCustomCategory());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.gamerule.v1;
|
||||
|
||||
import net.minecraft.world.GameRules;
|
||||
|
||||
import net.fabricmc.fabric.api.gamerule.v1.rule.DoubleRule;
|
||||
import net.fabricmc.fabric.api.gamerule.v1.rule.EnumRule;
|
||||
|
||||
/**
|
||||
* An extended game rule visitor which supports Fabric's own rule types.
|
||||
*
|
||||
* <p>Game rule visitors are typically used iterating all game rules.
|
||||
* In vanilla, the visitor is used to register game rule commands and populate the {@code Edit Game Rules} screen.
|
||||
*
|
||||
* <p>Rule types specified by this interface are not exhaustive.
|
||||
* New entries may be added in the future.
|
||||
*/
|
||||
public interface FabricGameRuleVisitor extends GameRules.Visitor {
|
||||
/**
|
||||
* Visit a double rule.
|
||||
*
|
||||
* <p>Note {@link #visit(GameRules.Key, GameRules.Type)} will be called before this method is visited.
|
||||
*
|
||||
* @param key the rule key
|
||||
* @param type the rule type
|
||||
*/
|
||||
default void visitDouble(GameRules.Key<DoubleRule> key, GameRules.Type<DoubleRule> type) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Visit an enum rule.
|
||||
*
|
||||
* <p>Note {@link #visit(GameRules.Key, GameRules.Type)} will be called before this method is visited.
|
||||
*
|
||||
* @param key the rule key
|
||||
* @param type the rule type
|
||||
*/
|
||||
default <E extends Enum<E>> void visitEnum(GameRules.Key<EnumRule<E>> key, GameRules.Type<EnumRule<E>> type) {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,311 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.gamerule.v1;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import com.mojang.brigadier.arguments.DoubleArgumentType;
|
||||
import com.mojang.brigadier.arguments.IntegerArgumentType;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.world.GameRules;
|
||||
|
||||
import net.fabricmc.fabric.api.gamerule.v1.rule.DoubleRule;
|
||||
import net.fabricmc.fabric.api.gamerule.v1.rule.EnumRule;
|
||||
import net.fabricmc.fabric.impl.gamerule.EnumRuleType;
|
||||
import net.fabricmc.fabric.impl.gamerule.rule.BoundedIntRule;
|
||||
import net.fabricmc.fabric.mixin.gamerule.BooleanRuleAccessor;
|
||||
|
||||
/**
|
||||
* A utility class containing factory methods to create game rule types.
|
||||
* A game rule is a persisted, per server data value which may control gameplay aspects.
|
||||
*
|
||||
* <p>Some factory methods allow specification of a callback that is invoked when the value of a game rule has changed.
|
||||
* Typically the callback is used for game rules which may influence game logic, such as {@link GameRules#DISABLE_RAIDS disabling raids}.
|
||||
*
|
||||
* <p>To register a game rule, you can use {@link GameRuleRegistry#register(String, GameRules.Category, GameRules.Type)}.
|
||||
* For example, to register a game rule that is an integer where the acceptable values are between 0 and 10, one would use the following:
|
||||
* <blockquote><pre>
|
||||
* public static final GameRules.Key<GameRules.IntRule> EXAMPLE_INT_RULE = GameRuleRegistry.register("exampleIntRule", GameRules.Category.UPDATES, GameRuleFactory.createIntRule(1, 10));
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* <p>To register a game rule in a custom category, {@link GameRuleRegistry#register(String, CustomGameRuleCategory, GameRules.Type)} should be used.
|
||||
*
|
||||
* @see GameRuleRegistry
|
||||
*/
|
||||
public final class GameRuleFactory {
|
||||
/**
|
||||
* Creates a boolean rule type.
|
||||
*
|
||||
* @param defaultValue the default value of the game rule
|
||||
* @return a boolean rule type
|
||||
*/
|
||||
public static GameRules.Type<GameRules.BooleanRule> createBooleanRule(boolean defaultValue) {
|
||||
return createBooleanRule(defaultValue, (server, rule) -> {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a boolean rule type.
|
||||
*
|
||||
* @param defaultValue the default value of the game rule
|
||||
* @param changedCallback a callback that is invoked when the value of a game rule has changed
|
||||
* @return a boolean rule type
|
||||
*/
|
||||
public static GameRules.Type<GameRules.BooleanRule> createBooleanRule(boolean defaultValue, BiConsumer<MinecraftServer, GameRules.BooleanRule> changedCallback) {
|
||||
return BooleanRuleAccessor.invokeCreate(defaultValue, changedCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an integer rule type.
|
||||
*
|
||||
* @param defaultValue the default value of the game rule
|
||||
* @return an integer rule type
|
||||
*/
|
||||
public static GameRules.Type<GameRules.IntRule> createIntRule(int defaultValue) {
|
||||
return createIntRule(defaultValue, (server, rule) -> {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an integer rule type.
|
||||
*
|
||||
* @param defaultValue the default value of the game rule
|
||||
* @param minimumValue the minimum value the game rule may accept
|
||||
* @return an integer rule type
|
||||
*/
|
||||
public static GameRules.Type<GameRules.IntRule> createIntRule(int defaultValue, int minimumValue) {
|
||||
return createIntRule(defaultValue, minimumValue, Integer.MAX_VALUE, (server, rule) -> {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an integer rule type.
|
||||
*
|
||||
* @param defaultValue the default value of the game rule
|
||||
* @param minimumValue the minimum value the game rule may accept
|
||||
* @param changedCallback a callback that is invoked when the value of a game rule has changed
|
||||
* @return an integer rule type
|
||||
*/
|
||||
public static GameRules.Type<GameRules.IntRule> createIntRule(int defaultValue, int minimumValue, BiConsumer<MinecraftServer, GameRules.IntRule> changedCallback) {
|
||||
return createIntRule(defaultValue, minimumValue, Integer.MAX_VALUE, changedCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an integer rule type.
|
||||
*
|
||||
* @param defaultValue the default value of the game rule
|
||||
* @param minimumValue the minimum value the game rule may accept
|
||||
* @param maximumValue the maximum value the game rule may accept
|
||||
* @return an integer rule type
|
||||
*/
|
||||
public static GameRules.Type<GameRules.IntRule> createIntRule(int defaultValue, int minimumValue, int maximumValue) {
|
||||
return createIntRule(defaultValue, minimumValue, maximumValue, (server, rule) -> {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an integer rule type.
|
||||
*
|
||||
* @param defaultValue the default value of the game rule
|
||||
* @param changedCallback a callback that is invoked when the value of a game rule has changed
|
||||
* @return an integer rule type
|
||||
*/
|
||||
public static GameRules.Type<GameRules.IntRule> createIntRule(int defaultValue, BiConsumer<MinecraftServer, GameRules.IntRule> changedCallback) {
|
||||
return createIntRule(defaultValue, Integer.MIN_VALUE, Integer.MAX_VALUE, changedCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an integer rule type.
|
||||
*
|
||||
* @param defaultValue the default value of the game rule
|
||||
* @param minimumValue the minimum value the game rule may accept
|
||||
* @param maximumValue the maximum value the game rule may accept
|
||||
* @param changedCallback a callback that is invoked when the value of a game rule has changed
|
||||
* @return an integer rule type
|
||||
*/
|
||||
public static GameRules.Type<GameRules.IntRule> createIntRule(int defaultValue, int minimumValue, int maximumValue, /* @Nullable */ BiConsumer<MinecraftServer, GameRules.IntRule> changedCallback) {
|
||||
return new GameRules.Type<>(
|
||||
() -> IntegerArgumentType.integer(minimumValue, maximumValue),
|
||||
type -> new BoundedIntRule(type, defaultValue, minimumValue, maximumValue), // Internally use a bounded int rule
|
||||
changedCallback,
|
||||
GameRules.Visitor::visitInt
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a double rule type.
|
||||
*
|
||||
* @param defaultValue the default value of the game rule
|
||||
* @return a double rule type
|
||||
*/
|
||||
public static GameRules.Type<DoubleRule> createDoubleRule(double defaultValue) {
|
||||
return createDoubleRule(defaultValue, (server, rule) -> {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a double rule type.
|
||||
*
|
||||
* @param defaultValue the default value of the game rule
|
||||
* @param minimumValue the minimum value the game rule may accept
|
||||
* @return a double rule type
|
||||
*/
|
||||
public static GameRules.Type<DoubleRule> createDoubleRule(double defaultValue, double minimumValue) {
|
||||
return createDoubleRule(defaultValue, minimumValue, Double.MAX_VALUE, (server, rule) -> {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a double rule type.
|
||||
*
|
||||
* @param defaultValue the default value of the game rule
|
||||
* @param minimumValue the minimum value the game rule may accept
|
||||
* @param changedCallback a callback that is invoked when the value of a game rule has changed
|
||||
* @return a double rule type
|
||||
*/
|
||||
public static GameRules.Type<DoubleRule> createDoubleRule(double defaultValue, double minimumValue, BiConsumer<MinecraftServer, DoubleRule> changedCallback) {
|
||||
return createDoubleRule(defaultValue, minimumValue, Double.MAX_VALUE, changedCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a double rule type.
|
||||
*
|
||||
* @param defaultValue the default value of the game rule
|
||||
* @param minimumValue the minimum value the game rule may accept
|
||||
* @param maximumValue the maximum value the game rule may accept
|
||||
* @return a double rule type
|
||||
*/
|
||||
public static GameRules.Type<DoubleRule> createDoubleRule(double defaultValue, double minimumValue, double maximumValue) {
|
||||
return createDoubleRule(defaultValue, minimumValue, maximumValue, (server, rule) -> {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a double rule type.
|
||||
*
|
||||
* @param defaultValue the default value of the game rule
|
||||
* @param changedCallback a callback that is invoked when the value of a game rule has changed
|
||||
* @return a double rule type
|
||||
*/
|
||||
public static GameRules.Type<DoubleRule> createDoubleRule(double defaultValue, BiConsumer<MinecraftServer, DoubleRule> changedCallback) {
|
||||
return createDoubleRule(defaultValue, Double.MIN_VALUE, Double.MAX_VALUE, changedCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a double rule type.
|
||||
*
|
||||
* @param defaultValue the default value of the game rule
|
||||
* @param minimumValue the minimum value the game rule may accept
|
||||
* @param maximumValue the maximum value the game rule may accept
|
||||
* @param changedCallback a callback that is invoked when the value of a game rule has changed
|
||||
* @return a double rule type
|
||||
*/
|
||||
public static GameRules.Type<DoubleRule> createDoubleRule(double defaultValue, double minimumValue, double maximumValue, BiConsumer<MinecraftServer, DoubleRule> changedCallback) {
|
||||
return new GameRules.Type<>(
|
||||
() -> DoubleArgumentType.doubleArg(minimumValue, maximumValue),
|
||||
type -> new DoubleRule(type, defaultValue, minimumValue, maximumValue),
|
||||
changedCallback,
|
||||
GameRuleFactory::visitDouble
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an enum rule type.
|
||||
*
|
||||
* <p>All enum values are supported.
|
||||
*
|
||||
* @param defaultValue the default value of the game rule
|
||||
* @param <E> the type of enum this game rule stores
|
||||
* @return an enum rule type
|
||||
*/
|
||||
public static <E extends Enum<E>> GameRules.Type<EnumRule<E>> createEnumRule(E defaultValue) {
|
||||
return createEnumRule(defaultValue, (server, rule) -> {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an enum rule type.
|
||||
*
|
||||
* <p>All enum values are supported.
|
||||
*
|
||||
* @param defaultValue the default value of the game rule
|
||||
* @param changedCallback a callback that is invoked when the value of a game rule has changed
|
||||
* @param <E> the type of enum this game rule stores
|
||||
* @return an enum rule type
|
||||
*/
|
||||
public static <E extends Enum<E>> GameRules.Type<EnumRule<E>> createEnumRule(E defaultValue, BiConsumer<MinecraftServer, EnumRule<E>> changedCallback) {
|
||||
return createEnumRule(defaultValue, defaultValue.getDeclaringClass().getEnumConstants(), changedCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an enum rule type.
|
||||
*
|
||||
* @param defaultValue the default value of the game rule
|
||||
* @param supportedValues the values the game rule may support
|
||||
* @param <E> the type of enum this game rule stores
|
||||
* @return an enum rule type
|
||||
*/
|
||||
public static <E extends Enum<E>> GameRules.Type<EnumRule<E>> createEnumRule(E defaultValue, E[] supportedValues) {
|
||||
return createEnumRule(defaultValue, supportedValues, (server, rule) -> {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an enum rule type.
|
||||
*
|
||||
* @param defaultValue the default value of the game rule
|
||||
* @param supportedValues the values the game rule may support
|
||||
* @param changedCallback a callback that is invoked when the value of a game rule has changed.
|
||||
* @param <E> the type of enum this game rule stores
|
||||
* @return an enum rule type
|
||||
*/
|
||||
public static <E extends Enum<E>> GameRules.Type<EnumRule<E>> createEnumRule(E defaultValue, E[] supportedValues, BiConsumer<MinecraftServer, EnumRule<E>> changedCallback) {
|
||||
checkNotNull(defaultValue, "Default rule value cannot be null");
|
||||
checkNotNull(supportedValues, "Supported Values cannot be null");
|
||||
|
||||
if (supportedValues.length == 0) {
|
||||
throw new IllegalArgumentException("Cannot register an enum rule where no values are supported");
|
||||
}
|
||||
|
||||
return new EnumRuleType<>(
|
||||
type -> new EnumRule<>(type, defaultValue, supportedValues),
|
||||
changedCallback,
|
||||
supportedValues,
|
||||
GameRuleFactory::visitEnum
|
||||
);
|
||||
}
|
||||
|
||||
// RULE VISITORS - INTERNAL
|
||||
|
||||
private static void visitDouble(GameRules.Visitor visitor, GameRules.Key<DoubleRule> key, GameRules.Type<DoubleRule> type) {
|
||||
if (visitor instanceof FabricGameRuleVisitor) {
|
||||
((FabricGameRuleVisitor) visitor).visitDouble(key, type);
|
||||
}
|
||||
}
|
||||
|
||||
private static <E extends Enum<E>> void visitEnum(GameRules.Visitor visitor, GameRules.Key<EnumRule<E>> key, GameRules.Type<EnumRule<E>> type) {
|
||||
if (visitor instanceof FabricGameRuleVisitor) {
|
||||
((FabricGameRuleVisitor) visitor).visitEnum(key, type);
|
||||
}
|
||||
}
|
||||
|
||||
private GameRuleFactory() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.gamerule.v1;
|
||||
|
||||
import net.minecraft.world.GameRules;
|
||||
|
||||
import net.fabricmc.fabric.impl.gamerule.RuleKeyExtensions;
|
||||
import net.fabricmc.fabric.mixin.gamerule.GameRulesAccessor;
|
||||
|
||||
/**
|
||||
* A utility class which allows for registration of game rules.
|
||||
* Note game rules with duplicate keys are not allowed.
|
||||
* Checking if a game rule key is already taken can be done using {@link GameRuleRegistry#hasRegistration(String)}.
|
||||
*
|
||||
* <p>Creation of rule types is done using {@link GameRuleFactory}.
|
||||
*
|
||||
* @see GameRuleFactory
|
||||
*/
|
||||
public final class GameRuleRegistry {
|
||||
private GameRuleRegistry() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a {@link GameRules.Rule}.
|
||||
*
|
||||
* @param name the name of the rule
|
||||
* @param category the category of this rule
|
||||
* @param type the rule type
|
||||
* @param <T> the type of rule
|
||||
* @return a rule key which can be used to query the value of the rule
|
||||
* @throws IllegalStateException if a rule of the same name already exists
|
||||
*/
|
||||
public static <T extends GameRules.Rule<T>> GameRules.Key<T> register(String name, GameRules.Category category, GameRules.Type<T> type) {
|
||||
return GameRulesAccessor.callRegister(name, category, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a {@link GameRules.Rule} with a custom category.
|
||||
*
|
||||
* @param name the name of the rule
|
||||
* @param category the category of this rule
|
||||
* @param type the rule type
|
||||
* @param <T> the type of rule
|
||||
* @return a rule key which can be used to query the value of the rule
|
||||
* @throws IllegalStateException if a rule of the same name already exists
|
||||
*/
|
||||
public static <T extends GameRules.Rule<T>> GameRules.Key<T> register(String name, CustomGameRuleCategory category, GameRules.Type<T> type) {
|
||||
final GameRules.Key<T> key = GameRulesAccessor.callRegister(name, GameRules.Category.MISC, type);
|
||||
((RuleKeyExtensions) (Object) key).fabric_setCustomCategory(category);
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a name for a game rule is already registered.
|
||||
*
|
||||
* @param ruleName the rule name to test
|
||||
* @return true if the name is taken.
|
||||
*/
|
||||
public static boolean hasRegistration(String ruleName) {
|
||||
return GameRulesAccessor.getRuleTypes().keySet().stream().anyMatch(key -> key.getName().equals(ruleName));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.gamerule.v1.rule;
|
||||
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.world.GameRules;
|
||||
|
||||
import net.fabricmc.fabric.api.gamerule.v1.GameRuleRegistry;
|
||||
|
||||
public final class DoubleRule extends GameRules.Rule<DoubleRule> implements ValidateableRule {
|
||||
private static final Logger LOGGER = LogManager.getLogger(GameRuleRegistry.class);
|
||||
|
||||
private final double minimumValue;
|
||||
private final double maximumValue;
|
||||
private double value;
|
||||
|
||||
/**
|
||||
* @deprecated You should not be calling this constructor!
|
||||
*/
|
||||
@Deprecated
|
||||
public DoubleRule(GameRules.Type<DoubleRule> type, double value, double minimumValue, double maximumValue) {
|
||||
super(type);
|
||||
this.value = value;
|
||||
this.minimumValue = minimumValue;
|
||||
this.maximumValue = maximumValue;
|
||||
|
||||
if (Double.isInfinite(value) || Double.isNaN(value)) {
|
||||
throw new IllegalArgumentException("Value cannot be infinite or NaN");
|
||||
}
|
||||
|
||||
if (Double.isInfinite(minimumValue) || Double.isNaN(minimumValue)) {
|
||||
throw new IllegalArgumentException("Minimum value cannot be infinite or NaN");
|
||||
}
|
||||
|
||||
if (Double.isInfinite(maximumValue) || Double.isNaN(maximumValue)) {
|
||||
throw new IllegalArgumentException("Maximum value cannot be infinite or NaN");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setFromArgument(CommandContext<ServerCommandSource> context, String name) {
|
||||
this.value = context.getArgument(name, Double.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deserialize(String value) {
|
||||
if (!value.isEmpty()) {
|
||||
try {
|
||||
final double d = Double.parseDouble(value);
|
||||
|
||||
if (this.inBounds(d)) {
|
||||
this.value = d;
|
||||
} else {
|
||||
LOGGER.warn("Failed to parse double {}. Was out of bounds {} - {}", value, this.minimumValue, this.maximumValue);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
LOGGER.warn("Failed to parse double {}", value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String serialize() {
|
||||
return Double.toString(this.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCommandResult() {
|
||||
return Double.compare(this.value, 0.0D);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DoubleRule getThis() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DoubleRule copy() {
|
||||
return new DoubleRule(this.type, this.value, this.minimumValue, this.maximumValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(DoubleRule rule, MinecraftServer minecraftServer) {
|
||||
if (!this.inBounds(rule.value)) {
|
||||
throw new IllegalArgumentException(String.format("Could not set value to %s. Was out of bounds %s - %s", rule.value, this.minimumValue, this.maximumValue));
|
||||
}
|
||||
|
||||
this.value = rule.value;
|
||||
this.changed(minecraftServer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(String value) {
|
||||
try {
|
||||
final double d = Double.parseDouble(value);
|
||||
|
||||
return this.inBounds(d);
|
||||
} catch (NumberFormatException ignored) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public double get() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
private boolean inBounds(double value) {
|
||||
return value >= this.minimumValue && value <= this.maximumValue;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.gamerule.v1.rule;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.world.GameRules;
|
||||
|
||||
import net.fabricmc.fabric.api.gamerule.v1.GameRuleRegistry;
|
||||
|
||||
public final class EnumRule<E extends Enum<E>> extends GameRules.Rule<EnumRule<E>> {
|
||||
private static final Logger LOGGER = LogManager.getLogger(GameRuleRegistry.class);
|
||||
|
||||
private final Class<E> classType;
|
||||
private final List<E> supportedValues;
|
||||
private E value;
|
||||
|
||||
/**
|
||||
* @deprecated You should not be calling this constructor!
|
||||
*/
|
||||
@Deprecated
|
||||
public EnumRule(GameRules.Type<EnumRule<E>> type, E value, E[] supportedValues) {
|
||||
this(type, value, Arrays.asList(supportedValues));
|
||||
}
|
||||
|
||||
/**
|
||||
* You should not be calling this constructor!
|
||||
*/
|
||||
@Deprecated
|
||||
public EnumRule(GameRules.Type<EnumRule<E>> type, E value, Collection<E> supportedValues) {
|
||||
super(type);
|
||||
this.classType = value.getDeclaringClass();
|
||||
this.value = value;
|
||||
this.supportedValues = new ArrayList<>(supportedValues);
|
||||
|
||||
if (!this.supports(value)) {
|
||||
throw new IllegalArgumentException("Cannot set default value");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setFromArgument(CommandContext<ServerCommandSource> context, String name) {
|
||||
// Do nothing. We use a different system for application with literals
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deserialize(String value) {
|
||||
try {
|
||||
final E deserialized = Enum.valueOf(this.classType, value);
|
||||
|
||||
if (!this.supports(deserialized)) {
|
||||
LOGGER.warn("Failed to parse rule of value {} for rule of type {}. Since the value {}, is unsupported.", value, this.classType, value);
|
||||
}
|
||||
|
||||
this.set(deserialized, null);
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOGGER.warn("Failed to parse rule of value {} for rule of type {}", value, this.classType);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String serialize() {
|
||||
return this.value.name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCommandResult() {
|
||||
// For now we are gonna use the ordinal as the command result. Could be changed or set to relate to something else entirely.
|
||||
return this.value.ordinal();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EnumRule<E> getThis() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Class<E> getEnumClass() {
|
||||
return this.classType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.value.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EnumRule<E> copy() {
|
||||
return new EnumRule<>(this.type, this.value, this.supportedValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(EnumRule<E> rule, MinecraftServer minecraftServer) {
|
||||
if (!this.supports(rule.value)) {
|
||||
throw new IllegalArgumentException(String.format("Rule does not support value: %s", rule.value));
|
||||
}
|
||||
|
||||
this.value = rule.value;
|
||||
this.changed(minecraftServer);
|
||||
}
|
||||
|
||||
public E get() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cycles the value of this enum rule to the next supported value.
|
||||
*/
|
||||
public void cycle() {
|
||||
int index = this.supportedValues.indexOf(this.value);
|
||||
|
||||
if (index < 0) {
|
||||
throw new IllegalArgumentException(String.format("Invalid value: %s", this.value));
|
||||
}
|
||||
|
||||
this.set(this.supportedValues.get((index + 1) % this.supportedValues.size()), null);
|
||||
}
|
||||
|
||||
public boolean supports(E value) {
|
||||
return this.supportedValues.contains(value);
|
||||
}
|
||||
|
||||
public void set(E value, /* @Nullable */ MinecraftServer server) throws IllegalArgumentException {
|
||||
checkNotNull(value);
|
||||
|
||||
if (!this.supports(value)) {
|
||||
throw new IllegalArgumentException("Tried to set an unsupported value: " + value.toString());
|
||||
}
|
||||
|
||||
this.value = value;
|
||||
this.changed(server);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.gamerule.v1.rule;
|
||||
|
||||
/**
|
||||
* A type of game rule which can validate an input.
|
||||
* This can be used to enforce syntax or clamp values.
|
||||
*/
|
||||
public interface ValidateableRule {
|
||||
/**
|
||||
* Validates if a rule can accept the input.
|
||||
*
|
||||
* @param value the value to validate
|
||||
* @return true if the value can be accepted.
|
||||
*/
|
||||
boolean validate(String value);
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.impl.gamerule;
|
||||
|
||||
import static net.minecraft.server.command.CommandManager.literal;
|
||||
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
|
||||
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.text.TranslatableText;
|
||||
import net.minecraft.world.GameRules;
|
||||
|
||||
import net.fabricmc.fabric.api.gamerule.v1.rule.EnumRule;
|
||||
import net.fabricmc.fabric.mixin.gamerule.GameRuleCommandAccessor;
|
||||
|
||||
public final class EnumRuleCommand {
|
||||
public static <E extends Enum<E>> void register(LiteralArgumentBuilder<ServerCommandSource> literalArgumentBuilder, GameRules.Key<EnumRule<E>> key, EnumRuleType<E> type) {
|
||||
literalArgumentBuilder.then(literal(key.getName()).executes(context -> {
|
||||
// We can use the vanilla query method
|
||||
return GameRuleCommandAccessor.invokeExecuteQuery(context.getSource(), key);
|
||||
}));
|
||||
|
||||
// The LiteralRuleType handles the executeSet
|
||||
type.register(literalArgumentBuilder, key);
|
||||
}
|
||||
|
||||
public static <E extends Enum<E>> int executeAndSetEnum(CommandContext<ServerCommandSource> context, E value, GameRules.Key<EnumRule<E>> key) throws CommandSyntaxException {
|
||||
// Mostly copied from vanilla, but tweaked so we can use literals
|
||||
ServerCommandSource serverCommandSource = context.getSource();
|
||||
EnumRule<E> rule = serverCommandSource.getMinecraftServer().getGameRules().get(key);
|
||||
|
||||
try {
|
||||
rule.set(value, serverCommandSource.getMinecraftServer());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new SimpleCommandExceptionType(new LiteralText(e.getMessage())).create();
|
||||
}
|
||||
|
||||
serverCommandSource.sendFeedback(new TranslatableText("commands.gamerule.set", key.getName(), rule.toString()), true);
|
||||
return rule.getCommandResult();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.impl.gamerule;
|
||||
|
||||
import static net.minecraft.server.command.CommandManager.literal;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
||||
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.world.GameRules;
|
||||
|
||||
import net.fabricmc.fabric.api.gamerule.v1.rule.EnumRule;
|
||||
|
||||
public final class EnumRuleType<E extends Enum<E>> extends GameRules.Type<EnumRule<E>> {
|
||||
private final E[] supportedValues;
|
||||
|
||||
public EnumRuleType(Function<GameRules.Type<EnumRule<E>>, EnumRule<E>> ruleFactory, BiConsumer<MinecraftServer, EnumRule<E>> changeCallback, E[] supportedValues, GameRules.Acceptor<EnumRule<E>> acceptor) {
|
||||
super(null, ruleFactory, changeCallback, acceptor);
|
||||
this.supportedValues = supportedValues;
|
||||
}
|
||||
|
||||
public void register(LiteralArgumentBuilder<ServerCommandSource> literalArgumentBuilder, GameRules.Key<EnumRule<E>> key) {
|
||||
LiteralCommandNode<ServerCommandSource> ruleNode = literal(key.getName()).build();
|
||||
|
||||
for (E supportedValue : this.supportedValues) {
|
||||
ruleNode.addChild(literal(supportedValue.toString()).executes(context -> EnumRuleCommand.executeAndSetEnum(context, supportedValue, key)).build());
|
||||
}
|
||||
|
||||
literalArgumentBuilder.then(ruleNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public RequiredArgumentBuilder<ServerCommandSource, ?> argument(String name) {
|
||||
return super.argument(name);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.impl.gamerule;
|
||||
|
||||
import net.fabricmc.fabric.api.gamerule.v1.CustomGameRuleCategory;
|
||||
|
||||
public interface RuleKeyExtensions {
|
||||
/* @Nullable */
|
||||
CustomGameRuleCategory fabric_getCustomCategory();
|
||||
|
||||
void fabric_setCustomCategory(CustomGameRuleCategory customCategory);
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.impl.gamerule.rule;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import net.minecraft.world.GameRules;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.gamerule.v1.GameRuleRegistry;
|
||||
import net.fabricmc.fabric.mixin.gamerule.IntRuleAccessor;
|
||||
|
||||
public final class BoundedIntRule extends GameRules.IntRule {
|
||||
private static final Logger LOGGER = LogManager.getLogger(GameRuleRegistry.class);
|
||||
|
||||
private final int minimumValue;
|
||||
private final int maximumValue;
|
||||
|
||||
public BoundedIntRule(GameRules.Type<GameRules.IntRule> type, int initialValue, int minimumValue, int maximumValue) {
|
||||
super(type, initialValue);
|
||||
this.minimumValue = minimumValue;
|
||||
this.maximumValue = maximumValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deserialize(String value) {
|
||||
final int i = BoundedIntRule.parseInt(value);
|
||||
|
||||
if (this.minimumValue > i || this.maximumValue < i) {
|
||||
LOGGER.warn("Failed to parse integer {}. Was out of bounds {} - {}", value, this.minimumValue, this.maximumValue);
|
||||
return;
|
||||
}
|
||||
|
||||
((IntRuleAccessor) (Object) this).setValue(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Environment(EnvType.CLIENT)
|
||||
public boolean validate(String input) {
|
||||
try {
|
||||
int value = Integer.parseInt(input);
|
||||
|
||||
if (this.minimumValue > value || this.maximumValue < value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
((IntRuleAccessor) (Object) this).setValue(value);
|
||||
return true;
|
||||
} catch (NumberFormatException var3) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GameRules.IntRule copy() {
|
||||
return new BoundedIntRule(this.type, ((IntRuleAccessor) (Object) this).getValue(), this.minimumValue, this.maximumValue);
|
||||
}
|
||||
|
||||
private static int parseInt(String input) {
|
||||
if (!input.isEmpty()) {
|
||||
try {
|
||||
return Integer.parseInt(input);
|
||||
} catch (NumberFormatException var2) {
|
||||
LOGGER.warn("Failed to parse integer {}", input);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.impl.gamerule.widget;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.class_5481;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.world.EditGameRulesScreen;
|
||||
import net.minecraft.client.gui.widget.TextFieldWidget;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.gamerule.v1.rule.DoubleRule;
|
||||
import net.fabricmc.fabric.mixin.gamerule.client.EditGameRulesScreenAccessor;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public final class DoubleRuleWidget extends EditGameRulesScreen.NamedRuleWidget {
|
||||
private final TextFieldWidget textFieldWidget;
|
||||
|
||||
public DoubleRuleWidget(EditGameRulesScreen gameRuleScreen, Text name, List<class_5481> description, final String ruleName, DoubleRule rule) {
|
||||
gameRuleScreen.super(description, name);
|
||||
EditGameRulesScreenAccessor accessor = (EditGameRulesScreenAccessor) gameRuleScreen;
|
||||
|
||||
this.textFieldWidget = new TextFieldWidget(MinecraftClient.getInstance().textRenderer, 10, 5, 42, 20,
|
||||
name.shallowCopy()
|
||||
.append("\n")
|
||||
.append(ruleName)
|
||||
.append("\n")
|
||||
);
|
||||
|
||||
this.textFieldWidget.setText(Double.toString(rule.get()));
|
||||
this.textFieldWidget.setChangedListener(value -> {
|
||||
if (rule.validate(value)) {
|
||||
this.textFieldWidget.setEditableColor(0xE0E0E0);
|
||||
accessor.callMarkValid(this);
|
||||
} else {
|
||||
this.textFieldWidget.setEditableColor(0xFF0000);
|
||||
accessor.callMarkInvalid(this);
|
||||
}
|
||||
});
|
||||
|
||||
this.children.add(this.textFieldWidget);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(MatrixStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) {
|
||||
// FIXME: Param names nightmare
|
||||
this.drawName(matrices, y, x);
|
||||
|
||||
this.textFieldWidget.x = x + entryWidth - 44;
|
||||
this.textFieldWidget.y = y;
|
||||
this.textFieldWidget.render(matrices, mouseX, mouseY, tickDelta);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.impl.gamerule.widget;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import net.minecraft.class_5481;
|
||||
import net.minecraft.client.gui.screen.world.EditGameRulesScreen;
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.client.resource.language.I18n;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.text.TranslatableText;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.gamerule.v1.rule.EnumRule;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public final class EnumRuleWidget<E extends Enum<E>> extends EditGameRulesScreen.NamedRuleWidget {
|
||||
private final ButtonWidget buttonWidget;
|
||||
private final String rootTranslationKey;
|
||||
|
||||
public EnumRuleWidget(EditGameRulesScreen gameRuleScreen, Text name, List<class_5481> description, final String ruleName, EnumRule<E> rule, String translationKey) {
|
||||
gameRuleScreen.super(description, name);
|
||||
|
||||
// Base translation key needs to be set before the button widget is created.
|
||||
this.rootTranslationKey = translationKey;
|
||||
this.buttonWidget = new ButtonWidget(10, 5, 88, 20, this.getValueText(rule.get()), (buttonWidget) -> {
|
||||
rule.cycle();
|
||||
buttonWidget.setMessage(this.getValueText(rule.get()));
|
||||
});
|
||||
|
||||
this.children.add(this.buttonWidget);
|
||||
}
|
||||
|
||||
public Text getValueText(E value) {
|
||||
final String key = this.rootTranslationKey + "." + value.name().toLowerCase(Locale.ROOT);
|
||||
|
||||
if (I18n.hasTranslation(key)) {
|
||||
return new TranslatableText(key);
|
||||
}
|
||||
|
||||
return new LiteralText(value.toString());
|
||||
}
|
||||
|
||||
public void render(MatrixStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) {
|
||||
// FIXME: Param names nightmare
|
||||
this.drawName(matrices, y, x);
|
||||
|
||||
this.buttonWidget.x = x + entryWidth - 89;
|
||||
this.buttonWidget.y = y;
|
||||
this.buttonWidget.render(matrices, mouseX, mouseY, tickDelta);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.gamerule;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.world.GameRules;
|
||||
|
||||
@Mixin(GameRules.BooleanRule.class)
|
||||
public interface BooleanRuleAccessor {
|
||||
@Invoker
|
||||
static GameRules.Type<GameRules.BooleanRule> invokeCreate(boolean initialValue, BiConsumer<MinecraftServer, GameRules.BooleanRule> changeCallback) {
|
||||
throw new AssertionError("This shouldn't happen!");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.gamerule;
|
||||
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
import net.minecraft.server.command.GameRuleCommand;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.world.GameRules;
|
||||
|
||||
@Mixin(GameRuleCommand.class)
|
||||
public interface GameRuleCommandAccessor {
|
||||
@Invoker
|
||||
static <T extends GameRules.Rule<T>> int invokeExecuteSet(CommandContext<ServerCommandSource> commandContext, GameRules.Key<T> ruleKey) {
|
||||
throw new AssertionError("This shouldn't happen!");
|
||||
}
|
||||
|
||||
@Invoker
|
||||
static <T extends GameRules.Rule<T>> int invokeExecuteQuery(ServerCommandSource serverCommandSource, GameRules.Key<T> ruleKey) {
|
||||
throw new AssertionError("This shouldn't happen!");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.gamerule;
|
||||
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.world.GameRules;
|
||||
|
||||
import net.fabricmc.fabric.impl.gamerule.EnumRuleCommand;
|
||||
import net.fabricmc.fabric.impl.gamerule.EnumRuleType;
|
||||
|
||||
@Mixin(targets = "net/minecraft/server/command/GameRuleCommand$1")
|
||||
public abstract class GameRuleCommandVisitorMixin {
|
||||
@Shadow
|
||||
private LiteralArgumentBuilder<ServerCommandSource> field_19419;
|
||||
|
||||
@Inject(at = @At("HEAD"), method = "visit(Lnet/minecraft/world/GameRules$Key;Lnet/minecraft/world/GameRules$Type;)V", cancellable = true)
|
||||
private <T extends GameRules.Rule<T>> void onRegisterCommand(GameRules.Key<T> key, GameRules.Type<T> type, CallbackInfo ci) {
|
||||
// Check if our type is a EnumRuleType
|
||||
if (type instanceof EnumRuleType) {
|
||||
//noinspection rawtypes,unchecked
|
||||
EnumRuleCommand.register(this.field_19419, (GameRules.Key) key, (EnumRuleType) type);
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.gamerule;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
import net.minecraft.world.GameRules;
|
||||
|
||||
@Mixin(GameRules.class)
|
||||
public interface GameRulesAccessor {
|
||||
@Invoker("register")
|
||||
static <T extends GameRules.Rule<T>> GameRules.Key<T> callRegister(String name, GameRules.Category category, GameRules.Type<T> type) {
|
||||
throw new AssertionError("This shouldn't happen!");
|
||||
}
|
||||
|
||||
@Accessor("RULE_TYPES")
|
||||
static Map<GameRules.Key<?>, GameRules.Type<?>> getRuleTypes() {
|
||||
throw new AssertionError("This shouldn't happen!");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.gamerule;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import net.minecraft.world.GameRules;
|
||||
|
||||
@Mixin(GameRules.IntRule.class)
|
||||
public interface IntRuleAccessor {
|
||||
@Accessor
|
||||
int getValue();
|
||||
|
||||
@Accessor
|
||||
void setValue(int value);
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.gamerule;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
|
||||
import net.minecraft.world.GameRules;
|
||||
|
||||
import net.fabricmc.fabric.api.gamerule.v1.CustomGameRuleCategory;
|
||||
import net.fabricmc.fabric.impl.gamerule.RuleKeyExtensions;
|
||||
|
||||
@Mixin(GameRules.Key.class)
|
||||
public abstract class RuleKeyMixin implements RuleKeyExtensions {
|
||||
/* @Nullable */
|
||||
@Unique
|
||||
private CustomGameRuleCategory customCategory;
|
||||
|
||||
@Override
|
||||
public CustomGameRuleCategory fabric_getCustomCategory() {
|
||||
return this.customCategory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fabric_setCustomCategory(CustomGameRuleCategory customCategory) {
|
||||
this.customCategory = customCategory;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.gamerule.client;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
import net.minecraft.client.gui.screen.world.EditGameRulesScreen;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
|
||||
@Mixin(EditGameRulesScreen.class)
|
||||
@Environment(EnvType.CLIENT)
|
||||
public interface EditGameRulesScreenAccessor {
|
||||
@Invoker("markValid")
|
||||
void callMarkValid(EditGameRulesScreen.AbstractRuleWidget ruleWidget);
|
||||
|
||||
@Invoker("markInvalid")
|
||||
void callMarkInvalid(EditGameRulesScreen.AbstractRuleWidget ruleWidget);
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.gamerule.client;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.world.EditGameRulesScreen;
|
||||
import net.minecraft.world.GameRules;
|
||||
|
||||
import net.fabricmc.fabric.api.gamerule.v1.CustomGameRuleCategory;
|
||||
|
||||
@Mixin(EditGameRulesScreen.RuleListWidget.class)
|
||||
public abstract class RuleListWidgetMixin extends net.minecraft.client.gui.widget.EntryListWidget<EditGameRulesScreen.AbstractRuleWidget> {
|
||||
@Unique
|
||||
private final Map<CustomGameRuleCategory, List<EditGameRulesScreen.AbstractRuleWidget>> fabricCategories = new HashMap<>();
|
||||
|
||||
public RuleListWidgetMixin(MinecraftClient client, int width, int height, int top, int bottom, int itemHeight) {
|
||||
super(client, width, height, top, bottom, itemHeight);
|
||||
}
|
||||
|
||||
@Inject(method = "<init>(Lnet/minecraft/world/GameRules;)V", at = @At("TAIL"))
|
||||
private void initializeFabricGameruleCategories(EditGameRulesScreen screen, GameRules gameRules, CallbackInfo ci) {
|
||||
this.fabricCategories.forEach((category, widgetList) -> {
|
||||
this.addEntry(screen.new RuleCategoryWidget(category.getName()));
|
||||
|
||||
for (EditGameRulesScreen.AbstractRuleWidget widget : widgetList) {
|
||||
this.addEntry(widget);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Inject(method = "method_27638(Ljava/util/Map$Entry;)V", at = @At("HEAD"), cancellable = true)
|
||||
private void ignoreKeysWithCustomCategories(Map.Entry<GameRules.Key<?>, EditGameRulesScreen.AbstractRuleWidget> entry, CallbackInfo ci) {
|
||||
final GameRules.Key<?> ruleKey = entry.getKey();
|
||||
CustomGameRuleCategory.getCategory(ruleKey).ifPresent(key -> {
|
||||
this.fabricCategories.computeIfAbsent(key, c -> new ArrayList<>()).add(entry.getValue());
|
||||
ci.cancel();
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.gamerule.client;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
import net.minecraft.client.gui.screen.world.EditGameRulesScreen;
|
||||
import net.minecraft.client.resource.language.I18n;
|
||||
import net.minecraft.world.GameRules;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.gamerule.v1.FabricGameRuleVisitor;
|
||||
import net.fabricmc.fabric.api.gamerule.v1.rule.DoubleRule;
|
||||
import net.fabricmc.fabric.api.gamerule.v1.rule.EnumRule;
|
||||
import net.fabricmc.fabric.impl.gamerule.widget.DoubleRuleWidget;
|
||||
import net.fabricmc.fabric.impl.gamerule.widget.EnumRuleWidget;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@Mixin(targets = "net/minecraft/client/gui/screen/world/EditGameRulesScreen$RuleListWidget$1")
|
||||
public abstract class RuleListWidgetVisitorMixin implements GameRules.Visitor, FabricGameRuleVisitor {
|
||||
@Final
|
||||
@Shadow
|
||||
private EditGameRulesScreen field_24314;
|
||||
@Shadow
|
||||
protected abstract <T extends GameRules.Rule<T>> void createRuleWidget(GameRules.Key<T> key, EditGameRulesScreen.RuleWidgetFactory<T> ruleWidgetFactory);
|
||||
|
||||
@Override
|
||||
public void visitDouble(GameRules.Key<DoubleRule> key, GameRules.Type<DoubleRule> type) {
|
||||
this.createRuleWidget(key, (name, description, ruleName, rule) -> {
|
||||
return new DoubleRuleWidget(this.field_24314, name, description, ruleName, rule);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public <E extends Enum<E>> void visitEnum(GameRules.Key<EnumRule<E>> key, GameRules.Type<EnumRule<E>> type) {
|
||||
this.createRuleWidget(key, (name, description, ruleName, rule) -> {
|
||||
return new EnumRuleWidget<>(this.field_24314, name, description, ruleName, rule, key.getTranslationKey());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason We need to display an enum rule's default value as translated.
|
||||
*/
|
||||
@Redirect(at = @At(value = "INVOKE", target = "Lnet/minecraft/world/GameRules$Rule;serialize()Ljava/lang/String;"), method = "createRuleWidget")
|
||||
private <T extends GameRules.Rule<T>> String displayProperEnumName(GameRules.Rule<T> rule, GameRules.Key<T> key, EditGameRulesScreen.RuleWidgetFactory<T> widgetFactory) {
|
||||
if (rule instanceof EnumRule) {
|
||||
String translationKey = key.getTranslationKey() + "." + ((EnumRule<?>) rule).get().name().toLowerCase(Locale.ROOT);
|
||||
|
||||
if (I18n.hasTranslation(translationKey)) {
|
||||
return I18n.translate(translationKey);
|
||||
}
|
||||
|
||||
return ((EnumRule<?>) rule).get().toString();
|
||||
}
|
||||
|
||||
return rule.serialize();
|
||||
}
|
||||
}
|
Binary file not shown.
After ![]() (image error) Size: 1.5 KiB |
|
@ -0,0 +1,5 @@
|
|||
accessWidener v1 named
|
||||
accessible method net/minecraft/world/GameRules$Type <init> (Ljava/util/function/Supplier;Ljava/util/function/Function;Ljava/util/function/BiConsumer;Lnet/minecraft/world/GameRules$Acceptor;)V
|
||||
extendable method net/minecraft/world/GameRules$Type <init> (Ljava/util/function/Supplier;Ljava/util/function/Function;Ljava/util/function/BiConsumer;Lnet/minecraft/world/GameRules$Acceptor;)V
|
||||
accessible class net/minecraft/world/GameRules$Acceptor
|
||||
accessible class net/minecraft/client/gui/screen/world/EditGameRulesScreen$RuleWidgetFactory
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"required": true,
|
||||
"package": "net.fabricmc.fabric.mixin.gamerule",
|
||||
"compatibilityLevel": "JAVA_8",
|
||||
"mixins": [
|
||||
"BooleanRuleAccessor",
|
||||
"GameRuleCommandAccessor",
|
||||
"GameRuleCommandVisitorMixin",
|
||||
"GameRulesAccessor",
|
||||
"IntRuleAccessor",
|
||||
"RuleKeyMixin"
|
||||
],
|
||||
"client": [
|
||||
"client.EditGameRulesScreenAccessor",
|
||||
"client.RuleListWidgetMixin",
|
||||
"client.RuleListWidgetVisitorMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
26
fabric-game-rule-api-v1/src/main/resources/fabric.mod.json
Normal file
26
fabric-game-rule-api-v1/src/main/resources/fabric.mod.json
Normal file
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "fabric-game-rule-api-v1",
|
||||
"name": "Fabric Game Rule API (v1)",
|
||||
"version": "${version}",
|
||||
"environment": "*",
|
||||
"license": "Apache-2.0",
|
||||
"icon": "assets/fabric-game-rule-api-v1/icon.png",
|
||||
"contact": {
|
||||
"homepage": "https://fabricmc.net",
|
||||
"irc": "irc://irc.esper.net:6667/fabric",
|
||||
"issues": "https://github.com/FabricMC/fabric/issues",
|
||||
"sources": "https://github.com/FabricMC/fabric"
|
||||
},
|
||||
"authors": [
|
||||
"FabricMC"
|
||||
],
|
||||
"depends": {
|
||||
"fabricloader": ">=0.8.2"
|
||||
},
|
||||
"description": "Allows registration of custom game rules.",
|
||||
"mixins": [
|
||||
"fabric-game-rule-api-v1.mixins.json"
|
||||
],
|
||||
"accessWidener" : "fabric-game-rule-api-v1.accesswidener"
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.test.gamerule;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import com.mojang.brigadier.tree.CommandNode;
|
||||
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||
import com.mojang.brigadier.tree.RootCommandNode;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.util.Formatting;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.world.GameRules;
|
||||
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
import net.fabricmc.fabric.api.gamerule.v1.CustomGameRuleCategory;
|
||||
import net.fabricmc.fabric.api.gamerule.v1.GameRuleRegistry;
|
||||
import net.fabricmc.fabric.api.gamerule.v1.GameRuleFactory;
|
||||
import net.fabricmc.fabric.api.gamerule.v1.rule.DoubleRule;
|
||||
import net.fabricmc.fabric.api.gamerule.v1.rule.EnumRule;
|
||||
|
||||
public class GameRulesTestMod implements ModInitializer {
|
||||
private static final Logger LOGGER = LogManager.getLogger(GameRulesTestMod.class);
|
||||
private static final Direction[] CARDINAL_DIRECTIONS = Arrays.stream(Direction.values()).filter(direction -> direction != Direction.UP && direction != Direction.DOWN).toArray(Direction[]::new);
|
||||
public static final CustomGameRuleCategory GREEN_CATEGORY = new CustomGameRuleCategory(new Identifier("fabric", "green"), new LiteralText("This One is Green").styled(style -> style.withBold(true).withColor(Formatting.DARK_GREEN)));
|
||||
public static final CustomGameRuleCategory RED_CATEGORY = new CustomGameRuleCategory(new Identifier("fabric", "red"), new LiteralText("This One is Red").styled(style -> style.withBold(true).withColor(Formatting.DARK_RED)));
|
||||
|
||||
// Bounded, Integer, Double and Float rules
|
||||
public static final GameRules.Key<GameRules.IntRule> POSITIVE_ONLY_TEST_INT = register("positiveOnlyTestInteger", GameRules.Category.UPDATES, GameRuleFactory.createIntRule(2, 0));
|
||||
public static final GameRules.Key<DoubleRule> ONE_TO_TEN_DOUBLE = register("oneToTenDouble", GameRules.Category.MISC, GameRuleFactory.createDoubleRule(1.0D, 1.0D, 10.0D));
|
||||
|
||||
// Test enum rule, with only some supported values.
|
||||
public static final GameRules.Key<EnumRule<Direction>> CARDINAL_DIRECTION_ENUM = register("cardinalDirection", GameRules.Category.MISC, GameRuleFactory.createEnumRule(Direction.NORTH, CARDINAL_DIRECTIONS, (server, rule) -> {
|
||||
LOGGER.info("Changed rule value to {}", rule.get());
|
||||
}));
|
||||
|
||||
// Rules in custom categories
|
||||
public static final GameRules.Key<GameRules.BooleanRule> RED_BOOLEAN = register("redBoolean", RED_CATEGORY, GameRuleFactory.createBooleanRule(true));
|
||||
public static final GameRules.Key<GameRules.BooleanRule> GREEN_BOOLEAN = register("greenBoolean", GREEN_CATEGORY, GameRuleFactory.createBooleanRule(false));
|
||||
|
||||
// An enum rule with no "toString" logic
|
||||
public static final GameRules.Key<EnumRule<PlayerEntity.SleepFailureReason>> RED_SLEEP_FAILURE_ENUM = register("redSleepFailureEnum", RED_CATEGORY, GameRuleFactory.createEnumRule(PlayerEntity.SleepFailureReason.NOT_POSSIBLE_HERE));
|
||||
|
||||
private static <T extends GameRules.Rule<T>> GameRules.Key<T> register(String name, GameRules.Category category, GameRules.Type<T> type) {
|
||||
return GameRuleRegistry.register(name, category, type);
|
||||
}
|
||||
|
||||
private static <T extends GameRules.Rule<T>> GameRules.Key<T> register(String name, CustomGameRuleCategory category, GameRules.Type<T> type) {
|
||||
return GameRuleRegistry.register(name, category, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
LOGGER.info("Loading GameRules test mod.");
|
||||
|
||||
// Test a vanilla rule
|
||||
if (!GameRuleRegistry.hasRegistration("keepInventory")) {
|
||||
throw new AssertionError("Expected to find \"keepInventory\" already registered, but it was not detected as registered");
|
||||
}
|
||||
|
||||
// Test our own rule
|
||||
if (!GameRuleRegistry.hasRegistration("redSleepFailureEnum")) {
|
||||
throw new AssertionError("Expected to find \"redSleepFailureEnum\" already registered, but it was not detected as registered");
|
||||
}
|
||||
|
||||
LOGGER.info("Loaded GameRules test mod.");
|
||||
|
||||
// Validate the EnumRule has registered it's commands
|
||||
ServerLifecycleEvents.SERVER_STARTED.register(server -> {
|
||||
RootCommandNode<ServerCommandSource> dispatcher = server.getCommandManager().getDispatcher().getRoot();
|
||||
// Find the GameRule node
|
||||
CommandNode<ServerCommandSource> gamerule = dispatcher.getChild("gamerule");
|
||||
|
||||
if (gamerule == null) {
|
||||
throw new AssertionError("Failed to find GameRule command node on server's command dispatcher");
|
||||
}
|
||||
|
||||
// Find the literal corresponding to our enum rule, using cardinal directions here.
|
||||
CommandNode<ServerCommandSource> cardinalDirection = gamerule.getChild("cardinalDirection");
|
||||
|
||||
if (cardinalDirection == null) {
|
||||
throw new AssertionError("Failed to find \"cardinalDirection\" literal node corresponding a rule.");
|
||||
}
|
||||
|
||||
// Verify we have a query command set.
|
||||
if (cardinalDirection.getCommand() == null) {
|
||||
throw new AssertionError("Expected to find a query command on \"cardinalDirection\" command node, but it was not present");
|
||||
}
|
||||
|
||||
Collection<CommandNode<ServerCommandSource>> children = cardinalDirection.getChildren();
|
||||
|
||||
// There should only be 4 child nodes.
|
||||
if (children.size() != 4) {
|
||||
throw new AssertionError(String.format("Expected only 4 child nodes on \"cardinalDirection\" command node, but %s were found", children.size()));
|
||||
}
|
||||
|
||||
// All children should be literals
|
||||
children.stream().filter(node -> !(node instanceof LiteralCommandNode)).findAny().ifPresent(node -> {
|
||||
throw new AssertionError(String.format("Found non-literal child node on \"cardinalDirection\" command node %s", node));
|
||||
});
|
||||
|
||||
// Verify we have all the correct nodes
|
||||
for (CommandNode<ServerCommandSource> child : children) {
|
||||
LiteralCommandNode<ServerCommandSource> node = (LiteralCommandNode<ServerCommandSource>) child;
|
||||
String name = node.getName();
|
||||
switch (name) {
|
||||
case "north":
|
||||
case "south":
|
||||
case "east":
|
||||
case "west":
|
||||
continue;
|
||||
default:
|
||||
throw new AssertionError(String.format("Found unexpected literal name. Found %s but only \"north, south, east, west\" are allowed", name));
|
||||
}
|
||||
}
|
||||
|
||||
children.stream().filter(node -> node.getCommand() == null).findAny().ifPresent(node -> {
|
||||
throw new AssertionError(String.format("Found child node with no command literal name. %s", node));
|
||||
});
|
||||
|
||||
LOGGER.info("GameRule command checks have passed. Try giving the enum rules a test.");
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"gamerule.cardinalDirection": "Random Cardinal Direction",
|
||||
"gamerule.cardinalDirection.description": "A cardinal direction. Should never be up or down",
|
||||
"gamerule.cardinalDirection.north": "Northbound",
|
||||
"gamerule.cardinalDirection.south": "Southbound",
|
||||
"gamerule.cardinalDirection.east": "Eastbound",
|
||||
"gamerule.cardinalDirection.west": "Westbound",
|
||||
|
||||
"gamerule.redSleepFailureEnum": "Why I didn't go to bed",
|
||||
"gamerule.redSleepFailureEnum.description": "Bed bugs are nasty man.",
|
||||
"gamerule.redSleepFailureEnum.not_possible_here": "Not here",
|
||||
"gamerule.redSleepFailureEnum.not_possible_now": "Not now",
|
||||
"gamerule.redSleepFailureEnum.too_far_away": "Too far away",
|
||||
"gamerule.redSleepFailureEnum.obstructed": "Obstructed",
|
||||
"gamerule.redSleepFailureEnum.other_problem": "Other problem",
|
||||
"gamerule.redSleepFailureEnum.not_safe": "Not safe"
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "fabric-game-rule-api-v1-testmod",
|
||||
"name": "Fabric Game Rule API (v1) Test Mod",
|
||||
"version": "1.0.0",
|
||||
"environment": "*",
|
||||
"license": "Apache-2.0",
|
||||
"depends": {
|
||||
"fabric-game-rule-api-v1": "*",
|
||||
"fabric-lifecycle-events-v1":"*",
|
||||
"fabric-resource-loader-v0": "*"
|
||||
},
|
||||
"entrypoints": {
|
||||
"main": [
|
||||
"net.fabricmc.fabric.test.gamerule.GameRulesTestMod"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@ include 'fabric-crash-report-info-v1'
|
|||
//include 'fabric-dimensions-v1'
|
||||
include 'fabric-events-interaction-v0'
|
||||
include 'fabric-events-lifecycle-v0'
|
||||
include 'fabric-game-rule-api-v1'
|
||||
include 'fabric-item-api-v1'
|
||||
include 'fabric-item-groups-v0'
|
||||
include 'fabric-keybindings-v0'
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue