configs
This commit is contained in:
@@ -5,6 +5,7 @@ import net.minecraft.resources.ResourceLocation;
|
|||||||
import net.neoforged.neoforge.attachment.IAttachmentHolder;
|
import net.neoforged.neoforge.attachment.IAttachmentHolder;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
@@ -30,10 +31,14 @@ public class GeneralCapabilityHolder<E extends IAttachmentHolder, T extends Gene
|
|||||||
INTERNAL_MAP.put(id, this);
|
INTERNAL_MAP.put(id, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public T get(E e) {
|
public T getOrCreate(E e) {
|
||||||
return e.getData(type());
|
return e.getData(type());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Optional<T> getExisting(E e) {
|
||||||
|
return e.getExistingData(type());
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isFor(IAttachmentHolder holder) {
|
public boolean isFor(IAttachmentHolder holder) {
|
||||||
return entity_class.isInstance(holder) && isProper(Wrappers.cast(holder));
|
return entity_class.isInstance(holder) && isProper(Wrappers.cast(holder));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ public class ClientDataHandler {
|
|||||||
public static <T extends ConditionalToken> void handle(TokenKey<T> key, T token) {
|
public static <T extends ConditionalToken> void handle(TokenKey<T> key, T token) {
|
||||||
Player player = Proxy.getClientPlayer();
|
Player player = Proxy.getClientPlayer();
|
||||||
if (player == null) return;
|
if (player == null) return;
|
||||||
ConditionalToken old = L2LibReg.CONDITIONAL.type().get(player).data.put(key, token);
|
ConditionalToken old = L2LibReg.CONDITIONAL.type().getOrCreate(player).data.put(key, token);
|
||||||
if (token instanceof NetworkSensitiveToken<?> t) {
|
if (token instanceof NetworkSensitiveToken<?> t) {
|
||||||
t.onSync(Wrappers.cast(old), player);
|
t.onSync(Wrappers.cast(old), player);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ public class PlayerFlagData extends PlayerCapabilityTemplate<PlayerFlagData> {
|
|||||||
|
|
||||||
public static void addFlag(LivingEntity entity, String str) {
|
public static void addFlag(LivingEntity entity, String str) {
|
||||||
if (entity instanceof Player player) {
|
if (entity instanceof Player player) {
|
||||||
L2LibReg.FLAGS.type().get(player).addFlag(str);
|
L2LibReg.FLAGS.type().getOrCreate(player).addFlag(str);
|
||||||
if (player instanceof ServerPlayer sp)
|
if (player instanceof ServerPlayer sp)
|
||||||
L2LibReg.FLAGS.type().network.toClient(sp);
|
L2LibReg.FLAGS.type().network.toClient(sp);
|
||||||
} else {
|
} else {
|
||||||
@@ -25,7 +25,7 @@ public class PlayerFlagData extends PlayerCapabilityTemplate<PlayerFlagData> {
|
|||||||
|
|
||||||
public static boolean hasFlag(LivingEntity entity, String str) {
|
public static boolean hasFlag(LivingEntity entity, String str) {
|
||||||
if (entity instanceof Player player) {
|
if (entity instanceof Player player) {
|
||||||
return L2LibReg.FLAGS.type().get(player).hasFlag(str);
|
return L2LibReg.FLAGS.type().getExisting(player).map(e -> e.hasFlag(str)).orElse(false);
|
||||||
} else {
|
} else {
|
||||||
return entity.getTags().contains(str);
|
return entity.getTags().contains(str);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,15 +12,18 @@ public class PlayerCapabilityNetworkHandler<T extends PlayerCapabilityTemplate<T
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void toClient(ServerPlayer e) {
|
public void toClient(ServerPlayer e) {
|
||||||
L2Core.PACKET_HANDLER.toClientPlayer(PlayerCapToClient.of(e, PlayerCapToClient.Action.CLIENT, holder, holder.get(e)), e);
|
holder.getExisting(e).ifPresent(x -> L2Core.PACKET_HANDLER.toClientPlayer(
|
||||||
|
PlayerCapToClient.of(e, PlayerCapToClient.Action.CLIENT, holder, x), e));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void toTracking(ServerPlayer e) {
|
public void toTracking(ServerPlayer e) {
|
||||||
L2Core.PACKET_HANDLER.toTrackingOnly(PlayerCapToClient.of(e, PlayerCapToClient.Action.TRACK, holder, holder.get(e)), e);
|
holder.getExisting(e).ifPresent(x -> L2Core.PACKET_HANDLER.toTrackingOnly(
|
||||||
|
PlayerCapToClient.of(e, PlayerCapToClient.Action.TRACK, holder, x), e));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startTracking(ServerPlayer tracker, ServerPlayer target) {
|
public void startTracking(ServerPlayer tracker, ServerPlayer target) {
|
||||||
L2Core.PACKET_HANDLER.toClientPlayer(PlayerCapToClient.of(target, PlayerCapToClient.Action.TRACK, holder, holder.get(target)), tracker);
|
holder.getExisting(target).ifPresent(x -> L2Core.PACKET_HANDLER.toClientPlayer(
|
||||||
|
PlayerCapToClient.of(target, PlayerCapToClient.Action.TRACK, holder, x), tracker));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ public class BaseCapabilityEvents {
|
|||||||
if (event.getEntity() instanceof LivingEntity le && le.isAlive()) {
|
if (event.getEntity() instanceof LivingEntity le && le.isAlive()) {
|
||||||
for (GeneralCapabilityHolder<?, ?> holder : GeneralCapabilityHolder.INTERNAL_MAP.values()) {
|
for (GeneralCapabilityHolder<?, ?> holder : GeneralCapabilityHolder.INTERNAL_MAP.values()) {
|
||||||
if (holder.isFor(event.getEntity()))
|
if (holder.isFor(event.getEntity()))
|
||||||
holder.get(Wrappers.cast(event.getEntity())).tick(Wrappers.cast(event.getEntity()));
|
holder.getOrCreate(Wrappers.cast(event.getEntity())).tick(Wrappers.cast(event.getEntity()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,7 @@ public class BaseCapabilityEvents {
|
|||||||
public static void onPlayerClone(PlayerEvent.Clone event) {
|
public static void onPlayerClone(PlayerEvent.Clone event) {
|
||||||
for (PlayerCapabilityHolder<?> holder : PlayerCapabilityHolder.INTERNAL_MAP.values()) {
|
for (PlayerCapabilityHolder<?> holder : PlayerCapabilityHolder.INTERNAL_MAP.values()) {
|
||||||
ServerPlayer e = (ServerPlayer) event.getEntity();
|
ServerPlayer e = (ServerPlayer) event.getEntity();
|
||||||
holder.get(e).onClone(e, event.isWasDeath());
|
holder.getOrCreate(e).onClone(e, event.isWasDeath());
|
||||||
holder.network.toClient(e);
|
holder.network.toClient(e);
|
||||||
holder.network.toTracking(e);
|
holder.network.toTracking(e);
|
||||||
}
|
}
|
||||||
@@ -40,7 +40,7 @@ public class BaseCapabilityEvents {
|
|||||||
ServerPlayer e = (ServerPlayer) event.getEntity();
|
ServerPlayer e = (ServerPlayer) event.getEntity();
|
||||||
if (e == null) return;
|
if (e == null) return;
|
||||||
for (PlayerCapabilityHolder<?> holder : PlayerCapabilityHolder.INTERNAL_MAP.values()) {
|
for (PlayerCapabilityHolder<?> holder : PlayerCapabilityHolder.INTERNAL_MAP.values()) {
|
||||||
holder.get(e).init(e);
|
holder.getOrCreate(e).init(e);
|
||||||
holder.network.toClient(e);
|
holder.network.toClient(e);
|
||||||
holder.network.toTracking(e);
|
holder.network.toTracking(e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import net.minecraft.client.renderer.RenderType;
|
|||||||
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
|
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.util.Mth;
|
import net.minecraft.util.Mth;
|
||||||
import net.minecraft.world.effect.MobEffect;
|
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
@@ -37,7 +36,6 @@ import net.neoforged.neoforge.client.event.RenderLivingEvent;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@EventBusSubscriber(value = Dist.CLIENT, modid = L2Core.MODID, bus = EventBusSubscriber.Bus.GAME)
|
@EventBusSubscriber(value = Dist.CLIENT, modid = L2Core.MODID, bus = EventBusSubscriber.Bus.GAME)
|
||||||
public class ClientEffectRenderEvents {
|
public class ClientEffectRenderEvents {
|
||||||
@@ -78,7 +76,7 @@ public class ClientEffectRenderEvents {
|
|||||||
LivingEntity entity = event.getEntity();
|
LivingEntity entity = event.getEntity();
|
||||||
if (!L2LibReg.EFFECT.type().isProper(entity)) return;
|
if (!L2LibReg.EFFECT.type().isProper(entity)) return;
|
||||||
if (entity.getTags().contains("ClientOnly")) return;//TODO
|
if (entity.getTags().contains("ClientOnly")) return;//TODO
|
||||||
ClientEffectCap cap = L2LibReg.EFFECT.type().get(entity);
|
ClientEffectCap cap = L2LibReg.EFFECT.type().getOrCreate(entity);
|
||||||
List<Pair<ClientRenderEffect, Integer>> l0 = new ArrayList<>();
|
List<Pair<ClientRenderEffect, Integer>> l0 = new ArrayList<>();
|
||||||
for (var entry : cap.map.entrySet()) {
|
for (var entry : cap.map.entrySet()) {
|
||||||
if (entry.getKey().value() instanceof ClientRenderEffect effect) {
|
if (entry.getKey().value() instanceof ClientRenderEffect effect) {
|
||||||
@@ -174,7 +172,7 @@ public class ClientEffectRenderEvents {
|
|||||||
Entity e = Minecraft.getInstance().level.getEntity(eff.entity());
|
Entity e = Minecraft.getInstance().level.getEntity(eff.entity());
|
||||||
if (!(e instanceof LivingEntity le)) return;
|
if (!(e instanceof LivingEntity le)) return;
|
||||||
if (!L2LibReg.EFFECT.type().isProper(le)) return;
|
if (!L2LibReg.EFFECT.type().isProper(le)) return;
|
||||||
ClientEffectCap cap = L2LibReg.EFFECT.type().get(le);
|
ClientEffectCap cap = L2LibReg.EFFECT.type().getOrCreate(le);
|
||||||
if (eff.exist()) {
|
if (eff.exist()) {
|
||||||
cap.map.put(eff.effect(), eff.level());
|
cap.map.put(eff.effect(), eff.level());
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -7,12 +7,19 @@ import dev.xkmc.l2core.capability.conditionals.PlayerFlagData;
|
|||||||
import dev.xkmc.l2core.capability.player.PlayerCapabilityNetworkHandler;
|
import dev.xkmc.l2core.capability.player.PlayerCapabilityNetworkHandler;
|
||||||
import dev.xkmc.l2core.init.reg.datapack.DatapackReg;
|
import dev.xkmc.l2core.init.reg.datapack.DatapackReg;
|
||||||
import dev.xkmc.l2core.init.reg.simple.*;
|
import dev.xkmc.l2core.init.reg.simple.*;
|
||||||
import dev.xkmc.l2core.serial.conditions.*;
|
import dev.xkmc.l2core.serial.configval.*;
|
||||||
import dev.xkmc.l2core.serial.ingredients.EnchantmentIngredient;
|
import dev.xkmc.l2core.serial.ingredients.EnchantmentIngredient;
|
||||||
import dev.xkmc.l2core.serial.ingredients.PotionIngredient;
|
import dev.xkmc.l2core.serial.ingredients.PotionIngredient;
|
||||||
|
import dev.xkmc.l2core.serial.loot.AddItemModifier;
|
||||||
|
import dev.xkmc.l2core.serial.loot.AddLootTableModifier;
|
||||||
|
import dev.xkmc.l2core.serial.loot.PlayerFlagCondition;
|
||||||
|
import dev.xkmc.l2serial.serialization.codec.MapCodecAdaptor;
|
||||||
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType;
|
||||||
import net.neoforged.bus.api.IEventBus;
|
import net.neoforged.bus.api.IEventBus;
|
||||||
import net.neoforged.neoforge.common.conditions.ICondition;
|
import net.neoforged.neoforge.common.conditions.ICondition;
|
||||||
|
import net.neoforged.neoforge.common.loot.IGlobalLootModifier;
|
||||||
import net.neoforged.neoforge.registries.NeoForgeRegistries;
|
import net.neoforged.neoforge.registries.NeoForgeRegistries;
|
||||||
|
|
||||||
public class L2LibReg {
|
public class L2LibReg {
|
||||||
@@ -42,6 +49,16 @@ public class L2LibReg {
|
|||||||
public static final AttVal.PlayerVal<PlayerFlagData> FLAGS = ATTACHMENT.player("flags",
|
public static final AttVal.PlayerVal<PlayerFlagData> FLAGS = ATTACHMENT.player("flags",
|
||||||
PlayerFlagData.class, PlayerFlagData::new, PlayerCapabilityNetworkHandler::new);
|
PlayerFlagData.class, PlayerFlagData::new, PlayerCapabilityNetworkHandler::new);
|
||||||
|
|
||||||
|
// loot modifiers
|
||||||
|
public static final CdcReg<IGlobalLootModifier> GLM = CdcReg.of(REG, NeoForgeRegistries.GLOBAL_LOOT_MODIFIER_SERIALIZERS);
|
||||||
|
public static final CdcVal<AddItemModifier> ADD_ITEM = GLM.reg("add_item", AddItemModifier.MAP_CODEC);
|
||||||
|
public static final CdcVal<AddLootTableModifier> ADD_TABLE = GLM.reg("add_table", AddLootTableModifier.MAP_CODEC);
|
||||||
|
|
||||||
|
// loot conditions
|
||||||
|
public static final SR<LootItemConditionType> LIC = SR.of(REG, BuiltInRegistries.LOOT_CONDITION_TYPE);
|
||||||
|
public static final Val<LootItemConditionType> LIC_FLAG = LIC.reg("player_flag", () -> new LootItemConditionType(MapCodecAdaptor.of(PlayerFlagCondition.class)));
|
||||||
|
|
||||||
|
// datapack
|
||||||
public static final DatapackReg<MenuLayoutConfig> MENU_LAYOUT = REG.dataReg("menu_layout", MenuLayoutConfig.class);
|
public static final DatapackReg<MenuLayoutConfig> MENU_LAYOUT = REG.dataReg("menu_layout", MenuLayoutConfig.class);
|
||||||
|
|
||||||
public static void register(IEventBus bus) {
|
public static void register(IEventBus bus) {
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
package dev.xkmc.l2core.serial.conditions;
|
|
||||||
|
|
||||||
import com.mojang.serialization.MapCodec;
|
|
||||||
import dev.xkmc.l2core.init.L2LibReg;
|
|
||||||
import net.neoforged.fml.config.ConfigTracker;
|
|
||||||
import net.neoforged.neoforge.common.ModConfigSpec;
|
|
||||||
import net.neoforged.neoforge.common.conditions.ICondition;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
public record BooleanValueCondition(String path, ArrayList<String> line, boolean expected) implements ICondition {
|
|
||||||
|
|
||||||
public static BooleanValueCondition of(String file, ModConfigSpec.ConfigValue<Boolean> config, boolean value) {
|
|
||||||
return new BooleanValueCondition(file, new ArrayList<>(config.getPath()), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean test(IContext context) {
|
|
||||||
var file = ConfigTracker.INSTANCE.fileMap().get(path);
|
|
||||||
if (file == null) return false;
|
|
||||||
var line = file.getConfigData().get(line());
|
|
||||||
if (line == null) return false;
|
|
||||||
return line instanceof Boolean bool && bool == expected;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MapCodec<BooleanValueCondition> codec() {
|
|
||||||
return L2LibReg.CONDITION_BOOL.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
package dev.xkmc.l2core.serial.conditions;
|
|
||||||
|
|
||||||
import com.mojang.serialization.MapCodec;
|
|
||||||
import dev.xkmc.l2core.init.L2LibReg;
|
|
||||||
import net.neoforged.fml.config.ConfigTracker;
|
|
||||||
import net.neoforged.neoforge.common.ModConfigSpec;
|
|
||||||
import net.neoforged.neoforge.common.conditions.ICondition;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
public record DoubleValueCondition(String path, ArrayList<String> line, double low, double high) implements ICondition {
|
|
||||||
|
|
||||||
public static DoubleValueCondition of(String file, ModConfigSpec.ConfigValue<Double> config, double low, double high) {
|
|
||||||
return new DoubleValueCondition(file, new ArrayList<>(config.getPath()), low, high);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean test(IContext context) {
|
|
||||||
var file = ConfigTracker.INSTANCE.fileMap().get(path);
|
|
||||||
if (file == null) return false;
|
|
||||||
var line = file.getConfigData().get(line());
|
|
||||||
if (line == null) return false;
|
|
||||||
return line instanceof Double val && low <= val && val <= high;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MapCodec<DoubleValueCondition> codec() {
|
|
||||||
return L2LibReg.CONDITION_DOUBLE.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
package dev.xkmc.l2core.serial.conditions;
|
|
||||||
|
|
||||||
import com.mojang.serialization.MapCodec;
|
|
||||||
import dev.xkmc.l2core.init.L2LibReg;
|
|
||||||
import net.neoforged.fml.config.ConfigTracker;
|
|
||||||
import net.neoforged.neoforge.common.ModConfigSpec;
|
|
||||||
import net.neoforged.neoforge.common.conditions.ICondition;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public record ListStringValueCondition(String path, ArrayList<String> line, String key) implements ICondition {
|
|
||||||
|
|
||||||
public static ListStringValueCondition of(String file, ModConfigSpec.ConfigValue<List<String>> config, String key) {
|
|
||||||
return new ListStringValueCondition(file, new ArrayList<>(config.getPath()), key);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean test(IContext context) {
|
|
||||||
var file = ConfigTracker.INSTANCE.fileMap().get(path);
|
|
||||||
if (file == null) return false;
|
|
||||||
var line = file.getConfigData().get(line());
|
|
||||||
if (line == null) return false;
|
|
||||||
return line instanceof List<?> val && val.contains(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MapCodec<ListStringValueCondition> codec() {
|
|
||||||
return L2LibReg.CONDITION_LIST_STR.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
package dev.xkmc.l2core.serial.conditions;
|
|
||||||
|
|
||||||
import com.mojang.serialization.MapCodec;
|
|
||||||
import dev.xkmc.l2core.init.L2LibReg;
|
|
||||||
import net.neoforged.fml.config.ConfigTracker;
|
|
||||||
import net.neoforged.neoforge.common.ModConfigSpec;
|
|
||||||
import net.neoforged.neoforge.common.conditions.ICondition;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
public record StringValueCondition(String path, ArrayList<String> line, String key) implements ICondition {
|
|
||||||
|
|
||||||
public static StringValueCondition of(String file, ModConfigSpec.ConfigValue<String> config, String key) {
|
|
||||||
return new StringValueCondition(file, new ArrayList<>(config.getPath()), key);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean test(IContext context) {
|
|
||||||
var file = ConfigTracker.INSTANCE.fileMap().get(path);
|
|
||||||
if (file == null) return false;
|
|
||||||
var line = file.getConfigData().get(line());
|
|
||||||
if (line == null) return false;
|
|
||||||
return line instanceof String val && val.equals(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MapCodec<StringValueCondition> codec() {
|
|
||||||
return L2LibReg.CONDITION_STR.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package dev.xkmc.l2core.serial.configval;
|
||||||
|
|
||||||
|
import net.neoforged.fml.config.ConfigTracker;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class AbstractConfigParser {
|
||||||
|
|
||||||
|
public static Optional<Object> parse(String path, List<String> line) {
|
||||||
|
return Optional.ofNullable(ConfigTracker.INSTANCE.fileMap().get(path))
|
||||||
|
.map(file -> file.getConfigData().get(line));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package dev.xkmc.l2core.serial.configval;
|
||||||
|
|
||||||
|
import com.mojang.datafixers.util.Either;
|
||||||
|
import com.mojang.serialization.Codec;
|
||||||
|
import net.neoforged.neoforge.common.ModConfigSpec;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.BooleanSupplier;
|
||||||
|
|
||||||
|
public record BooleanConfigValue(String path, List<String> line) implements BooleanSupplier {
|
||||||
|
|
||||||
|
public static BooleanConfigValue of(String file, ModConfigSpec.ConfigValue<Double> config) {
|
||||||
|
return new BooleanConfigValue(file, config.getPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BooleanConfigValue of(String data) {
|
||||||
|
int last = data.lastIndexOf('/');
|
||||||
|
var line = data.substring(last + 1).split("\\.");
|
||||||
|
return new BooleanConfigValue(data.substring(0, last), List.of(line));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Codec<BooleanSupplier> CODEC = Codec.either(Codec.BOOL, Codec.STRING)
|
||||||
|
.xmap(e -> e.map(x -> (BooleanSupplier) (() -> x), BooleanConfigValue::of),
|
||||||
|
e -> e instanceof BooleanConfigValue val ?
|
||||||
|
Either.right(val.toData()) :
|
||||||
|
Either.left(e.getAsBoolean()));
|
||||||
|
|
||||||
|
public boolean getAsBoolean() {
|
||||||
|
return AbstractConfigParser.parse(path, line)
|
||||||
|
.map(e -> e instanceof Boolean val ? val : false)
|
||||||
|
.orElse(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toData() {
|
||||||
|
StringBuilder lines = new StringBuilder();
|
||||||
|
for (var e : line) {
|
||||||
|
if (!lines.isEmpty()) {
|
||||||
|
lines.append(".");
|
||||||
|
}
|
||||||
|
lines.append(e);
|
||||||
|
}
|
||||||
|
return path + "/" + lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package dev.xkmc.l2core.serial.configval;
|
||||||
|
|
||||||
|
import com.mojang.serialization.MapCodec;
|
||||||
|
import dev.xkmc.l2core.init.L2LibReg;
|
||||||
|
import net.neoforged.neoforge.common.ModConfigSpec;
|
||||||
|
import net.neoforged.neoforge.common.conditions.ICondition;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public record BooleanValueCondition(String path, ArrayList<String> line, boolean expected) implements ICondition {
|
||||||
|
|
||||||
|
public static BooleanValueCondition of(String file, ModConfigSpec.ConfigValue<Boolean> config, boolean value) {
|
||||||
|
return new BooleanValueCondition(file, new ArrayList<>(config.getPath()), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean test(IContext context) {
|
||||||
|
return AbstractConfigParser.parse(path, line)
|
||||||
|
.map(e -> e instanceof Boolean bool && bool == expected).orElse(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MapCodec<BooleanValueCondition> codec() {
|
||||||
|
return L2LibReg.CONDITION_BOOL.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package dev.xkmc.l2core.serial.configval;
|
||||||
|
|
||||||
|
import com.mojang.datafixers.util.Either;
|
||||||
|
import com.mojang.serialization.Codec;
|
||||||
|
import net.neoforged.neoforge.common.ModConfigSpec;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.DoubleSupplier;
|
||||||
|
|
||||||
|
public record DoubleConfigValue(String path, List<String> line) implements DoubleSupplier {
|
||||||
|
|
||||||
|
public static DoubleConfigValue of(String file, ModConfigSpec.ConfigValue<Double> config) {
|
||||||
|
return new DoubleConfigValue(file, config.getPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DoubleConfigValue of(String data) {
|
||||||
|
int last = data.lastIndexOf('/');
|
||||||
|
var line = data.substring(last + 1).split("\\.");
|
||||||
|
return new DoubleConfigValue(data.substring(0, last), List.of(line));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Codec<DoubleSupplier> CODEC = Codec.either(Codec.DOUBLE, Codec.STRING)
|
||||||
|
.xmap(e -> e.map(x -> (DoubleSupplier) (() -> x), DoubleConfigValue::of),
|
||||||
|
e -> e instanceof DoubleConfigValue val ?
|
||||||
|
Either.right(val.toData()) :
|
||||||
|
Either.left(e.getAsDouble()));
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getAsDouble() {
|
||||||
|
return AbstractConfigParser.parse(path, line)
|
||||||
|
.map(e -> e instanceof Number val ? val.doubleValue() : 0d)
|
||||||
|
.orElse(0d);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toData() {
|
||||||
|
StringBuilder lines = new StringBuilder();
|
||||||
|
for (var e : line) {
|
||||||
|
if (!lines.isEmpty()) {
|
||||||
|
lines.append(".");
|
||||||
|
}
|
||||||
|
lines.append(e);
|
||||||
|
}
|
||||||
|
return path + "/" + lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package dev.xkmc.l2core.serial.configval;
|
||||||
|
|
||||||
|
import com.mojang.serialization.MapCodec;
|
||||||
|
import dev.xkmc.l2core.init.L2LibReg;
|
||||||
|
import net.neoforged.neoforge.common.ModConfigSpec;
|
||||||
|
import net.neoforged.neoforge.common.conditions.ICondition;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public record DoubleValueCondition(String path, ArrayList<String> line, double low, double high) implements ICondition {
|
||||||
|
|
||||||
|
public static DoubleValueCondition of(String file, ModConfigSpec.ConfigValue<Double> config, double low, double high) {
|
||||||
|
return new DoubleValueCondition(file, new ArrayList<>(config.getPath()), low, high);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean test(IContext context) {
|
||||||
|
return AbstractConfigParser.parse(path, line)
|
||||||
|
.map(e -> e instanceof Double val && low <= val && val <= high).orElse(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MapCodec<DoubleValueCondition> codec() {
|
||||||
|
return L2LibReg.CONDITION_DOUBLE.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package dev.xkmc.l2core.serial.configval;
|
||||||
|
|
||||||
|
import com.mojang.datafixers.util.Either;
|
||||||
|
import com.mojang.serialization.Codec;
|
||||||
|
import net.neoforged.neoforge.common.ModConfigSpec;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.IntSupplier;
|
||||||
|
|
||||||
|
public record IntConfigValue(String path, List<String> line) implements IntSupplier {
|
||||||
|
|
||||||
|
public static IntConfigValue of(String file, ModConfigSpec.ConfigValue<Integer> config) {
|
||||||
|
return new IntConfigValue(file, config.getPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IntConfigValue of(String data) {
|
||||||
|
int last = data.lastIndexOf('/');
|
||||||
|
var line = data.substring(last + 1).split("\\.");
|
||||||
|
return new IntConfigValue(data.substring(0, last), List.of(line));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Codec<IntSupplier> CODEC = Codec.either(Codec.INT, Codec.STRING)
|
||||||
|
.xmap(e -> e.map(x -> (IntSupplier) (() -> x), IntConfigValue::of),
|
||||||
|
e -> e instanceof IntConfigValue val ?
|
||||||
|
Either.right(val.toData()) :
|
||||||
|
Either.left(e.getAsInt()));
|
||||||
|
|
||||||
|
public int getAsInt() {
|
||||||
|
return AbstractConfigParser.parse(path, line)
|
||||||
|
.map(e -> e instanceof Number val ? val.intValue() : 0)
|
||||||
|
.orElse(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toData() {
|
||||||
|
StringBuilder lines = new StringBuilder();
|
||||||
|
for (var e : line) {
|
||||||
|
if (!lines.isEmpty()) {
|
||||||
|
lines.append(".");
|
||||||
|
}
|
||||||
|
lines.append(e);
|
||||||
|
}
|
||||||
|
return path + "/" + lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,10 +1,7 @@
|
|||||||
package dev.xkmc.l2core.serial.conditions;
|
package dev.xkmc.l2core.serial.configval;
|
||||||
|
|
||||||
import com.mojang.serialization.MapCodec;
|
import com.mojang.serialization.MapCodec;
|
||||||
import dev.xkmc.l2core.init.L2Core;
|
|
||||||
import dev.xkmc.l2core.init.L2LibReg;
|
import dev.xkmc.l2core.init.L2LibReg;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.neoforged.fml.config.ConfigTracker;
|
|
||||||
import net.neoforged.neoforge.common.ModConfigSpec;
|
import net.neoforged.neoforge.common.ModConfigSpec;
|
||||||
import net.neoforged.neoforge.common.conditions.ICondition;
|
import net.neoforged.neoforge.common.conditions.ICondition;
|
||||||
|
|
||||||
@@ -18,11 +15,8 @@ public record IntValueCondition(String path, ArrayList<String> line, int low, in
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean test(IContext context) {
|
public boolean test(IContext context) {
|
||||||
var file = ConfigTracker.INSTANCE.fileMap().get(path);
|
return AbstractConfigParser.parse(path, line)
|
||||||
if (file == null) return false;
|
.map(e -> e instanceof Integer val && low <= val && val <= high).orElse(false);
|
||||||
var line = file.getConfigData().get(line());
|
|
||||||
if (line == null) return false;
|
|
||||||
return line instanceof Integer val && low <= val && val <= high;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package dev.xkmc.l2core.serial.configval;
|
||||||
|
|
||||||
|
import com.mojang.serialization.MapCodec;
|
||||||
|
import dev.xkmc.l2core.init.L2LibReg;
|
||||||
|
import net.neoforged.neoforge.common.ModConfigSpec;
|
||||||
|
import net.neoforged.neoforge.common.conditions.ICondition;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public record ListStringValueCondition(String path, ArrayList<String> line, String key) implements ICondition {
|
||||||
|
|
||||||
|
public static ListStringValueCondition of(String file, ModConfigSpec.ConfigValue<List<String>> config, String key) {
|
||||||
|
return new ListStringValueCondition(file, new ArrayList<>(config.getPath()), key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean test(IContext context) {
|
||||||
|
return AbstractConfigParser.parse(path, line)
|
||||||
|
.map(e -> e instanceof List<?> val && val.contains(key)).orElse(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MapCodec<ListStringValueCondition> codec() {
|
||||||
|
return L2LibReg.CONDITION_LIST_STR.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package dev.xkmc.l2core.serial.configval;
|
||||||
|
|
||||||
|
import com.mojang.serialization.MapCodec;
|
||||||
|
import dev.xkmc.l2core.init.L2LibReg;
|
||||||
|
import net.neoforged.neoforge.common.ModConfigSpec;
|
||||||
|
import net.neoforged.neoforge.common.conditions.ICondition;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public record StringValueCondition(String path, ArrayList<String> line, String key) implements ICondition {
|
||||||
|
|
||||||
|
public static StringValueCondition of(String file, ModConfigSpec.ConfigValue<String> config, String key) {
|
||||||
|
return new StringValueCondition(file, new ArrayList<>(config.getPath()), key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean test(IContext context) {
|
||||||
|
return AbstractConfigParser.parse(path, line)
|
||||||
|
.map(e -> e instanceof String val && val.equals(key)).orElse(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MapCodec<StringValueCondition> codec() {
|
||||||
|
return L2LibReg.CONDITION_STR.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
@MethodsReturnNonnullByDefault
|
@MethodsReturnNonnullByDefault
|
||||||
@ParametersAreNonnullByDefault
|
@ParametersAreNonnullByDefault
|
||||||
|
|
||||||
package dev.xkmc.l2core.serial.conditions;
|
package dev.xkmc.l2core.serial.configval;
|
||||||
|
|
||||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||||
|
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package dev.xkmc.l2core.serial.loot;
|
||||||
|
|
||||||
|
import com.mojang.serialization.Codec;
|
||||||
|
import com.mojang.serialization.MapCodec;
|
||||||
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||||
|
import dev.xkmc.l2core.serial.configval.DoubleConfigValue;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||||
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
|
import net.minecraft.world.item.Item;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.Items;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
||||||
|
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition;
|
||||||
|
import net.neoforged.neoforge.common.loot.LootModifier;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.DoubleSupplier;
|
||||||
|
|
||||||
|
public class AddItemModifier extends LootModifier {
|
||||||
|
|
||||||
|
public static final Codec<AddItemModifier> CODEC = RecordCodecBuilder.create(i -> LootModifier.codecStart(i).and(i.group(
|
||||||
|
BuiltInRegistries.ITEM.byNameCodec().fieldOf("item").forGetter(m -> m.item),
|
||||||
|
BuiltInRegistries.ITEM.byNameCodec().optionalFieldOf("fail").forGetter(m -> m.fail == Items.AIR ? Optional.<Item>empty() : Optional.of(m.fail)),
|
||||||
|
DoubleConfigValue.CODEC.optionalFieldOf("chance")
|
||||||
|
.forGetter(m -> Optional.ofNullable(m.chance))
|
||||||
|
)).apply(i, AddItemModifier::new));
|
||||||
|
|
||||||
|
public static final MapCodec<AddItemModifier> MAP_CODEC = CODEC.dispatchMap(e -> e, AddItemModifier::codec);
|
||||||
|
|
||||||
|
public final Item item, fail;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public final DoubleSupplier chance;
|
||||||
|
|
||||||
|
protected AddItemModifier(LootItemCondition[] conditionsIn, Item item, Optional<Item> fail, Optional<DoubleSupplier> chance) {
|
||||||
|
super(conditionsIn);
|
||||||
|
this.item = item;
|
||||||
|
this.fail = fail.orElse(Items.AIR);
|
||||||
|
this.chance = chance.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddItemModifier(Item item, @Nullable DoubleConfigValue chance, LootItemCondition... conditionsIn) {
|
||||||
|
this(item, Items.AIR, chance, conditionsIn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddItemModifier(Item item, Item fail, @Nullable DoubleConfigValue chance, LootItemCondition... conditionsIn) {
|
||||||
|
super(conditionsIn);
|
||||||
|
this.item = item;
|
||||||
|
this.fail = fail;
|
||||||
|
this.chance = chance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected @NotNull ObjectArrayList<ItemStack> doApply(ObjectArrayList<ItemStack> generatedLoot, LootContext context) {
|
||||||
|
if (!context.hasParam(LootContextParams.DAMAGE_SOURCE)) {
|
||||||
|
return generatedLoot;
|
||||||
|
}
|
||||||
|
if (chance == null || context.getRandom().nextDouble() <= chance.getAsDouble()) {
|
||||||
|
generatedLoot.add(new ItemStack(item));
|
||||||
|
} else if (fail != Items.AIR) {
|
||||||
|
generatedLoot.add(new ItemStack(fail));
|
||||||
|
}
|
||||||
|
return generatedLoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MapCodec<AddItemModifier> codec() {
|
||||||
|
return MAP_CODEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package dev.xkmc.l2core.serial.loot;
|
||||||
|
|
||||||
|
import com.mojang.serialization.Codec;
|
||||||
|
import com.mojang.serialization.MapCodec;
|
||||||
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||||
|
import net.minecraft.core.registries.Registries;
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition;
|
||||||
|
import net.neoforged.neoforge.common.loot.LootModifier;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
import static net.minecraft.world.level.storage.loot.LootTable.createStackSplitter;
|
||||||
|
|
||||||
|
public class AddLootTableModifier extends LootModifier {
|
||||||
|
|
||||||
|
public static final Codec<AddLootTableModifier> CODEC = RecordCodecBuilder.create(inst -> codecStart(inst)
|
||||||
|
.and(ResourceLocation.CODEC.fieldOf("lootTable").forGetter((m) -> m.lootTable))
|
||||||
|
.apply(inst, AddLootTableModifier::new));
|
||||||
|
|
||||||
|
public static final MapCodec<AddLootTableModifier> MAP_CODEC = CODEC.dispatchMap(e -> e, AddLootTableModifier::codec);
|
||||||
|
|
||||||
|
private final ResourceLocation lootTable;
|
||||||
|
|
||||||
|
protected AddLootTableModifier(LootItemCondition[] conditionsIn, ResourceLocation lootTable) {
|
||||||
|
super(conditionsIn);
|
||||||
|
this.lootTable = lootTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddLootTableModifier(ResourceLocation lootTable, LootItemCondition... conditionsIn) {
|
||||||
|
super(conditionsIn);
|
||||||
|
this.lootTable = lootTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
protected ObjectArrayList<ItemStack> doApply(ObjectArrayList<ItemStack> generatedLoot, LootContext context) {
|
||||||
|
var extraTable = context.getResolver().lookupOrThrow(Registries.LOOT_TABLE)
|
||||||
|
.getOrThrow(ResourceKey.create(Registries.LOOT_TABLE, this.lootTable)).value();
|
||||||
|
extraTable.getRandomItemsRaw(context, createStackSplitter(context.getLevel(), generatedLoot::add));
|
||||||
|
return generatedLoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MapCodec<AddLootTableModifier> codec() {
|
||||||
|
return MAP_CODEC;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package dev.xkmc.l2core.serial.loot;
|
||||||
|
|
||||||
|
import dev.xkmc.l2core.init.L2LibReg;
|
||||||
|
import dev.xkmc.l2serial.serialization.marker.SerialClass;
|
||||||
|
import dev.xkmc.l2serial.serialization.marker.SerialField;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
||||||
|
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition;
|
||||||
|
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType;
|
||||||
|
|
||||||
|
@SerialClass
|
||||||
|
public class PlayerFlagCondition implements LootItemCondition {
|
||||||
|
|
||||||
|
@SerialField
|
||||||
|
public String flag;
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public PlayerFlagCondition() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlayerFlagCondition(String flag) {
|
||||||
|
this.flag = flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LootItemConditionType getType() {
|
||||||
|
return L2LibReg.LIC_FLAG.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean test(LootContext ctx) {
|
||||||
|
if (!ctx.hasParam(LootContextParams.LAST_DAMAGE_PLAYER)) return false;
|
||||||
|
var player = ctx.getParam(LootContextParams.LAST_DAMAGE_PLAYER);
|
||||||
|
return L2LibReg.FLAGS.type().getExisting(player).map(e -> e.hasFlag(flag)).orElse(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
@MethodsReturnNonnullByDefault
|
||||||
|
@ParametersAreNonnullByDefault
|
||||||
|
|
||||||
|
package dev.xkmc.l2core.serial.loot;
|
||||||
|
|
||||||
|
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
Reference in New Issue
Block a user