Merge branch '1.20.1' into 1.20.2

# Conflicts:
#	gradle.properties
This commit is contained in:
Sollace 2024-02-24 13:24:05 +00:00
commit 07bf99fcac
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
54 changed files with 324 additions and 147 deletions

View file

@ -4,7 +4,7 @@ buildscript {
}
}
plugins {
id 'fabric-loom' version '1.3-SNAPSHOT'
id 'fabric-loom' version '1.5-SNAPSHOT'
id 'com.modrinth.minotaur' version '2.+'
id 'org.ajoberstar.reckon' version '0.13.0'
}
@ -43,6 +43,7 @@ repositories {
maven { name 'minelp-snapshot'; url 'https://repo.minelittlepony-mod.com/maven/snapshot' }
maven { name 'minelp-releases'; url 'https://repo.minelittlepony-mod.com/maven/release' }
maven { name 'TerraformersMC'; url 'https://maven.terraformersmc.com/' }
maven { name 'Nodium'; url 'https://maven.cafeteria.dev/releases/' }
maven { name 'Modrinth'; url 'https://api.modrinth.com/maven' }
maven { name 'JitPack'; url 'https://jitpack.io'; content { includeGroup "com.github.Virtuoel" } }
}
@ -75,6 +76,9 @@ dependencies {
modImplementation "com.terraformersmc.terraform-api:terraform-wood-api-v1:${project.terraformer_api_version}"
include "com.terraformersmc.terraform-api:terraform-wood-api-v1:${project.terraformer_api_version}"
modImplementation "me.luligabi:NoIndium:${project.nodium_version}"
include "me.luligabi:NoIndium:${project.nodium_version}"
modCompileOnly "maven.modrinth:farmers-delight-fabric:${project.farmers_delight_version}", { exclude group: "net.fabricmc.fabric-api" }
if (project.use_pehkui == '1') {
modCompileOnly "maven.modrinth:pehkui:${project.pehkui_version}", { exclude group: "net.fabricmc.fabric-api" }
@ -82,8 +86,9 @@ dependencies {
}
if (project.use_sodium == '1') {
modCompileOnly "maven.modrinth:indium:${project.indium_version}", { exclude group: "net.fabricmc.fabric-api" }
modCompileOnly "maven.modrinth:sodium:${project.sodium_version}", { exclude group: "net.fabricmc.fabric-api" }
modCompileOnly "maven.modrinth:iris:${project.iris_version}", { exclude group: "net.fabricmc.fabric-api" }
// modCompileOnly "maven.modrinth:iris:${project.iris_version}", { exclude group: "net.fabricmc.fabric-api" }
}
if (project.tmi_type == 'emi') {

View file

@ -3,10 +3,10 @@ org.gradle.daemon=false
# Fabric Properties
# check these on https://fabricmc.net/develop
minecraft_version=1.20.2-rc1
yarn_mappings=1.20.2-rc1+build.2
loader_version=0.14.22
fabric_version=0.88.5+1.20.2
minecraft_version=1.20.2
yarn_mappings=1.20.2+build.4
loader_version=0.15.7
fabric_version=0.91.6+1.20.2
# Mod Properties
group=com.minelittlepony
@ -27,15 +27,17 @@ org.gradle.daemon=false
reach_attributes_version=2.3.4
trinkets_version=3.8.0
terraformer_api_version=8.0.0-beta.1
nodium_version=1.1.0+1.20
# Testing
use_pehkui=0
use_sodium=1
use_sodium=0
farmers_delight_version=1.4.3
pehkui_version=3.7.8+1.14.4-1.20.1
iris_version=1.6.8+1.20.1
sodium_version=mc1.20.1-0.5.2
pehkui_version=3.7.8+1.14.4-1.20.2
iris_version=1.6.17+1.20.2
sodium_version=mc1.20.2-0.5.5
indium_version=1.0.30+mc1.20.4
# TMI Testing
tmi_type=emi

View file

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View file

@ -1,16 +1,78 @@
package com.minelittlepony.unicopia;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.minelittlepony.unicopia.mixin.MixinPointOfInterestType;
import com.minelittlepony.unicopia.mixin.PointOfInterestTypesAccessor;
import net.fabricmc.fabric.api.event.registry.DynamicRegistrySetupCallback;
import net.fabricmc.fabric.api.event.registry.RegistryEntryAddedCallback;
import net.fabricmc.fabric.api.object.builder.v1.world.poi.PointOfInterestHelper;
import net.minecraft.block.AbstractChestBlock;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.ChestBlock;
import net.minecraft.registry.Registries;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.util.Identifier;
import net.minecraft.world.poi.PointOfInterestType;
import net.minecraft.world.poi.PointOfInterestTypes;
public interface UPOIs {
PointOfInterestType CHESTS = PointOfInterestHelper.register(Unicopia.id("chests"), 1, 64, Registries.BLOCK.getEntrySet().stream()
.map(entry -> entry.getValue())
.filter(b -> b instanceof AbstractChestBlock)
.toArray(Block[]::new));
Set<RegistryKey<PointOfInterestType>> CHEST_POINTS_OF_INTEREST = new HashSet<>();
RegistryKey<PointOfInterestType> CHESTS = register(Unicopia.id("chests"), 1, 64, () -> {
return Registries.BLOCK.getEntrySet().stream()
.map(entry -> entry.getValue())
.filter(b -> b instanceof AbstractChestBlock)
.flatMap(block -> {
List<BlockState> states = block.getStateManager().getStates();
List<RegistryKey<PointOfInterestType>> existingTypes = states.stream()
.flatMap(state -> PointOfInterestTypes.getTypeForState(state).stream())
.flatMap(entry -> entry.getKey().stream())
.toList();
static void bootstrap() { }
if (!existingTypes.isEmpty()) {
CHEST_POINTS_OF_INTEREST.addAll(existingTypes);
return Stream.empty();
}
return states.stream();
})
.distinct();
});
static RegistryKey<PointOfInterestType> register(Identifier id, int ticketCount, int searchDistance, Supplier<Stream<BlockState>> states) {
PointOfInterestType type = PointOfInterestHelper.register(id, ticketCount, searchDistance, List.of());
((MixinPointOfInterestType)(Object)type).setStates(new HashSet<>());
DynamicRegistrySetupCallback.EVENT.register(registries -> {
if (type.blockStates().isEmpty()) {
type.blockStates().addAll(states.get().collect(Collectors.toSet()));
PointOfInterestTypesAccessor.registerStates(Registries.POINT_OF_INTEREST_TYPE.entryOf(CHESTS), type.blockStates());
}
});
return RegistryKey.of(RegistryKeys.POINT_OF_INTEREST_TYPE, id);
}
static boolean isChest(RegistryEntry<PointOfInterestType> type) {
return type.getKey().filter(CHEST_POINTS_OF_INTEREST::contains).isPresent();
}
static void bootstrap() {
CHEST_POINTS_OF_INTEREST.add(CHESTS);
Registries.POINT_OF_INTEREST_TYPE.getEntrySet().forEach(poi -> {
if (poi.getValue().blockStates().stream().anyMatch(state -> state.getBlock() instanceof ChestBlock)) {
CHEST_POINTS_OF_INTEREST.add(poi.getKey());
}
});
RegistryEntryAddedCallback.event(Registries.POINT_OF_INTEREST_TYPE).register((raw, key, value) -> {
if (value.blockStates().stream().anyMatch(state -> state.getBlock() instanceof ChestBlock)) {
CHEST_POINTS_OF_INTEREST.add(RegistryKey.of(RegistryKeys.POINT_OF_INTEREST_TYPE, key));
}
});
}
}

View file

@ -69,7 +69,7 @@ public class Unicopia implements ModInitializer {
UCriteria.bootstrap();
UEntities.bootstrap();
Commands.bootstrap();
TrinketsDelegate.getInstance().bootstrap();
TrinketsDelegate.getInstance(null).bootstrap();
ServerTickEvents.END_WORLD_TICK.register(w -> {
((BlockDestructionManager.Source)w).getDestructionManager().tick();

View file

@ -13,6 +13,8 @@ import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.particle.ParticleUtils;
import com.minelittlepony.unicopia.particle.UParticles;
import net.minecraft.block.ChestBlock;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityGroup;
import net.minecraft.entity.LivingEntity;
@ -78,8 +80,8 @@ public class SeaponySonarPulseAbility implements Ability<Hit> {
if (player.asWorld() instanceof ServerWorld sw) {
sw.getPointOfInterestStorage().getNearestPosition(
type -> type.value() == UPOIs.CHESTS,
pos -> player.asWorld().getFluidState(pos).isIn(FluidTags.WATER), player.getOrigin(), 64, OccupationStatus.ANY)
UPOIs::isChest,
pos -> player.asWorld().getFluidState(pos).isIn(FluidTags.WATER) && (player.asWorld().getBlockState(pos).getBlock() instanceof ChestBlock), player.getOrigin(), 64, OccupationStatus.ANY)
.ifPresent(chestPos -> {
emitPing(player, chestPos.toCenterPos(), 20, 0.5F, 2F);
});

View file

@ -7,6 +7,7 @@ import java.util.stream.Stream;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.*;
import com.minelittlepony.unicopia.ability.Ability;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.entity.*;
import com.minelittlepony.unicopia.entity.damage.UDamageSources;
@ -103,6 +104,10 @@ public interface Caster<E extends Entity> extends
return !Ether.get(asWorld()).anyMatch(SpellType.ARCANE_PROTECTION, (spell, caster) -> spell.blocksMagicFor(caster, this, pos));
}
default boolean canUse(Ability<?> ability) {
return false;
}
static Stream<Caster<?>> stream(Stream<Entity> entities) {
return entities.map(Caster::of).flatMap(Optional::stream);
}

View file

@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.ability.magic.spell;
import java.util.Optional;
import com.minelittlepony.unicopia.ability.Abilities;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.IllusionarySpell;
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType;
@ -55,6 +56,10 @@ public class DispersableDisguiseSpell extends AbstractDisguiseSpell implements I
}
}
if (!source.canUse(Abilities.DISGUISE)) {
setDead();
}
Entity owner = source.asEntity();
Entity appearance = getDisguise().getAppearance();

View file

@ -103,7 +103,8 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS
@Override
public Collection<Spell> getDelegates() {
return List.of(spell.get());
Spell spell = this.spell.get();
return spell == null ? List.of() : List.of(spell);
}
@Override

View file

@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.ability.magic.spell;
import com.minelittlepony.unicopia.InteractionManager;
import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.Abilities;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.effect.*;
import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation;
@ -45,7 +46,7 @@ public class RageAbilitySpell extends AbstractSpell {
@Override
public boolean tick(Caster<?> source, Situation situation) {
if (situation != Situation.BODY || source.asEntity().isRemoved()) {
if (situation != Situation.BODY || source.asEntity().isRemoved() || !source.canUse(Abilities.RAGE)) {
return false;
}

View file

@ -4,6 +4,7 @@ import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.InteractionManager;
import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.ability.Abilities;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.effect.*;
import com.minelittlepony.unicopia.entity.damage.UDamageTypes;
@ -43,7 +44,7 @@ public class RainboomAbilitySpell extends AbstractSpell {
@Override
public boolean tick(Caster<?> source, Situation situation) {
if (situation != Situation.BODY) {
if (situation != Situation.BODY || !source.canUse(Abilities.RAINBOOM)) {
return false;
}

View file

@ -4,7 +4,6 @@ import com.minelittlepony.unicopia.ability.Abilities;
import com.minelittlepony.unicopia.ability.data.Rot;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.effect.*;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.server.world.UGameRules;
import com.minelittlepony.unicopia.server.world.UnicopiaWorldProperties;
@ -31,11 +30,7 @@ public class TimeControlAbilitySpell extends AbstractSpell {
@Override
public boolean tick(Caster<?> source, Situation situation) {
if (!source.asWorld().getGameRules().getBoolean(UGameRules.DO_TIME_MAGIC)) {
return false;
}
if (situation != Situation.BODY || !(source instanceof Pony pony) || !Abilities.TIME.canUse(pony.getCompositeRace())) {
if (!source.asWorld().getGameRules().getBoolean(UGameRules.DO_TIME_MAGIC) || situation != Situation.BODY || !source.canUse(Abilities.TIME)) {
return false;
}

View file

@ -29,8 +29,6 @@ public class FruitBearingBlock extends LeavesBlock implements TintedBlock, Bucka
public static final int WITHER_AGE = 15;
public static final EnumProperty<Stage> STAGE = EnumProperty.of("stage", Stage.class);
public static final List<FruitBearingBlock> REGISTRY = new ArrayList<>();
private final Supplier<Block> fruit;
private final Supplier<ItemStack> rottenFruitSupplier;
@ -47,7 +45,6 @@ public class FruitBearingBlock extends LeavesBlock implements TintedBlock, Bucka
this.overlay = overlay;
this.fruit = fruit;
this.rottenFruitSupplier = rottenFruitSupplier;
REGISTRY.add(this);
FlammableBlockRegistry.getDefaultInstance().add(this, 30, 60);
}

View file

@ -156,6 +156,7 @@ public interface URenderers {
BlockRenderLayerMap.INSTANCE.putBlocks(RenderLayer.getTranslucent(), UBlocks.SEMI_TRANSPARENT_BLOCKS.stream().toArray(Block[]::new));
// for lava boats
BlockRenderLayerMap.INSTANCE.putFluids(RenderLayer.getTranslucent(), Fluids.LAVA, Fluids.FLOWING_LAVA);
LeavesAdditionsModel.bootstrap();
TerraformBoatClientHelper.registerModelLayers(Unicopia.id("palm"), false);

View file

@ -65,7 +65,7 @@ class BangleGear implements Gear {
@Override
public void pose(PonyModel<?> model, Entity entity, boolean rainboom, UUID interpolatorId, float move, float swing, float bodySwing, float ticks) {
alex = entity instanceof ClientPlayerEntity && ((ClientPlayerEntity)entity).method_52814().model() == Model.SLIM;
alex = entity instanceof ClientPlayerEntity && ((ClientPlayerEntity)entity).getSkinTextures().model() == Model.SLIM;
FriendshipBraceletItem.getWornBangles((LivingEntity)entity, slot).findFirst().ifPresent(bracelet -> {
color = ((DyeableItem)bracelet.getItem()).getColor(bracelet);
glowing = ((GlowableItem)bracelet.getItem()).isGlowing(bracelet);

View file

@ -60,7 +60,7 @@ public class BraceletFeatureRenderer<E extends LivingEntity> implements Accessor
private void renderBangleThirdPerson(ItemStack item, MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, E entity, float limbDistance, float limbAngle, float tickDelta, float age, float headYaw, float headPitch, Arm mainArm) {
int j = ((DyeableItem)item.getItem()).getColor(item);
boolean alex = entity instanceof ClientPlayerEntity && ((ClientPlayerEntity)entity).method_52814().model() == SkinTextures.Model.SLIM;
boolean alex = entity instanceof ClientPlayerEntity && ((ClientPlayerEntity)entity).getSkinTextures().model() == SkinTextures.Model.SLIM;
BraceletModel model = alex ? alexModel : steveModel;
boolean isLeft = mainArm == Arm.LEFT;
@ -86,7 +86,7 @@ public class BraceletFeatureRenderer<E extends LivingEntity> implements Accessor
FriendshipBraceletItem.getWornBangles(entity, side == entity.getMainArm() ? TrinketsDelegate.MAINHAND : TrinketsDelegate.OFFHAND).findFirst().ifPresent(item -> {
int j = ((DyeableItem)item.getItem()).getColor(item);
boolean alex = entity instanceof ClientPlayerEntity && ((ClientPlayerEntity)entity).method_52814().model() == SkinTextures.Model.SLIM;
boolean alex = entity instanceof ClientPlayerEntity && ((ClientPlayerEntity)entity).getSkinTextures().model() == SkinTextures.Model.SLIM;
BraceletModel model = alex ? alexModel : steveModel;

View file

@ -0,0 +1,54 @@
package com.minelittlepony.unicopia.client.render;
import java.util.function.Supplier;
import com.minelittlepony.unicopia.block.FruitBearingBlock;
import net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin;
import net.fabricmc.fabric.api.client.model.loading.v1.ModelModifier;
import net.fabricmc.fabric.api.renderer.v1.RendererAccess;
import net.fabricmc.fabric.api.renderer.v1.material.BlendMode;
import net.fabricmc.fabric.api.renderer.v1.material.MaterialFinder;
import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
import net.minecraft.block.BlockState;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.registry.Registries;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.random.Random;
import net.minecraft.world.BlockRenderView;
public final class LeavesAdditionsModel extends ForwardingBakedModel {
public static void bootstrap() {
ModelLoadingPlugin.register(ctx -> {
ctx.modifyModelAfterBake().register(ModelModifier.WRAP_PHASE, (model, context) -> {
Identifier id = context.id();
if (!id.getPath().endsWith("_flowering") || !(Registries.BLOCK.get(id.withPath(p -> p.replace("block/", "").replace("_flowering", ""))) instanceof FruitBearingBlock)) {
return model;
}
return model == null ? null : new LeavesAdditionsModel(model);
});
});
}
private LeavesAdditionsModel(BakedModel model) {
this.wrapped = model;
}
@Override
public boolean isVanillaAdapter() {
return false;
}
@Override
public void emitBlockQuads(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
MaterialFinder finder = RendererAccess.INSTANCE.getRenderer().materialFinder();
context.pushTransform(quad -> {
quad.material(finder.copyFrom(quad.material()).blendMode(BlendMode.CUTOUT).find());
return true;
});
super.emitBlockQuads(blockView, state, pos, randomSupplier, context);
context.popTransform();
}
}

View file

@ -4,6 +4,8 @@ import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.EntityConvertable;
import com.minelittlepony.unicopia.container.SpellbookScreenHandler;
@ -11,6 +13,7 @@ import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.slot.Slot;
@ -26,11 +29,10 @@ public interface TrinketsDelegate {
TrinketsDelegate EMPTY = new TrinketsDelegate() {};
static TrinketsDelegate getInstance() {
if (!hasTrinkets()) {
static TrinketsDelegate getInstance(@Nullable LivingEntity entity) {
if (!(entity instanceof PlayerEntity && hasTrinkets())) {
return EMPTY;
}
return TrinketsDelegateImpl.INSTANCE;
}
@ -101,7 +103,7 @@ public interface TrinketsDelegate {
interface Inventory extends EntityConvertable<LivingEntity> {
default Stream<ItemStack> getEquippedStacks(Identifier slot) {
return TrinketsDelegate.getInstance().getEquipped(asEntity(), slot);
return TrinketsDelegate.getInstance(asEntity()).getEquipped(asEntity(), slot);
}
default ItemStack getEquippedStack(Identifier slot) {
@ -109,7 +111,7 @@ public interface TrinketsDelegate {
}
default void equipStack(Identifier slot, ItemStack stack) {
TrinketsDelegate.getInstance().setEquippedStack(asEntity(), slot, stack);
TrinketsDelegate.getInstance(asEntity()).setEquippedStack(asEntity(), slot, stack);
}
}
}

View file

@ -150,10 +150,10 @@ public class SpellbookScreenHandler extends ScreenHandler {
}
});
TrinketsDelegate.getInstance().createSlot(this, inv.player, TrinketsDelegate.FACE, 0, rightHandX, inventoryY + slotSpacing * 6).ifPresent(this::addSlot);
TrinketsDelegate.getInstance().createSlot(this, inv.player, TrinketsDelegate.NECKLACE, 0, leftHandX, equipmentY + slotSpacing).ifPresent(this::addSlot);
TrinketsDelegate.getInstance().createSlot(this, inv.player, TrinketsDelegate.MAINHAND, 0, leftHandX, equipmentY).ifPresent(this::addSlot);
TrinketsDelegate.getInstance().createSlot(this, inv.player, TrinketsDelegate.OFFHAND, 0, rightHandX, equipmentY).ifPresent(this::addSlot);
TrinketsDelegate.getInstance(inv.player).createSlot(this, inv.player, TrinketsDelegate.FACE, 0, rightHandX, inventoryY + slotSpacing * 6).ifPresent(this::addSlot);
TrinketsDelegate.getInstance(inv.player).createSlot(this, inv.player, TrinketsDelegate.NECKLACE, 0, leftHandX, equipmentY + slotSpacing).ifPresent(this::addSlot);
TrinketsDelegate.getInstance(inv.player).createSlot(this, inv.player, TrinketsDelegate.MAINHAND, 0, leftHandX, equipmentY).ifPresent(this::addSlot);
TrinketsDelegate.getInstance(inv.player).createSlot(this, inv.player, TrinketsDelegate.OFFHAND, 0, rightHandX, equipmentY).ifPresent(this::addSlot);
addSlot(outputSlot = new OutputSlot(this, inventory.player, input, result, 0, gemPos.get(0)));

View file

@ -10,6 +10,7 @@ import java.util.stream.Collectors;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.item.ItemDuck;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec;
@ -104,6 +105,7 @@ public record DietProfile(
public void appendTooltip(ItemStack stack, @Nullable PlayerEntity user, List<Text> tooltip, TooltipContext context) {
var food = stack.getItem().getFoodComponent();
var ratios = getRatios(stack);
if (food == null || isInedible(ratios)) {
if (stack.getUseAction() != UseAction.DRINK) {
@ -115,15 +117,30 @@ public record DietProfile(
float baseMultiplier = (isForaged(stack) ? foragingMultiplier() : defaultMultiplier());
if (context.isAdvanced()) {
var nonAdjustedFood = getNonAdjustedFoodComponent(stack, user).orElse(food);
tooltip.add(Text.literal(" ").append(Text.translatable("unicopia.diet.base_multiplier", baseMultiplier).formatted(Formatting.DARK_GRAY)));
tooltip.add(Text.literal(" ").append(Text.translatable("unicopia.diet.hunger.detailed", Math.max(1, (int)(ratios.getFirst() * food.getHunger())), food.getHunger(), (int)(ratios.getFirst() * 100))).formatted(Formatting.DARK_GRAY));
tooltip.add(Text.literal(" ").append(Text.translatable("unicopia.diet.saturation.detailed", String.format("%.2f", ratios.getSecond() * food.getSaturationModifier()), (int)(ratios.getSecond() * 100))).formatted(Formatting.DARK_GRAY));
tooltip.add(Text.literal(" ").append(Text.translatable("unicopia.diet.hunger.detailed", food.getHunger(), nonAdjustedFood.getHunger(), (int)(ratios.getFirst() * 100))).formatted(Formatting.DARK_GRAY));
tooltip.add(Text.literal(" ").append(Text.translatable("unicopia.diet.saturation.detailed", food.getSaturationModifier(), nonAdjustedFood.getSaturationModifier(), (int)(ratios.getSecond() * 100))).formatted(Formatting.DARK_GRAY));
} else {
tooltip.add(Text.literal(" ").append(Text.translatable("unicopia.diet.hunger", (int)(ratios.getFirst() * 100))).formatted(Formatting.DARK_GRAY));
tooltip.add(Text.literal(" ").append(Text.translatable("unicopia.diet.saturation", (int)(ratios.getSecond() * 100))).formatted(Formatting.DARK_GRAY));
}
}
private Optional<FoodComponent> getNonAdjustedFoodComponent(ItemStack stack, @Nullable PlayerEntity user) {
@Nullable
Pony pony = Pony.of(user);
Optional<FoodComponent> food = ((ItemDuck)stack.getItem()).getOriginalFoodComponent();
if (food.isEmpty() && pony.getObservedSpecies().hasIronGut()) {
return findEffect(stack)
.flatMap(Effect::foodComponent)
.or(() -> PonyDiets.getInstance().getEffects(stack).foodComponent());
}
return food;
}
public record Multiplier(
Set<TagKey<Item>> tags,
float hunger,

View file

@ -53,7 +53,7 @@ public class PonyDiets implements DietView {
return Optional.ofNullable(diets.get(pony.getObservedSpecies())).orElse(DietProfile.EMPTY);
}
private Effect getEffects(ItemStack stack) {
Effect getEffects(ItemStack stack) {
return effects.stream().filter(effect -> effect.test(stack)).findFirst().orElse(Effect.EMPTY);
}

View file

@ -10,6 +10,7 @@ import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.ability.Abilities;
import com.minelittlepony.unicopia.ability.Ability;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.SpellContainer;
import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
@ -509,7 +510,7 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
if (glasses.getItem() == UItems.SUNGLASSES) {
ItemStack broken = UItems.BROKEN_SUNGLASSES.getDefaultStack();
broken.setNbt(glasses.getNbt());
TrinketsDelegate.getInstance().setEquippedStack(entity, TrinketsDelegate.FACE, broken);
TrinketsDelegate.getInstance(entity).setEquippedStack(entity, TrinketsDelegate.FACE, broken);
playSound(USounds.ITEM_SUNGLASSES_SHATTER, 1, 1);
}
}
@ -547,7 +548,7 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
return StreamSupport.stream(entity.getArmorItems().spliterator(), false);
}
return Stream.concat(
TrinketsDelegate.getInstance().getEquipped(entity, TrinketsDelegate.NECKLACE),
TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.NECKLACE),
StreamSupport.stream(entity.getArmorItems().spliterator(), false)
);
}
@ -612,6 +613,11 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
updateVelocity(entity);
}
@Override
public boolean canUse(Ability<?> ability) {
return ability.canUse(getCompositeRace());
}
public static Optional<Living<?>> getOrEmpty(Entity entity) {
return Equine.of(entity, a -> a instanceof Living);
}

View file

@ -73,7 +73,7 @@ public class SunBlindnessStatusEffect extends StatusEffect {
}
if (entity.getEquippedStack(EquipmentSlot.HEAD).isIn(UTags.SHADES)
|| TrinketsDelegate.getInstance().getEquipped(entity, TrinketsDelegate.FACE).anyMatch(i -> i.isIn(UTags.SHADES))
|| TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.FACE).anyMatch(i -> i.isIn(UTags.SHADES))
|| entity.isSubmergedInWater()) {
return false;
}

View file

@ -180,8 +180,10 @@ public class IgnominiousBulbEntity extends MobEntity {
});
}
}
@Nullable
LivingEntity target = getAttacker();
if (!canTarget(target)) {
if (target == null || !canTarget(target)) {
target = null;
setAttacker(null);
}

View file

@ -234,7 +234,7 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
public void tick() {
super.tick();
if (pony.isClient() && this.isFlying()) {
if (pony.isClientPlayer() && isFlying() && (pony.getJumpingHeuristic().hasChanged(Heuristic.ONCE) || pony.sneakingChanged())) {
Channel.FLIGHT_CONTROLS_INPUT.sendToServer(new MsgPlayerFlightControlsInput(pony));
}

View file

@ -530,7 +530,7 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
}
if (getObservedSpecies() == Race.BAT && !entity.hasPortalCooldown()) {
boolean hasShades = TrinketsDelegate.getInstance().getEquipped(entity, TrinketsDelegate.FACE).anyMatch(s -> s.isIn(UTags.SHADES));
boolean hasShades = TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.FACE).anyMatch(s -> s.isIn(UTags.SHADES));
if (!this.hasShades && hasShades && getObservedSpecies() == Race.BAT) {
UCriteria.WEAR_SHADES.trigger(entity);
}

View file

@ -95,7 +95,7 @@ public class AmuletItem extends WearableItem implements ChargeableItem {
}
public static ItemStack getForEntity(LivingEntity entity) {
return TrinketsDelegate.getInstance().getEquipped(entity, TrinketsDelegate.NECKLACE)
return TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.NECKLACE)
.filter(stack -> stack.getItem() instanceof AmuletItem)
.findFirst()
.orElse(ItemStack.EMPTY);

View file

@ -126,13 +126,14 @@ public class FriendshipBraceletItem extends WearableItem implements DyeableItem,
public static Stream<ItemStack> getWornBangles(LivingEntity entity) {
return Stream.concat(
TrinketsDelegate.getInstance().getEquipped(entity, TrinketsDelegate.MAINHAND),
TrinketsDelegate.getInstance().getEquipped(entity, TrinketsDelegate.OFFHAND)
TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.MAINHAND),
TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.OFFHAND)
).filter(stack -> stack.getItem() == UItems.FRIENDSHIP_BRACELET);
}
public static Stream<ItemStack> getWornBangles(LivingEntity entity, Identifier slot) {
return TrinketsDelegate.getInstance().getEquipped(entity, slot)
return TrinketsDelegate.getInstance(entity)
.getEquipped(entity, slot)
.filter(stack -> stack.getItem() == UItems.FRIENDSHIP_BRACELET);
}
}

View file

@ -29,7 +29,7 @@ public class GlassesItem extends WearableItem {
}
public static ItemStack getForEntity(LivingEntity entity) {
return TrinketsDelegate.getInstance().getEquipped(entity, TrinketsDelegate.FACE)
return TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.FACE)
.filter(stack -> stack.getItem() instanceof GlassesItem)
.findFirst()
.orElse(ItemStack.EMPTY);

View file

@ -24,7 +24,7 @@ public abstract class WearableItem extends Item implements Equipment {
public WearableItem(FabricItemSettings settings) {
super(configureEquipmentSlotSupplier(settings));
DispenserBlock.registerBehavior(this, DISPENSER_BEHAVIOR);
TrinketsDelegate.getInstance().registerTrinket(this);
TrinketsDelegate.getInstance(null).registerTrinket(this);
}
private static FabricItemSettings configureEquipmentSlotSupplier(FabricItemSettings settings) {
@ -37,8 +37,8 @@ public abstract class WearableItem extends Item implements Equipment {
@Override
public TypedActionResult<ItemStack> use(World world, PlayerEntity player, Hand hand) {
ItemStack stack = player.getStackInHand(hand);
return TrinketsDelegate.getInstance().getAvailableTrinketSlots(player, TrinketsDelegate.ALL).stream()
.filter(slotId -> TrinketsDelegate.getInstance().equipStack(player, slotId, stack))
return TrinketsDelegate.getInstance(player).getAvailableTrinketSlots(player, TrinketsDelegate.ALL).stream()
.filter(slotId -> TrinketsDelegate.getInstance(player).equipStack(player, slotId, stack))
.findAny()
.map(slotId -> TypedActionResult.success(stack, world.isClient()))
.orElseGet(() -> TypedActionResult.fail(stack));
@ -66,10 +66,10 @@ public abstract class WearableItem extends Item implements Equipment {
EntityPredicates.EXCEPT_SPECTATOR
)
.stream()
.flatMap(entity -> TrinketsDelegate.getInstance()
.flatMap(entity -> TrinketsDelegate.getInstance(entity)
.getAvailableTrinketSlots(entity, TrinketsDelegate.ALL)
.stream()
.filter(slotId -> TrinketsDelegate.getInstance().equipStack(entity, slotId, armor)))
.filter(slotId -> TrinketsDelegate.getInstance(entity).equipStack(entity, slotId, armor)))
.findFirst()
.isPresent();
}

View file

@ -5,6 +5,8 @@ import com.minelittlepony.unicopia.entity.player.MagicReserves.Bar;
import com.minelittlepony.unicopia.entity.player.Pony;
import net.minecraft.entity.mob.HostileEntity;
public class StressfulEnchantment extends SimpleEnchantment {
protected StressfulEnchantment(Options options) {
@ -13,8 +15,18 @@ public class StressfulEnchantment extends SimpleEnchantment {
@Override
public void onUserTick(Living<?> user, int level) {
if (user instanceof Pony) {
Bar bar = ((Pony)user).getMagicalReserves().getEnergy();
if (user instanceof Pony pony && pony.asEntity().age % 10 == 0) {
int range = (level + 1) * 3;
if (pony.asWorld().getEntitiesByClass(HostileEntity.class, user.asEntity().getBoundingBox().expand(range, 0, range), enemy -> {
return enemy != null
&& enemy.canTarget(user.asEntity())
&& enemy.canSee(user.asEntity())
&& enemy.getTarget() == user.asEntity();
}).isEmpty()) {
return;
}
Bar bar = pony.getMagicalReserves().getEnergy();
float targetPercent = (level / (float)getMaxLevel()) * 0.05125F;
float increase = 1F + (level * level)/100F;
if (bar.getPercentFill() < targetPercent) {

View file

@ -35,7 +35,7 @@ public interface UEnchantments {
/**
* Heavy players move more slowly but are less likely to be flung around wildly.
*/
Enchantment HEAVY = register("heavy", new AttributedEnchantment(Options.armor().rarity(Rarity.UNCOMMON).maxLevel(4)))
Enchantment HEAVY = register("heavy", new AttributedEnchantment(Options.armor().rarity(Rarity.RARE).maxLevel(4)))
.addModifier(EntityAttributes.GENERIC_MOVEMENT_SPEED, (user, level) -> {
return new EntityAttributeModifier(UUID.fromString("a3d5a94f-4c40-48f6-a343-558502a13e10"), "Heavyness", (1 - level/(float)10) - 1, Operation.MULTIPLY_TOTAL);
});
@ -72,7 +72,7 @@ public interface UEnchantments {
/**
* Who doesn't like a good freakout?
*/
Enchantment STRESSED = register("stressed", new StressfulEnchantment(Options.allItems().rarity(Rarity.RARE).curse().treasure().maxLevel(3)));
Enchantment STRESSED = register("stressed", new StressfulEnchantment(Options.allItems().rarity(Rarity.VERY_RARE).curse().treasure().maxLevel(3)));
/**
* This item just wants to be held.

View file

@ -0,0 +1,16 @@
package com.minelittlepony.unicopia.mixin;
import java.util.Set;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.gen.Accessor;
import net.minecraft.block.BlockState;
import net.minecraft.world.poi.PointOfInterestType;
@Mixin(PointOfInterestType.class)
public interface MixinPointOfInterestType {
@Mutable
@Accessor("blockStates")
void setStates(Set<BlockState> states);
}

View file

@ -0,0 +1,19 @@
package com.minelittlepony.unicopia.mixin;
import java.util.Set;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
import net.minecraft.block.BlockState;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.world.poi.PointOfInterestType;
import net.minecraft.world.poi.PointOfInterestTypes;
@Mixin(PointOfInterestTypes.class)
public interface PointOfInterestTypesAccessor {
@Invoker("registerStates")
static void registerStates(RegistryEntry<PointOfInterestType> poiTypeEntry, Set<BlockState> states) {
}
}

View file

@ -38,7 +38,7 @@ abstract class MixinScreenHandler {
)
// redirect slot.getMaxItemCount() to stack aware version
protected int onGetMaxItemCount(Slot sender, ItemStack stack) {
return TrinketsDelegate.getInstance().isTrinketSlot(sender) ? sender.getMaxItemCount(stack) : sender.getMaxItemCount();
return TrinketsDelegate.getInstance(null).isTrinketSlot(sender) ? sender.getMaxItemCount(stack) : sender.getMaxItemCount();
}
@Redirect(method = "insertItem",
@ -50,7 +50,7 @@ abstract class MixinScreenHandler {
)
// redirect "if (!itemStack.isEmpty() && ItemStack.canCombine(stack, itemStack))" -> "if (!canNotInsert(itemStack, slot) && ItemStack.canCombine(stack, itemStack))"
protected boolean canNotInsert(ItemStack sender) {
return sender.isEmpty() || (TrinketsDelegate.getInstance().isTrinketSlot(currentSlot) && (currentSlot.getStack().getCount() + sender.getCount()) <= currentSlot.getMaxItemCount(sender));
return sender.isEmpty() || (TrinketsDelegate.getInstance(null).isTrinketSlot(currentSlot) && (currentSlot.getStack().getCount() + sender.getCount()) <= currentSlot.getMaxItemCount(sender));
}
@Redirect(method = "canInsertItemIntoSlot",
@ -60,6 +60,6 @@ abstract class MixinScreenHandler {
)
)
private static int onGetMaxCount(ItemStack sender, @Nullable Slot slot) {
return TrinketsDelegate.getInstance().isTrinketSlot(slot) ? slot.getMaxItemCount(sender) : sender.getMaxCount();
return TrinketsDelegate.getInstance(null).isTrinketSlot(slot) ? slot.getMaxItemCount(sender) : sender.getMaxCount();
}
}

View file

@ -1,16 +1,11 @@
{
"variants": {
"stage=flowering": {
"model": "unicopia:block/green_apple_leaves_flowering"
"multipart": [
{
"apply": { "model": "unicopia:block/green_apple_leaves" }
},
"stage=idle": {
"model": "unicopia:block/green_apple_leaves"
},
"stage=fruiting": {
"model": "unicopia:block/green_apple_leaves"
},
"stage=withering": {
"model": "unicopia:block/green_apple_leaves"
{
"apply": { "model": "unicopia:block/green_apple_leaves_flowering" },
"when": { "stage": "flowering" }
}
}
]
}

View file

@ -1,16 +1,11 @@
{
"variants": {
"stage=flowering": {
"model": "unicopia:block/sour_apple_leaves_flowering"
"multipart": [
{
"apply": { "model": "unicopia:block/sour_apple_leaves" }
},
"stage=idle": {
"model": "unicopia:block/sour_apple_leaves"
},
"stage=fruiting": {
"model": "unicopia:block/sour_apple_leaves"
},
"stage=withering": {
"model": "unicopia:block/sour_apple_leaves"
{
"apply": { "model": "unicopia:block/sour_apple_leaves_flowering" },
"when": { "stage": "flowering" }
}
}
]
}

View file

@ -1,16 +1,11 @@
{
"variants": {
"stage=flowering": {
"model": "unicopia:block/sweet_apple_leaves_flowering"
"multipart": [
{
"apply": { "model": "unicopia:block/sweet_apple_leaves" }
},
"stage=idle": {
"model": "unicopia:block/sweet_apple_leaves"
},
"stage=fruiting": {
"model": "unicopia:block/sweet_apple_leaves"
},
"stage=withering": {
"model": "unicopia:block/sweet_apple_leaves"
{
"apply": { "model": "unicopia:block/sweet_apple_leaves_flowering" },
"when": { "stage": "flowering" }
}
}
]
}

View file

@ -594,7 +594,7 @@
"unicopia.diet.not_edible": "Item is not edible",
"unicopia.diet.base_multiplier": "Base Multiplier: %s%%",
"unicopia.diet.hunger.detailed": "Hunger gained: %s of %s (%s%%)",
"unicopia.diet.saturation.detailed": "Saturation gained: %s (%s%%)",
"unicopia.diet.saturation.detailed": "Saturation gained: %s of %s (%s%%)",
"unicopia.diet.hunger": "Hunger Ratio: %s%%",
"unicopia.diet.saturation": "Saturation Ratio: %s%%",
@ -617,6 +617,7 @@
"tag.unicopia.food_types.desserts": "Desserts",
"tag.unicopia.food_types.fruits_and_vegetables": "Fruits & Vegetables",
"tag.unicopia.food_types.drinks": "Drinks",
"tag.minecraft.leaves": "Leaves",
"tag.unicopia.food_types.forage_edible_filling": "Bulky Plant Matter",
"tag.unicopia.food_types.forage_edible": "Plant Matter",

View file

@ -1,7 +1,6 @@
{
"parent": "unicopia:block/sweet_apple_leaves_flowering",
"parent": "minecraft:block/cube_all",
"textures": {
"all": "unicopia:block/green_apple_leaves",
"overlay": "unicopia:block/green_apple_leaves_flowering"
"all": "unicopia:block/green_apple_leaves_flowering"
}
}

View file

@ -1,7 +1,6 @@
{
"parent": "unicopia:block/sweet_apple_leaves_flowering",
"parent": "minecraft:block/cube_all",
"textures": {
"all": "unicopia:block/sour_apple_leaves",
"overlay": "unicopia:block/sour_apple_leaves_flowering"
"all": "unicopia:block/sour_apple_leaves_flowering"
}
}

View file

@ -1,31 +1,6 @@
{ "parent": "minecraft:block/block",
"textures": {
"all": "unicopia:block/sweet_apple_leaves",
"particle": "#all",
"overlay": "unicopia:block/sweet_apple_leaves_flowering"
},
"elements": [
{ "from": [ 0, 0, 0 ],
"to": [ 16, 16, 16 ],
"faces": {
"down": { "uv": [ 0, 0, 16, 16 ], "texture": "#all", "tintindex": 0, "cullface": "down" },
"up": { "uv": [ 0, 0, 16, 16 ], "texture": "#all", "tintindex": 0, "cullface": "up" },
"north": { "uv": [ 0, 0, 16, 16 ], "texture": "#all", "tintindex": 0, "cullface": "north" },
"south": { "uv": [ 0, 0, 16, 16 ], "texture": "#all", "tintindex": 0, "cullface": "south" },
"west": { "uv": [ 0, 0, 16, 16 ], "texture": "#all", "tintindex": 0, "cullface": "west" },
"east": { "uv": [ 0, 0, 16, 16 ], "texture": "#all", "tintindex": 0, "cullface": "east" }
}
},
{ "from": [ 0, 0, 0 ],
"to": [ 16, 16, 16 ],
"faces": {
"down": { "uv": [ 0, 0, 16, 16 ], "texture": "#overlay", "cullface": "down" },
"up": { "uv": [ 0, 0, 16, 16 ], "texture": "#overlay", "cullface": "up" },
"north": { "uv": [ 0, 0, 16, 16 ], "texture": "#overlay", "cullface": "north" },
"south": { "uv": [ 0, 0, 16, 16 ], "texture": "#overlay", "cullface": "south" },
"west": { "uv": [ 0, 0, 16, 16 ], "texture": "#overlay", "cullface": "west" },
"east": { "uv": [ 0, 0, 16, 16 ], "texture": "#overlay", "cullface": "east" }
}
}
]
{
"parent": "minecraft:block/cube_all",
"textures": {
"all": "unicopia:block/sweet_apple_leaves_flowering"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 256 B

After

Width:  |  Height:  |  Size: 6.5 KiB

View file

@ -0,0 +1,10 @@
{
"tags": [ "minecraft:leaves" ],
"food_component": {
"hunger": 2,
"saturation": 1.5
},
"ailment": {
"effects": []
}
}

View file

@ -1,6 +1,7 @@
{
"type": "minecraft:crafting_shaped",
"pattern": [
"##",
"##",
"##"
],
@ -9,5 +10,5 @@
{ "item": "unicopia:dense_cloud" }
]
},
"result": { "item": "unicopia:cloud_door", "count": 1 }
"result": { "item": "unicopia:cloud_door", "count": 3 }
}

View file

@ -2,7 +2,6 @@
"replace": false,
"values": [
"minecraft:hay_block",
"#minecraft:leaves",
"#c:foraging/edibles_filling"
]
}

View file

@ -10,6 +10,6 @@
},
"start_pool": "unicopia:clouds/start",
"step": "surface_structures",
"terrain_adaptation": "beard_thin",
"terrain_adaptation": "none",
"use_expansion_hack": true
}

View file

@ -36,6 +36,7 @@
"MixinPlayerEntity",
"MixinPlayerInventory",
"MixinPlayerManager",
"MixinPointOfInterestType",
"MixinPowderSnowBlock",
"MixinProjectileEntity",
"MixinPufferfishEntity",
@ -53,6 +54,7 @@
"MixinWardenEntity",
"MixinWorld",
"MixinWorldChunk",
"PointOfInterestTypesAccessor",
"trinkets.MixinTrinketSurvivalSlot",
"trinkets.MixinTrinketItem",
"trinkets.MixinTrinketInventory",