Update some enchantment stuff and update more items code

This commit is contained in:
Sollace 2024-09-30 17:00:29 +01:00
parent 668dd13db7
commit ab25ab7556
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
20 changed files with 257 additions and 176 deletions

View file

@ -24,9 +24,13 @@ import com.minelittlepony.unicopia.util.RegistryUtils;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
import com.mojang.serialization.Codec;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.network.RegistryByteBuf;
import net.minecraft.network.codec.PacketCodec;
import net.minecraft.network.codec.PacketCodecs;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import net.minecraft.util.Util;
@ -41,6 +45,8 @@ public final class SpellType<T extends Spell> implements Affine, SpellPredicate<
public static final Registry<SpellType<?>> REGISTRY = RegistryUtils.createSimple(Unicopia.id("spells"));
public static final RegistryKey<? extends Registry<SpellType<?>>> REGISTRY_KEY = REGISTRY.getKey();
public static final Codec<SpellType<?>> CODEC = REGISTRY.getCodec();
public static final PacketCodec<RegistryByteBuf, SpellType<?>> PACKET_CODEC = PacketCodecs.registryValue(REGISTRY_KEY);
private static final DynamicCommandExceptionType UNKNOWN_SPELL_TYPE_EXCEPTION = new DynamicCommandExceptionType(id -> Text.translatable("spell_type.unknown", id));

View file

@ -5,6 +5,7 @@ import java.util.Optional;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.item.WeatherJarItem;
import com.minelittlepony.unicopia.item.enchantment.EnchantmentUtil;
import com.minelittlepony.unicopia.particle.LightningBoltParticleEffect;
import com.mojang.serialization.MapCodec;
@ -14,14 +15,12 @@ import net.minecraft.block.ShapeContext;
import net.minecraft.block.TransparentBlock;
import net.minecraft.block.Waterloggable;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.enchantment.Enchantments;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.FluidState;
import net.minecraft.fluid.Fluids;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.item.ItemStack;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.state.StateManager;
import net.minecraft.state.property.BooleanProperty;
import net.minecraft.state.property.Properties;
@ -104,7 +103,7 @@ public class JarBlock extends TransparentBlock implements Waterloggable {
public void afterBreak(World world, PlayerEntity player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool) {
super.afterBreak(world, player, pos, state, blockEntity, tool);
// TODO: Enchantment tag
if (EnchantmentHelper.getLevel(world.getRegistryManager().get(RegistryKeys.ENCHANTMENT).getEntry(Enchantments.SILK_TOUCH).get(), tool) == 0 && !player.shouldCancelInteraction()) {
if (EnchantmentUtil.getLevel(world, Enchantments.SILK_TOUCH, tool) == 0 && !player.shouldCancelInteraction()) {
if (asItem() instanceof WeatherJarItem jar) {
jar.releaseContents(world, pos);
}

View file

@ -14,6 +14,7 @@ import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.network.codec.PacketCodec;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.predicate.entity.EntityPredicates;
import net.minecraft.registry.RegistryKey;
@ -22,7 +23,6 @@ import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.Identifier;
import net.minecraft.util.StringIdentifiable;
import net.minecraft.util.function.ValueLists;
import net.minecraft.util.math.*;
import net.minecraft.util.math.random.Random;
import net.minecraft.util.shape.VoxelShape;
@ -37,7 +37,6 @@ import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@ -56,9 +55,13 @@ import com.minelittlepony.unicopia.entity.collision.MultiBox;
import com.minelittlepony.unicopia.item.BasketItem;
import com.minelittlepony.unicopia.item.HotAirBalloonItem;
import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.item.component.UDataComponentTypes;
import com.minelittlepony.unicopia.server.world.WeatherConditions;
import com.minelittlepony.unicopia.util.serialization.PacketCodecUtils;
import com.terraformersmc.terraform.boat.api.TerraformBoatType;
import io.netty.buffer.ByteBuf;
public class AirBalloonEntity extends MobEntity implements EntityCollisions.ComplexCollidable, MultiBoundingBoxEntity, MagicImmune, EquineContext {
private static final TrackedData<Boolean> ASCENDING = DataTracker.registerData(AirBalloonEntity.class, TrackedDataHandlerRegistry.BOOLEAN);
private static final TrackedData<Integer> BOOSTING = DataTracker.registerData(AirBalloonEntity.class, TrackedDataHandlerRegistry.INTEGER);
@ -375,7 +378,7 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp
if (!player.isSneaky()) {
getWorld().emitGameEvent(player, GameEvent.EQUIP, getBlockPos());
}
setDesign(HotAirBalloonItem.getDesign(getWorld(), stack));
setDesign(AirBalloonEntity.BalloonDesign.of(getWorld(), stack));
if (hasBurner() && hasBalloon()) {
UCriteria.CONSTRUCT_BALLOON.trigger(player);
}
@ -792,8 +795,9 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp
STORM,
TALE;
private static final BalloonDesign[] VALUES = values();
public static final EnumCodec<BalloonDesign> CODEC = StringIdentifiable.createCodec(BalloonDesign::values);
private static final IntFunction<BalloonDesign> BY_ID = ValueLists.<BalloonDesign>createIdToValueFunction(Enum::ordinal, values(), ValueLists.OutOfBoundsHandling.ZERO);
public static final PacketCodec<ByteBuf, BalloonDesign> PACKET_CODEC = PacketCodecUtils.ofEnum(BalloonDesign.class);
private final String name = name().toLowerCase(Locale.ROOT);
@ -802,8 +806,16 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp
return name;
}
public static AirBalloonEntity.BalloonDesign of(World world, ItemStack stack) {
AirBalloonEntity.BalloonDesign design = stack.getOrDefault(UDataComponentTypes.BALLOON_DESIGN, NONE);
if (design == NONE) {
return VALUES[1 + world.getRandom().nextInt(VALUES.length - 1)];
}
return design;
}
public static BalloonDesign getType(int type) {
return BY_ID.apply(type);
return VALUES[Math.abs(type) % VALUES.length];
}
public static BalloonDesign getType(String name) {

View file

@ -12,7 +12,7 @@ public interface ChameleonItem {
return true;
}
default ItemStack getAppearanceStack(ItemStack stack) {
static ItemStack getAppearanceStack(ItemStack stack) {
Item appearance = getAppearance(stack);
if (appearance != Items.AIR) {
return createAppearanceStack(stack, appearance);
@ -20,7 +20,7 @@ public interface ChameleonItem {
return stack;
}
default ItemStack createAppearanceStack(ItemStack stack, Item appearance) {
static ItemStack createAppearanceStack(ItemStack stack, Item appearance) {
ItemStack newAppearance = appearance.getDefaultStack();
if (stack.hasNbt()) {
newAppearance.setNbt(stack.getNbt().copy());
@ -30,11 +30,11 @@ public interface ChameleonItem {
return newAppearance;
}
default boolean hasAppearance(ItemStack stack) {
static boolean hasAppearance(ItemStack stack) {
return getAppearance(stack) != Items.AIR;
}
default Item getAppearance(ItemStack stack) {
static Item getAppearance(ItemStack stack) {
if (stack.hasNbt() && stack.getNbt().contains("appearance")) {
return Registries.ITEM.get(new Identifier(stack.getNbt().getString("appearance")));
}
@ -42,7 +42,7 @@ public interface ChameleonItem {
return Items.AIR;
}
default ItemStack setAppearance(ItemStack stack, ItemStack appearance) {
static ItemStack setAppearance(ItemStack stack, ItemStack appearance) {
ItemStack result = stack.copy();
if (appearance.hasNbt()) {

View file

@ -1,6 +1,7 @@
package com.minelittlepony.unicopia.item;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
@ -72,8 +73,8 @@ public class CrystalHeartItem extends Item implements FloatingArtefactEntity.Art
}
if (world instanceof ServerWorld serverWorld) {
FloatingArtefactEntity entity = UEntities.FLOATING_ARTEFACT.create(serverWorld, context.getStack().getNbt(), null, blockPos, SpawnReason.SPAWN_EGG, false, true);
Consumer<FloatingArtefactEntity> consumer = EntityType.copier(serverWorld, context.getStack(), context.getPlayer());
FloatingArtefactEntity entity = UEntities.FLOATING_ARTEFACT.create(serverWorld, consumer, blockPos, SpawnReason.SPAWN_EGG, false, true);
if (entity == null) {
return ActionResult.FAIL;

View file

@ -12,13 +12,14 @@ import com.minelittlepony.unicopia.particle.ParticleUtils;
import com.minelittlepony.unicopia.util.InventoryUtil;
import net.minecraft.block.Block;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.InventoryOwner;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemStack;
import net.minecraft.registry.tag.EnchantmentTags;
import net.minecraft.world.World;
public class CuringJokeItem extends BlockItem {
@ -84,15 +85,14 @@ public class CuringJokeItem extends BlockItem {
static boolean uncurseItem(LivingEntity user) {
return getInventory(user)
.filter(s -> EnchantmentHelper.get(s).keySet().stream().anyMatch(Enchantment::isCursed))
.findAny()
.filter(s -> {
var enchantments = EnchantmentHelper.get(s);
return enchantments.keySet().stream().filter(Enchantment::isCursed).findAny().filter(e -> {
enchantments.remove(e);
EnchantmentHelper.set(enchantments, s);
return true;
}).isPresent();
var enchantments = s.get(DataComponentTypes.ENCHANTMENTS);
return enchantments != null && enchantments.getEnchantments().stream().anyMatch(entry -> entry.isIn(EnchantmentTags.CURSE));
})
.findAny()
.map(s -> {
EnchantmentHelper.apply(s, builder -> builder.remove(entry -> entry.isIn(EnchantmentTags.CURSE)));
return s;
}).isPresent();
}

View file

@ -10,12 +10,12 @@ import com.minelittlepony.unicopia.ability.magic.spell.Spell;
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.item.component.UDataComponentTypes;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemConvertible;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Hand;
import net.minecraft.util.Identifier;
import net.minecraft.util.TypedActionResult;
public interface EnchantableItem extends ItemConvertible {
@ -63,7 +63,7 @@ public interface EnchantableItem extends ItemConvertible {
}
static boolean isEnchanted(ItemStack stack) {
return !stack.isEmpty() && stack.hasNbt() && stack.getNbt().contains("spell");
return !getSpellKey(stack).isEmpty();
}
static ItemStack enchant(ItemStack stack, SpellType<?> type) {
@ -74,21 +74,23 @@ public interface EnchantableItem extends ItemConvertible {
if (type.isEmpty()) {
return unenchant(stack);
}
stack.getOrCreateNbt().putString("spell", type.getId().toString());
stack.set(UDataComponentTypes.STORED_SPELL, type);
return type.getTraits().applyTo(stack);
}
static ItemStack unenchant(ItemStack stack) {
stack.removeSubNbt("spell");
stack.removeSubNbt("spell_traits");
stack.remove(UDataComponentTypes.STORED_SPELL);
stack.remove(UDataComponentTypes.SPELL_TRAITS);
return stack;
}
static Optional<SpellType<?>> getSpellKeyOrEmpty(ItemStack stack) {
return isEnchanted(stack) ? SpellType.REGISTRY.getOrEmpty(new Identifier(stack.getNbt().getString("spell"))) : Optional.empty();
SpellType<?> type = getSpellKey(stack);
return type.isEmpty() ? Optional.empty() : Optional.of(type);
}
@SuppressWarnings("unchecked")
static <T extends Spell> SpellType<T> getSpellKey(ItemStack stack) {
return SpellType.getKey(isEnchanted(stack) ? new Identifier(stack.getNbt().getString("spell")) : SpellType.EMPTY_ID);
return (SpellType<T>)stack.getOrDefault(UDataComponentTypes.STORED_SPELL, SpellType.empty());
}
}

View file

@ -5,8 +5,6 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod;
@ -226,7 +224,7 @@ public class EnchantedStaffItem extends StaffItem implements EnchantableItem, Ch
@Override
public void onDischarge(ItemStack stack) {
if ((stack.hasNbt() && stack.getNbt().contains("energy") ? stack.getNbt().getFloat("energy") : 0) == 0) {
if (ChargeableItem.getEnergy(stack) == 0) {
EnchantableItem.unenchant(stack);
}
}

View file

@ -9,10 +9,10 @@ import com.minelittlepony.unicopia.block.FancyBedBlock;
import net.minecraft.block.Block;
import net.minecraft.block.BlockEntityProvider;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.component.type.NbtComponent;
import net.minecraft.item.BedItem;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.util.math.BlockPos;
public class FancyBedItem extends BedItem implements Supplier<BlockEntity> {
@ -29,12 +29,13 @@ public class FancyBedItem extends BedItem implements Supplier<BlockEntity> {
return renderEntity.get();
}
@SuppressWarnings("deprecation")
public static FancyBedBlock.SheetPattern getPattern(ItemStack stack) {
@Nullable
NbtCompound blockEntityNbt = getBlockEntityNbt(stack);
if (blockEntityNbt == null || !blockEntityNbt.contains("pattern", NbtElement.STRING_TYPE)) {
NbtComponent blockEntityNbt = stack.getOrDefault(DataComponentTypes.BLOCK_ENTITY_DATA, NbtComponent.DEFAULT);
if (blockEntityNbt == null || !blockEntityNbt.contains("pattern")) {
return FancyBedBlock.SheetPattern.NONE;
}
return FancyBedBlock.SheetPattern.byId(blockEntityNbt.getString("pattern"));
return FancyBedBlock.SheetPattern.byId(blockEntityNbt.getNbt().getString("pattern"));
}
}

View file

@ -1,7 +1,6 @@
package com.minelittlepony.unicopia.item;
import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.entity.Living;
import com.minelittlepony.unicopia.entity.mob.ButterflyEntity;
import com.minelittlepony.unicopia.entity.mob.UEntities;
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
@ -10,21 +9,17 @@ import com.minelittlepony.unicopia.projectile.ProjectileDelegate;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.enchantment.Enchantments;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.FlyingItemEntity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.attribute.EntityAttributeInstance;
import net.minecraft.entity.attribute.EntityAttributes;
import net.minecraft.entity.ProjectileDeflection;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.sound.SoundEvent;
import net.minecraft.text.Text;
import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.WorldEvents;
public class FilledJarItem extends ProjectileItem implements ProjectileDelegate.HitListener, ChameleonItem {
@ -39,7 +34,7 @@ public class FilledJarItem extends ProjectileItem implements ProjectileDelegate.
@Override
public Text getName(ItemStack stack) {
return hasAppearance(stack) ? Text.translatable(getTranslationKey(stack), getAppearanceStack(stack).getName()) : UItems.EMPTY_JAR.getName(UItems.EMPTY_JAR.getDefaultStack());
return ChameleonItem.hasAppearance(stack) ? Text.translatable(getTranslationKey(stack), ChameleonItem.getAppearanceStack(stack).getName()) : UItems.EMPTY_JAR.getName(UItems.EMPTY_JAR.getDefaultStack());
}
@Override
@ -55,71 +50,38 @@ public class FilledJarItem extends ProjectileItem implements ProjectileDelegate.
return;
}
ItemStack stack = getAppearanceStack(((FlyingItemEntity)projectile).getStack());
ItemStack stack = ChameleonItem.getAppearanceStack(((FlyingItemEntity)projectile).getStack());
boolean onFire = false;
float prevHealth = 0.0F;
int fire = EnchantmentHelper.getLevel(Enchantments.FIRE_ASPECT, stack);
if (projectile.getWorld() instanceof ServerWorld world) {
DamageSource damageSource = entity.getDamageSources().thrown(projectile, projectile.getOwner());
if (entity instanceof LivingEntity) {
prevHealth = ((LivingEntity)entity).getHealth();
float damage = EnchantmentHelper.getDamage(world, stack, entity, damageSource, projectile.getThrowDamage());
if (fire > 0 && !entity.isOnFire()) {
onFire = true;
entity.setOnFireFor(1);
}
if (projectile.getOwner() instanceof LivingEntity owner) {
owner.onAttacking(entity);
}
float damage = EnchantmentHelper.getAttackDamage(stack, entity instanceof LivingEntity ? ((LivingEntity)entity).getGroup() : EntityGroup.DEFAULT);
EntityAttributeInstance instance = new EntityAttributeInstance(EntityAttributes.GENERIC_ATTACK_DAMAGE, i -> {});
stack.getAttributeModifiers(EquipmentSlot.MAINHAND).get(EntityAttributes.GENERIC_ATTACK_DAMAGE).forEach(modifier -> {
instance.addTemporaryModifier(modifier);
});
damage += instance.getValue();
if (entity.damage(entity.getDamageSources().thrown(projectile, projectile.getOwner()), damage)) {
int knockback = EnchantmentHelper.getLevel(Enchantments.KNOCKBACK, stack);
final float toRadians = (float)Math.PI / 180F;
if (entity.damage(damageSource, damage)) {
if (entity instanceof LivingEntity living) {
living.takeKnockback(
knockback / 2F,
MathHelper.sin(projectile.getYaw() * toRadians),
-MathHelper.cos(projectile.getYaw() * toRadians)
);
Living.updateVelocity(living);
if (fire > 0) {
entity.setOnFireFor(fire * 4);
}
float healthDiff = prevHealth - ((LivingEntity)entity).getHealth();
if (projectile.getWorld() instanceof ServerWorld && healthDiff > 2) {
((ServerWorld)projectile.getWorld()).spawnParticles(ParticleTypes.DAMAGE_INDICATOR, entity.getX(), entity.getBodyY(0.5D), entity.getZ(), (int)(healthDiff / 2F), 0.1, 0, 0.1, 0.2);
}
} else {
entity.addVelocity(
-MathHelper.sin(projectile.getYaw() * toRadians) * knockback / 2F, 0.1D,
MathHelper.cos(projectile.getYaw() * toRadians) * knockback / 2F
);
projectile.knockback(living, damageSource, stack);
EnchantmentHelper.onTargetDamaged(world, living, damageSource, stack);
}
} else {
if (onFire) {
entity.setOnFire(false);
}
projectile.deflect(ProjectileDeflection.SIMPLE, entity, projectile.getOwner(), false);
projectile.setVelocity(projectile.getVelocity().multiply(0.2));
}
}
}
@Override
public void onImpact(MagicProjectileEntity projectile) {
ItemStack stack = getAppearanceStack(projectile.getStack());
ItemStack stack = ChameleonItem.getAppearanceStack(projectile.getStack());
if (stack.isOf(UItems.BUTTERFLY)) {
ButterflyEntity butterfly = UEntities.BUTTERFLY.create(projectile.getWorld());
@ -136,6 +98,6 @@ public class FilledJarItem extends ProjectileItem implements ProjectileDelegate.
}
public ItemStack withContents(ItemStack contents) {
return setAppearance(getDefaultStack(), contents);
return ChameleonItem.setAppearance(getDefaultStack(), contents);
}
}

View file

@ -12,11 +12,14 @@ import net.fabricmc.fabric.api.event.player.UseBlockCallback;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.enchantment.Enchantments;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.HoeItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ToolMaterials;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.tag.BlockTags;
import net.minecraft.registry.tag.ItemTags;
import net.minecraft.sound.SoundCategory;
@ -51,11 +54,11 @@ public class ForageableItem extends Item {
world.playSound(player, pos, state.getSoundGroup().getHitSound(), SoundCategory.BLOCKS);
InteractionManager.getInstance().addBlockBreakingParticles(pos, hitResult.getSide());
int miningLevel = (stack.getItem() instanceof HoeItem hoe ? hoe.getMaterial().getMiningLevel() : 59);
float foragingChance = getForagingChance(stack);
for (ForageableItem item : REGISTRY) {
if ((result = item.onTryForage(world, pos, state, stack, player, miningLevel)).isAccepted()) {
stack.damage(1, player, p -> p.sendToolBreakStatus(hand));
if ((result = item.onTryForage(world, pos, state, stack, player, foragingChance)).isAccepted()) {
stack.damage(1, player, LivingEntity.getSlotForHand(hand));
return result;
}
}
@ -73,13 +76,15 @@ public class ForageableItem extends Item {
REGISTRY.add(this);
}
public ActionResult onTryForage(World world, BlockPos pos, BlockState state, ItemStack stack, PlayerEntity player, int miningLevel) {
if (state.isOf(targetBlock.get())) {
int spawnChance = (int)((1F - MathHelper.clamp(miningLevel / (float)ToolMaterials.NETHERITE.getMiningLevel(), 0, 1)) * 32);
public ActionResult onTryForage(World world, BlockPos pos, BlockState state, ItemStack stack, PlayerEntity player, float spawnChance) {
if (!state.isOf(targetBlock.get())) {
return ActionResult.PASS;
}
spawnChance -= EnchantmentUtil.getLuck(1, player);
if (spawnChance <= 0 || world.random.nextInt(spawnChance) == 0) {
Block.dropStack(world, pos, new ItemStack(this, 1 + EnchantmentHelper.getLooting(player)));
if (spawnChance <= 0 || world.random.nextInt((int)(spawnChance * 32)) == 0) {
Block.dropStack(world, pos, new ItemStack(this, 1 + EnchantmentHelper.getEquipmentLevel(player.getRegistryManager().get(RegistryKeys.ENCHANTMENT).getEntry(Enchantments.LOOTING).get(), player)));
world.syncWorldEvent(WorldEvents.BLOCK_BROKEN, pos, Block.getRawIdFromState(state));
if (BlockDestructionManager.of(world).damageBlock(pos, world.getRandom().nextBetween(3, 7)) >= BlockDestructionManager.MAX_DAMAGE) {
world.breakBlock(pos, true);
@ -88,6 +93,22 @@ public class ForageableItem extends Item {
}
return ActionResult.FAIL;
}
return ActionResult.PASS;
static float getForagingChance(ItemStack stack) {
if (!(stack.getItem() instanceof HoeItem hoe)) {
return 0.25F;
}
float spawnChance = hoe.getMaterial() instanceof ToolMaterials m ? switch(m) {
case WOOD -> 0.25F;
case STONE -> 0.3F;
case IRON -> 0.4F;
case GOLD -> 0.6F;
case DIAMOND -> 0.7F;
case NETHERITE -> 0.8F;
default -> 0.25F;
} : MathHelper.clamp(hoe.getMaterial().getMiningSpeedMultiplier(), 0, 1);
return 1F - spawnChance;
}
}

View file

@ -14,6 +14,8 @@ import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.compat.trinkets.TrinketsDelegate;
import com.minelittlepony.unicopia.entity.AmuletSelectors;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.item.component.Issuer;
import com.minelittlepony.unicopia.item.component.UDataComponentTypes;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
@ -23,7 +25,6 @@ import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Item.TooltipContext;
import net.minecraft.item.tooltip.TooltipType;
import net.minecraft.stat.Stats;
import net.minecraft.text.Text;
@ -47,10 +48,7 @@ public class FriendshipBraceletItem extends WearableItem {
)) {
player.setCurrentHand(hand);
ItemStack result = stack.copy();
result.setCount(1);
result.getOrCreateNbt().putString("issuer", player.getName().getString());
result.getOrCreateNbt().putUuid("issuer_id", player.getUuid());
ItemStack result = Issuer.set(stack.copyWithCount(1), player);
if (!player.getAbilities().creativeMode) {
stack.decrement(1);
@ -75,8 +73,8 @@ public class FriendshipBraceletItem extends WearableItem {
@Environment(EnvType.CLIENT)
public void appendTooltip(ItemStack stack, TooltipContext context, List<Text> lines, TooltipType type) {
super.appendTooltip(stack, context, lines, type);
if (isSigned(stack)) {
lines.add(Text.translatable("item.unicopia.friendship_bracelet.issuer", getSignatorName(stack)));
if (Issuer.isSigned(stack)) {
stack.get(UDataComponentTypes.ISSUER).appendTooltip(context, lines::add, type);
}
if (GlowableItem.isGlowing(stack)) {
lines.add(Text.translatable("item.unicopia.friendship_bracelet.glowing").formatted(Formatting.ITALIC, Formatting.GRAY));
@ -85,49 +83,42 @@ public class FriendshipBraceletItem extends WearableItem {
@Override
public EquipmentSlot getSlotType(ItemStack stack) {
return isSigned(stack) ? EquipmentSlot.CHEST : super.getSlotType(stack);
}
private boolean checkSignature(ItemStack stack, PlayerEntity player) {
return checkSignature(stack, player.getUuid());
}
private boolean checkSignature(ItemStack stack, UUID player) {
return player.equals(getSignatorId(stack));
return Issuer.isSigned(stack) ? EquipmentSlot.CHEST : super.getSlotType(stack);
}
@Nullable
public static String getSignatorName(ItemStack stack) {
return isSigned(stack) ? stack.getNbt().getString("issuer") : null;
return Issuer.getSignatorName(stack);
}
@Nullable
public static UUID getSignatorId(ItemStack stack) {
return isSigned(stack) ? stack.getNbt().getUuid("issuer_id") : null;
return Issuer.getSignatorId(stack);
}
@Deprecated
public static boolean isSigned(ItemStack stack) {
return stack.hasNbt() && stack.getNbt().contains("issuer_id");
return Issuer.isSigned(stack);
}
@Deprecated
public static boolean isSignedBy(ItemStack stack, PlayerEntity player) {
return stack.getItem() instanceof FriendshipBraceletItem
&& ((FriendshipBraceletItem)stack.getItem()).checkSignature(stack, player);
return Issuer.isSignedBy(stack, player);
}
@Deprecated
public static boolean isSignedBy(ItemStack stack, UUID player) {
return stack.getItem() instanceof FriendshipBraceletItem
&& ((FriendshipBraceletItem)stack.getItem()).checkSignature(stack, player);
return Issuer.isSignedBy(stack, player);
}
public static boolean isComrade(Owned<?> caster, Entity entity) {
return entity instanceof LivingEntity l && caster.getMasterId()
.filter(id -> getWornBangles(l).anyMatch(stack -> isSignedBy(stack.stack(), id)))
.filter(id -> getWornBangles(l).anyMatch(stack -> Issuer.isSignedBy(stack.stack(), id)))
.isPresent();
}
public static boolean isComrade(UUID signator, Entity entity) {
return entity instanceof LivingEntity l && getWornBangles(l, stack -> isSignedBy(stack, signator)).findAny().isPresent();
return entity instanceof LivingEntity l && getWornBangles(l, stack -> Issuer.isSignedBy(stack, signator)).findAny().isPresent();
}
public static Stream<Pony> getPartyMembers(Caster<?> caster, double radius) {

View file

@ -1,24 +0,0 @@
package com.minelittlepony.unicopia.item;
import com.minelittlepony.unicopia.entity.mob.AirBalloonEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
public class HotAirBalloonItem extends Item {
public HotAirBalloonItem(Settings settings) {
super(settings);
}
public static AirBalloonEntity.BalloonDesign getDesign(World world, ItemStack stack) {
String design;
if (stack.hasNbt() && !(design = stack.getNbt().getString("design")).isEmpty()) {
return AirBalloonEntity.BalloonDesign.getType(design);
}
int ordinal = 1 + world.getRandom().nextInt(AirBalloonEntity.BalloonDesign.values().length - 1);
return AirBalloonEntity.BalloonDesign.getType(ordinal);
}
}

View file

@ -177,7 +177,7 @@ public interface UItems {
Item BAMBOO_BASKET = register("bamboo_basket", new BasketItem(AirBalloonEntity.BasketType.of(BoatEntity.Type.BAMBOO), new Item.Settings().maxCount(1)), ItemGroups.TOOLS);
Item PALM_BASKET = register("palm_basket", new BasketItem(AirBalloonEntity.BasketType.of(UWoodTypes.PALM_BOAT_TYPE), new Item.Settings().maxCount(1)), ItemGroups.TOOLS);
Item GIANT_BALLOON = register("giant_balloon", new HotAirBalloonItem(new Item.Settings().maxCount(1)), ItemGroups.TOOLS);
Item GIANT_BALLOON = register("giant_balloon", new Item(new Item.Settings().maxCount(1).component(UDataComponentTypes.BALLOON_DESIGN, AirBalloonEntity.BalloonDesign.NONE)), ItemGroups.TOOLS);
Item SPECTRAL_CLOCK = register("spectral_clock", new Item(new Item.Settings()), ItemGroups.TOOLS);
Item WHITE_BED_SHEETS = register(CloudBedBlock.SheetPattern.WHITE);

View file

@ -37,7 +37,7 @@ import net.minecraft.world.event.GameEvent;
public class ZapAppleItem extends Item implements ChameleonItem, MultiItem {
public ZapAppleItem(Settings settings) {
super(settings);
super(settings.rarity(Rarity.RARE));
}
@Override
@ -105,20 +105,18 @@ public class ZapAppleItem extends Item implements ChameleonItem, MultiItem {
.stream()
.flatMap(world -> RegistryUtils.valuesForTag(world, UConventionalTags.Items.APPLES))
.filter(a -> a != this).map(item -> {
ItemStack stack = new ItemStack(this);
stack.getOrCreateNbt().putString("appearance", Registries.ITEM.getId(item).toString());
return stack;
return ChameleonItem.setAppearance(getDefaultStack(), item.getDefaultStack());
}).toList();
}
@Override
public Text getName(ItemStack stack) {
return hasAppearance(stack) ? getAppearanceStack(stack).getName() : super.getName(stack);
return ChameleonItem.hasAppearance(stack) ? ChameleonItem.getAppearanceStack(stack).getName() : super.getName(stack);
}
@Override
public Rarity getRarity(ItemStack stack) {
if (hasAppearance(stack)) {
if (ChameleonItem.hasAppearance(stack)) {
return Rarity.EPIC;
}

View file

@ -0,0 +1,77 @@
package com.minelittlepony.unicopia.item.component;
import java.util.UUID;
import java.util.function.Consumer;
import org.jetbrains.annotations.Nullable;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import io.netty.buffer.ByteBuf;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item.TooltipContext;
import net.minecraft.item.ItemStack;
import net.minecraft.item.tooltip.TooltipAppender;
import net.minecraft.item.tooltip.TooltipType;
import net.minecraft.network.codec.PacketCodec;
import net.minecraft.network.codec.PacketCodecs;
import net.minecraft.text.Text;
import net.minecraft.util.Uuids;
public record Issuer(String name, UUID id) implements TooltipAppender {
public static final Codec<Issuer> CODEC = RecordCodecBuilder.create(instance -> instance.group(
Codec.STRING.fieldOf("name").forGetter(Issuer::name),
Uuids.CODEC.fieldOf("id").forGetter(Issuer::id)
).apply(instance, Issuer::new));
public static final PacketCodec<ByteBuf, Issuer> PACKET_CODEC = PacketCodec.tuple(
PacketCodecs.STRING, Issuer::name,
Uuids.PACKET_CODEC, Issuer::id,
Issuer::new
);
public static ItemStack set(ItemStack stack, Entity signer) {
stack.set(UDataComponentTypes.ISSUER, new Issuer(signer.getDisplayName().getString(), signer.getUuid()));
return stack;
}
@Override
public void appendTooltip(TooltipContext context, Consumer<Text> tooltip, TooltipType type) {
tooltip.accept(Text.translatable("item.unicopia.friendship_bracelet.issuer", name()));
}
public boolean isSignedBy(PlayerEntity player) {
return isSignedBy(player.getUuid());
}
public boolean isSignedBy(UUID player) {
return player.equals(id());
}
@Nullable
public static String getSignatorName(ItemStack stack) {
Issuer issuer = stack.get(UDataComponentTypes.ISSUER);
return issuer == null ? null : issuer.name();
}
@Nullable
public static UUID getSignatorId(ItemStack stack) {
Issuer issuer = stack.get(UDataComponentTypes.ISSUER);
return issuer == null ? null : issuer.id();
}
public static boolean isSigned(ItemStack stack) {
return stack.contains(UDataComponentTypes.ISSUER);
}
public static boolean isSignedBy(ItemStack stack, PlayerEntity player) {
Issuer issuer = stack.get(UDataComponentTypes.ISSUER);
return issuer != null && issuer.isSignedBy(player);
}
public static boolean isSignedBy(ItemStack stack, UUID player) {
Issuer issuer = stack.get(UDataComponentTypes.ISSUER);
return issuer != null && issuer.isSignedBy(player);
}
}

View file

@ -3,8 +3,10 @@ package com.minelittlepony.unicopia.item.component;
import java.util.function.UnaryOperator;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.container.SpellbookState;
import com.minelittlepony.unicopia.entity.mob.AirBalloonEntity;
import com.minelittlepony.unicopia.entity.mob.ButterflyEntity;
import com.mojang.serialization.Codec;
@ -14,10 +16,13 @@ import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
public interface UDataComponentTypes {
ComponentType<SpellType<?>> STORED_SPELL = register("stored_spell", builder -> builder.codec(SpellType.CODEC).packetCodec(SpellType.PACKET_CODEC));
ComponentType<SpellTraits> SPELL_TRAITS = register("spell_traits", builder -> builder.codec(SpellTraits.CODEC).packetCodec(SpellTraits.PACKET_CODEC).cache());
ComponentType<SpellbookState> SPELLBOOK_STATE = register("spellbook_state", builder -> builder.codec(SpellbookState.CODEC).packetCodec(SpellbookState.PACKET_CODEC).cache());
ComponentType<Boolean> GLOWING = register("glowing", builder -> builder.codec(Codec.BOOL).packetCodec(PacketCodecs.BOOL));
ComponentType<ButterflyEntity.Variant> BUTTERFLY_VARIANT = register("butterfly_variant", builder -> builder.codec(ButterflyEntity.Variant.CODEC).packetCodec(ButterflyEntity.Variant.PACKET_CODEC));
ComponentType<AirBalloonEntity.BalloonDesign> BALLOON_DESIGN = register("balloon_design", builder -> builder.codec(AirBalloonEntity.BalloonDesign.CODEC).packetCodec(AirBalloonEntity.BalloonDesign.PACKET_CODEC));
ComponentType<Issuer> ISSUER = register("issuer", builder -> builder.codec(Issuer.CODEC).packetCodec(Issuer.PACKET_CODEC).cache());
private static <T> ComponentType<T> register(String name, UnaryOperator<ComponentType.Builder<T>> builderOperator) {
return Registry.register(Registries.DATA_COMPONENT_TYPE, Unicopia.id(name), builderOperator.apply(ComponentType.builder()).build());

View file

@ -7,13 +7,17 @@ import com.minelittlepony.unicopia.entity.Living;
import net.minecraft.component.type.ItemEnchantmentsComponent;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.enchantment.Enchantments;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.effect.StatusEffect;
import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.item.ItemStack;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.random.Random;
import net.minecraft.world.World;
public interface EnchantmentUtil {
String HEART_BOUND_CONSUMED_FLAG = "unicopia:heart_bound_consumed";
@ -48,10 +52,21 @@ public interface EnchantmentUtil {
return (int)MathHelper.clamp(baseline + luckAmplifier + dolphinsGraceAmplifier - unluckAmplifier - badOmenAmplifier, -10, 10);
}
static int getEffectAmplifier(LivingEntity entity, RegistryEntry<StatusEffect> effect) {
if (!entity.hasStatusEffect(effect)) {
return 0;
@Deprecated
static int getLevel(World world, RegistryKey<Enchantment> enchantment, ItemStack stack) {
return world.getRegistryManager().get(RegistryKeys.ENCHANTMENT).getEntry(Enchantments.LOOTING).map(entry -> {
return EnchantmentHelper.getLevel(entry, stack);
}).orElse(0);
}
return entity.getStatusEffect(effect).getAmplifier();
@Deprecated
static int getLevel(RegistryKey<Enchantment> enchantment, LivingEntity entity) {
return entity.getRegistryManager().get(RegistryKeys.ENCHANTMENT).getEntry(Enchantments.LOOTING).map(entry -> {
return EnchantmentHelper.getEquipmentLevel(entry, entity);
}).orElse(0);
}
static int getEffectAmplifier(LivingEntity entity, RegistryEntry<StatusEffect> effect) {
return entity.hasStatusEffect(effect) ? entity.getStatusEffect(effect).getAmplifier() : 0;
}
}

View file

@ -15,7 +15,7 @@ abstract class MixinItemModels {
index = 1)
private ItemStack modifyStack(ItemStack stack) {
if (stack.getItem() instanceof ChameleonItem && ((ChameleonItem)stack.getItem()).isFullyDisguised()) {
return ((ChameleonItem)stack.getItem()).getAppearanceStack(stack);
return ChameleonItem.getAppearanceStack(stack);
}
return stack;
}

View file

@ -12,10 +12,14 @@ import com.minelittlepony.unicopia.WeaklyOwned;
import com.minelittlepony.unicopia.entity.EntityReference;
import com.minelittlepony.unicopia.entity.mob.UEntities;
import com.minelittlepony.unicopia.item.UItems;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.FallingBlockEntity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.attribute.EntityAttributes;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.data.DataTracker;
import net.minecraft.entity.data.TrackedData;
import net.minecraft.entity.data.TrackedDataHandlerRegistry;
@ -28,9 +32,11 @@ import net.minecraft.nbt.NbtElement;
import net.minecraft.particle.ItemStackParticleEffect;
import net.minecraft.particle.ParticleEffect;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
/**
@ -223,6 +229,17 @@ public class MagicProjectileEntity extends ThrownItemEntity implements WeaklyOwn
}
}
public void knockback(LivingEntity target, DamageSource source, ItemStack weapon) {
double d = weapon != null && getWorld() instanceof ServerWorld serverWorld ? EnchantmentHelper.modifyKnockback(serverWorld, weapon, target, source, 0) : 0;
if (d > 0) {
double e = Math.max(0, 1 - target.getAttributeValue(EntityAttributes.GENERIC_KNOCKBACK_RESISTANCE));
Vec3d vec3d = this.getVelocity().multiply(1, 0, 1).normalize().multiply(d * 0.6 * e);
if (vec3d.lengthSquared() > 0) {
target.addVelocity(vec3d.x, 0.1, vec3d.z);
}
}
}
protected <T extends ProjectileDelegate> void forEachDelegates(Consumer<T> consumer, Function<Object, T> predicate) {
try {
Optional.ofNullable(predicate.apply(getStack().getItem())).ifPresent(consumer);