diff --git a/src/main/java/com/minelittlepony/unicopia/client/URenderers.java b/src/main/java/com/minelittlepony/unicopia/client/URenderers.java index bdd8d991..9b503add 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/URenderers.java +++ b/src/main/java/com/minelittlepony/unicopia/client/URenderers.java @@ -15,11 +15,12 @@ import com.minelittlepony.unicopia.client.render.AccessoryFeatureRenderer; import com.minelittlepony.unicopia.client.render.AmuletFeatureRenderer; import com.minelittlepony.unicopia.client.render.BatWingsFeatureRenderer; import com.minelittlepony.unicopia.client.render.BraceletFeatureRenderer; -import com.minelittlepony.unicopia.client.render.ButterflyEntityRenderer; -import com.minelittlepony.unicopia.client.render.CastSpellEntityRenderer; import com.minelittlepony.unicopia.client.render.FloatingArtefactEntityRenderer; import com.minelittlepony.unicopia.client.render.IcarusWingsFeatureRenderer; import com.minelittlepony.unicopia.client.render.WingsFeatureRenderer; +import com.minelittlepony.unicopia.client.render.entity.ButterflyEntityRenderer; +import com.minelittlepony.unicopia.client.render.entity.CastSpellEntityRenderer; +import com.minelittlepony.unicopia.client.render.entity.SpellbookEntityRenderer; import com.minelittlepony.unicopia.entity.UEntities; import com.minelittlepony.unicopia.item.ChameleonItem; import com.minelittlepony.unicopia.item.GemstoneItem; @@ -69,6 +70,7 @@ public interface URenderers { EntityRendererRegistry.INSTANCE.register(UEntities.BUTTERFLY, ButterflyEntityRenderer::new); EntityRendererRegistry.INSTANCE.register(UEntities.FLOATING_ARTEFACT, FloatingArtefactEntityRenderer::new); EntityRendererRegistry.INSTANCE.register(UEntities.CAST_SPELL, CastSpellEntityRenderer::new); + EntityRendererRegistry.INSTANCE.register(UEntities.SPELLBOOK, SpellbookEntityRenderer::new); ColorProviderRegistry.ITEM.register((stack, i) -> i > 0 ? -1 : ((DyeableItem)stack.getItem()).getColor(stack), UItems.FRIENDSHIP_BRACELET); BuiltinItemRendererRegistry.INSTANCE.register(UItems.FILLED_JAR, (stack, mode, matrices, vertexConsumers, light, overlay) -> { diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/ButterflyEntityRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/entity/ButterflyEntityRenderer.java similarity index 97% rename from src/main/java/com/minelittlepony/unicopia/client/render/ButterflyEntityRenderer.java rename to src/main/java/com/minelittlepony/unicopia/client/render/entity/ButterflyEntityRenderer.java index 1ce54975..099af689 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/ButterflyEntityRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/entity/ButterflyEntityRenderer.java @@ -1,5 +1,6 @@ -package com.minelittlepony.unicopia.client.render; +package com.minelittlepony.unicopia.client.render.entity; +import com.minelittlepony.unicopia.client.render.RenderLayers; import com.minelittlepony.unicopia.entity.ButterflyEntity; import net.minecraft.client.model.ModelData; diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/CastSpellEntityRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/entity/CastSpellEntityRenderer.java similarity index 91% rename from src/main/java/com/minelittlepony/unicopia/client/render/CastSpellEntityRenderer.java rename to src/main/java/com/minelittlepony/unicopia/client/render/entity/CastSpellEntityRenderer.java index 0e7e0a3d..3e729ec3 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/CastSpellEntityRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/entity/CastSpellEntityRenderer.java @@ -1,4 +1,4 @@ -package com.minelittlepony.unicopia.client.render; +package com.minelittlepony.unicopia.client.render.entity; import com.minelittlepony.unicopia.entity.CastSpellEntity; diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/entity/SpellbookEntityRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/entity/SpellbookEntityRenderer.java new file mode 100644 index 00000000..f8f614a6 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/client/render/entity/SpellbookEntityRenderer.java @@ -0,0 +1,56 @@ +package com.minelittlepony.unicopia.client.render.entity; + +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3f; + +import com.minelittlepony.unicopia.entity.SpellbookEntity; + +import net.minecraft.client.render.entity.EntityRendererFactory; +import net.minecraft.client.render.entity.LivingEntityRenderer; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.Identifier; + +public class SpellbookEntityRenderer extends LivingEntityRenderer { + private static final Identifier BLUE = new Identifier("unicopia", "textures/entity/spellbook/blue.png"); + private static final Identifier NORMAL = new Identifier("unicopia", "textures/entity/spellbook/normal.png"); + + public SpellbookEntityRenderer(EntityRendererFactory.Context context) { + super(context, new SpellbookModel(SpellbookModel.getTexturedModelData().createModel()), 0); + } + + @Override + public Identifier getTexture(SpellbookEntity entity) { + return entity.getIsAltered() ? BLUE : NORMAL; + } + + @Override + protected float getLyingAngle(SpellbookEntity entity) { + return 0; + } + + @Override + protected void setupTransforms(SpellbookEntity entity, MatrixStack matrices, float f, float g, float partialTicks) { + super.setupTransforms(entity, matrices, f, g + 90, partialTicks); + + if (entity.getIsOpen()) { + matrices.translate(-1.25F, -0.35F, 0); + + float floatPosition = MathHelper.sin((entity.age + partialTicks + entity.getId()) / 20) * 0.04F; + + matrices.translate(0, floatPosition, 0); + matrices.multiply(Vec3f.NEGATIVE_Z.getDegreesQuaternion(60)); + } else { + matrices.translate(-1.5F, 0.1F, 0.2F); + matrices.multiply(Vec3f.NEGATIVE_Z.getDegreesQuaternion(90)); + matrices.multiply(Vec3f.NEGATIVE_Y.getDegreesQuaternion(90)); + } + } + + @Override + protected boolean hasLabel(SpellbookEntity targetEntity) { + return super.hasLabel(targetEntity) + && (targetEntity.isCustomNameVisible() + || targetEntity.hasCustomName() + && targetEntity == dispatcher.targetedEntity); + } +} \ No newline at end of file diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/entity/SpellbookModel.java b/src/main/java/com/minelittlepony/unicopia/client/render/entity/SpellbookModel.java new file mode 100644 index 00000000..381e6032 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/client/render/entity/SpellbookModel.java @@ -0,0 +1,52 @@ +package com.minelittlepony.unicopia.client.render.entity; + +import com.minelittlepony.unicopia.entity.SpellbookEntity; + +import net.minecraft.client.model.ModelPart; +import net.minecraft.client.model.TexturedModelData; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.entity.model.BookModel; +import net.minecraft.client.render.entity.model.EntityModel; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.math.MathHelper; + +public class SpellbookModel extends EntityModel { + + private final BookModel book; + + public SpellbookModel(ModelPart root) { + book = new BookModel(root); + } + + public static TexturedModelData getTexturedModelData() { + return BookModel.getTexturedModelData(); + } + + @Override + public void render(MatrixStack matrices, VertexConsumer vertexConsumer, int light, int overlay, float red, float green, float blue, float alpha) { + book.render(matrices, vertexConsumer, light, overlay, red, green, blue, alpha); + } + + @Deprecated + public void setPageAngles(float breath, float leftPageRot, float rightPageRot, float openAngle) { + book.setPageAngles(breath, leftPageRot, rightPageRot, openAngle); + } + + @Override + public void setAngles(SpellbookEntity entity, float limbAngle, float limbDistance, float customAngle, float headYaw, float headPitch) { + float breath = MathHelper.sin((entity.age + customAngle) / 20) * 0.01F + 0.1F; + + float first_page_rot = limbDistance + (breath * 10); + float second_page_rot = 1 - first_page_rot; + float open_angle = 0.9f - limbDistance; + + if (first_page_rot > 1) first_page_rot = 1; + if (second_page_rot > 1) second_page_rot = 1; + + if (!entity.getIsOpen()) { + first_page_rot = second_page_rot = open_angle = 0; + } + + book.setPageAngles(breath, first_page_rot, second_page_rot, open_angle); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/container/SpellBookScreenHandler.java b/src/main/java/com/minelittlepony/unicopia/container/SpellBookScreenHandler.java new file mode 100644 index 00000000..0755dd96 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/container/SpellBookScreenHandler.java @@ -0,0 +1,19 @@ +package com.minelittlepony.unicopia.container; + +import com.minelittlepony.unicopia.EquinePredicates; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.screen.ScreenHandler; + +public class SpellBookScreenHandler extends ScreenHandler { + + protected SpellBookScreenHandler(int syncId, PlayerInventory inv) { + super(UScreenHandlers.SPELL_BOOK, syncId); + } + + @Override + public boolean canUse(PlayerEntity player) { + return EquinePredicates.IS_CASTER.test(player); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/container/UScreenHandlers.java b/src/main/java/com/minelittlepony/unicopia/container/UScreenHandlers.java new file mode 100644 index 00000000..07c14e59 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/container/UScreenHandlers.java @@ -0,0 +1,17 @@ +package com.minelittlepony.unicopia.container; + +import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry; +import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry.SimpleClientHandlerFactory; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.screen.ScreenHandlerType; +import net.minecraft.util.Identifier; + +public interface UScreenHandlers { + ScreenHandlerType SPELL_BOOK = register("spell_book", SpellBookScreenHandler::new); + + static ScreenHandlerType register(String name, SimpleClientHandlerFactory factory) { + return ScreenHandlerRegistry.registerSimple(new Identifier("unicopia", name), factory); + } + + static void bootstrap() { } +} diff --git a/src/main/java/com/minelittlepony/unicopia/entity/SpellbookEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/SpellbookEntity.java new file mode 100644 index 00000000..39b81c19 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/entity/SpellbookEntity.java @@ -0,0 +1,202 @@ +package com.minelittlepony.unicopia.entity; + +import com.minelittlepony.unicopia.EquinePredicates; +import com.minelittlepony.unicopia.container.UScreenHandlers; +import com.minelittlepony.unicopia.item.UItems; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.damage.DamageSource; +import net.minecraft.entity.data.DataTracker; +import net.minecraft.entity.data.TrackedData; +import net.minecraft.entity.data.TrackedDataHandlerRegistry; +import net.minecraft.entity.mob.MobEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.predicate.entity.EntityPredicates; +import net.minecraft.screen.SimpleNamedScreenHandlerFactory; +import net.minecraft.sound.BlockSoundGroup; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvents; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.GameRules; +import net.minecraft.world.World; + +public class SpellbookEntity extends MobEntity { + private static final TrackedData OPENED = DataTracker.registerData(SpellbookEntity.class, TrackedDataHandlerRegistry.BOOLEAN); + private static final TrackedData ALTERED = DataTracker.registerData(SpellbookEntity.class, TrackedDataHandlerRegistry.BOOLEAN); + private static final TrackedData OPENED_USER = DataTracker.registerData(SpellbookEntity.class, TrackedDataHandlerRegistry.BYTE); + + public SpellbookEntity(EntityType type, World world) { + super(type, world); + setPersistent(); + + if (world.random.nextInt(3) == 0) { + setAltered(); + } + } + + @Override + protected void initDataTracker() { + super.initDataTracker(); + dataTracker.startTracking(OPENED, true); + dataTracker.startTracking(OPENED_USER, (byte)1); + dataTracker.startTracking(ALTERED, false); + } + + @Override + public ItemStack getPickBlockStack() { + return new ItemStack(UItems.SPELLBOOK); + } + + @Override + public boolean isPushable() { + return false; + } + + @Override + public boolean doesRenderOnFire() { + return false; + } + + public boolean getIsAltered() { + return dataTracker.get(ALTERED); + } + + public void setAltered() { + dataTracker.set(ALTERED, true); + } + + public boolean getIsOpen() { + return dataTracker.get(OPENED); + } + + public Boolean getUserSetState() { + byte state = dataTracker.get(OPENED_USER); + return state == 1 ? null : state == 2; + } + + public void setIsOpen(boolean val) { + dataTracker.set(OPENED, val); + } + + public void setUserSetState(Boolean val) { + dataTracker.set(OPENED_USER, val == null ? (byte)1 : val == true ? (byte)2 : (byte)0); + } + + @Override + public void tick() { + boolean open = getIsOpen(); + jumping = open && isTouchingWater(); + super.tick(); + if (open && world.isClient) { + for (int offX = -2; offX <= 1; ++offX) { + for (int offZ = -2; offZ <= 1; ++offZ) { + if (offX > -1 && offX < 1 && offZ == -1) { + offZ = 1; + } + + if (random.nextInt(320) == 0) { + for (int offY = 0; offY <= 1; ++offY) { + world.addParticle(ParticleTypes.ENCHANT, + getX(), getY(), getZ(), + offX/2F + random.nextFloat(), + offY/2F - random.nextFloat() + 0.5f, + offZ/2F + random.nextFloat() + ); + } + } + } + } + } + + if (open) { + world.getOtherEntities(this, getBoundingBox().expand(2), EntityPredicates.EXCEPT_SPECTATOR.and(e -> e instanceof PlayerEntity)).stream().findFirst().ifPresent(player -> { + Vec3d diff = player.getPos().subtract(getPos()); + double yaw = Math.atan2(diff.z, diff.x) * 180D / Math.PI - 90; + + setHeadYaw((float)yaw); + setYaw((float)yaw); + }); + } + + if (world.random.nextInt(30) == 0) { + float celest = world.getSkyAngleRadians(1) * 4; + + boolean isDay = celest > 3 || celest < 1; + + Boolean userState = getUserSetState(); + + boolean canToggle = (isDay != open) && (userState == null || userState == isDay); + + if (canToggle) { + setUserSetState(null); + setIsOpen(isDay); + } + + if (userState != null && (isDay == open) && (userState == open)) { + setUserSetState(null); + } + } + } + + @Override + public boolean damage(DamageSource source, float amount) { + if (!world.isClient) { + remove(Entity.RemovalReason.KILLED); + + BlockSoundGroup sound = BlockSoundGroup.WOOD; + + world.playSound(getX(), getY(), getZ(), sound.getBreakSound(), SoundCategory.BLOCKS, sound.getVolume(), sound.getPitch(), true); + + if (world.getGameRules().getBoolean(GameRules.DO_TILE_DROPS)) { + dropItem(UItems.SPELLBOOK, 1); + } + } + return false; + } + + @Override + public ActionResult interactAt(PlayerEntity player, Vec3d vec, Hand hand) { + if (player.isSneaking()) { + boolean open = !getIsOpen(); + + setIsOpen(open); + setUserSetState(open); + + return ActionResult.SUCCESS; + } + + if (EquinePredicates.PLAYER_UNICORN.test(player)) { + player.openHandledScreen(new SimpleNamedScreenHandlerFactory((syncId, inv, ply) -> UScreenHandlers.SPELL_BOOK.create(syncId, inv), getDisplayName())); + player.playSound(SoundEvents.BLOCK_FURNACE_FIRE_CRACKLE, 2, 1); + return ActionResult.SUCCESS; + } + + return ActionResult.PASS; + } + + @Override + public void readCustomDataFromNbt(NbtCompound compound) { + super.readCustomDataFromNbt(compound); + + setIsOpen(compound.getBoolean("open")); + setUserSetState(compound.contains("force_open") ? compound.getBoolean("force_open") : null); + } + + @Override + public void writeCustomDataToNbt(NbtCompound compound) { + super.writeCustomDataToNbt(compound); + compound.putBoolean("open", getIsOpen()); + + Boolean state = getUserSetState(); + + if (state != null) { + compound.putBoolean("force_open", state); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/entity/UEntities.java b/src/main/java/com/minelittlepony/unicopia/entity/UEntities.java index 2ace07a4..7b56d4ee 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/UEntities.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/UEntities.java @@ -20,7 +20,6 @@ import net.minecraft.world.biome.Biome.Category; @SuppressWarnings("deprecation") public interface UEntities { - EntityType BUTTERFLY = register("butterfly", FabricEntityTypeBuilder.create(SpawnGroup.AMBIENT, ButterflyEntity::new) .dimensions(EntityDimensions.fixed(0.25F, 0.25F))); EntityType THROWN_ITEM = register("thrown_item", FabricEntityTypeBuilder.create(SpawnGroup.MISC, MagicProjectileEntity::new) @@ -33,6 +32,9 @@ public interface UEntities { EntityType CAST_SPELL = register("cast_spell", FabricEntityTypeBuilder.create(SpawnGroup.MISC, CastSpellEntity::new) .trackRangeBlocks(200) .dimensions(EntityDimensions.fixed(1, 1))); + EntityType SPELLBOOK = register("spellbook", FabricEntityTypeBuilder.create(SpawnGroup.MISC, SpellbookEntity::new) + .trackRangeBlocks(200) + .dimensions(EntityDimensions.fixed(1, 1))); static EntityType register(String name, FabricEntityTypeBuilder builder) { EntityType type = builder.build(); @@ -41,6 +43,7 @@ public interface UEntities { static void bootstrap() { FabricDefaultAttributeRegistry.register(BUTTERFLY, ButterflyEntity.createButterflyAttributes()); + FabricDefaultAttributeRegistry.register(SPELLBOOK, SpellbookEntity.createMobAttributes()); final Predicate butterflySpawnable = BiomeSelectors.foundInOverworld() .and(ctx -> ctx.getBiome().getPrecipitation() == Biome.Precipitation.RAIN); diff --git a/src/main/java/com/minelittlepony/unicopia/item/SpellbookItem.java b/src/main/java/com/minelittlepony/unicopia/item/SpellbookItem.java new file mode 100644 index 00000000..13c33771 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/item/SpellbookItem.java @@ -0,0 +1,83 @@ +package com.minelittlepony.unicopia.item; + +import org.jetbrains.annotations.Nullable; + +import com.minelittlepony.unicopia.EquinePredicates; +import com.minelittlepony.unicopia.entity.SpellbookEntity; +import com.minelittlepony.unicopia.entity.UEntities; +import com.minelittlepony.unicopia.util.Dispensable; + +import net.minecraft.block.DispenserBlock; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.BookItem; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemUsageContext; +import net.minecraft.util.ActionResult; +import net.minecraft.util.TypedActionResult; +import net.minecraft.util.math.BlockPointer; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.World; + +public class SpellbookItem extends BookItem implements Dispensable { + public SpellbookItem(Settings settings) { + super(settings); + DispenserBlock.registerBehavior(this, createDispenserBehaviour()); + } + + @Override + public TypedActionResult dispenseStack(BlockPointer source, ItemStack stack) { + Direction facing = source.getBlockState().get(DispenserBlock.FACING); + BlockPos pos = source.getBlockPos().offset(facing); + + float yaw = facing.getOpposite().asRotation(); + placeBook(source.getWorld(), pos.getX(), pos.getY(), pos.getZ(), yaw); + stack.decrement(1); + + return new TypedActionResult<>(ActionResult.SUCCESS, stack); + } + + @Override + public ActionResult useOnBlock(ItemUsageContext context) { + + @Nullable + PlayerEntity player = context.getPlayer(); + + if (!context.getWorld().isClient && EquinePredicates.PLAYER_UNICORN.test(player)) { + BlockPos pos = context.getBlockPos().offset(context.getSide()); + + placeBook(context.getWorld(), pos.getX(), pos.getY(), pos.getZ(), context.getPlayerYaw() + 180); + + if (!player.getAbilities().creativeMode) { + player.getStackInHand(context.getHand()).decrement(1); + } + + return ActionResult.SUCCESS; + } + return ActionResult.PASS; + } + + private static void placeBook(World world, int x, int y, int z, float yaw) { + SpellbookEntity book = UEntities.SPELLBOOK.create(world); + + book.refreshPositionAndAngles(x + 0.5, y, z + 0.5, 0, 0); + book.setHeadYaw(yaw); + book.setYaw(yaw); + world.spawnEntity(book); + } +} + + + + + + + + + + + + + + + diff --git a/src/main/java/com/minelittlepony/unicopia/item/UItems.java b/src/main/java/com/minelittlepony/unicopia/item/UItems.java index 90246f9d..24b4a068 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/UItems.java +++ b/src/main/java/com/minelittlepony/unicopia/item/UItems.java @@ -84,6 +84,8 @@ public interface UItems { Item BUTTERFLY_SPAWN_EGG = register("butterfly_spawn_egg", new SpawnEggItem(UEntities.BUTTERFLY, 0x222200, 0xaaeeff, new Item.Settings().group(ItemGroup.MISC))); Item BUTTERFLY = register("butterfly", new Item(new Item.Settings().group(ItemGroup.FOOD).food(UFoodComponents.INSECTS))); + Item SPELLBOOK = register("spellbook", new SpellbookItem(new Item.Settings().maxCount(1).rarity(Rarity.UNCOMMON).group(ItemGroup.TOOLS))); + AmuletItem PEGASUS_AMULET = register("pegasus_amulet", new AmuletItem(new FabricItemSettings() .maxCount(1) .maxDamage(890) diff --git a/src/main/java/com/minelittlepony/unicopia/util/Dispensable.java b/src/main/java/com/minelittlepony/unicopia/util/Dispensable.java new file mode 100644 index 00000000..b7479c1b --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/util/Dispensable.java @@ -0,0 +1,47 @@ +package com.minelittlepony.unicopia.util; + +import net.minecraft.block.dispenser.DispenserBehavior; +import net.minecraft.block.dispenser.ItemDispenserBehavior; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ActionResult; +import net.minecraft.util.TypedActionResult; +import net.minecraft.util.math.BlockPointer; +import net.minecraft.util.math.Direction; + +public interface Dispensable { + default DispenserBehavior createDispenserBehaviour() { + return new ItemDispenserBehavior() { + private ActionResult result; + @Override + protected ItemStack dispenseSilently(BlockPointer source, ItemStack stack) { + TypedActionResult result = dispenseStack(source, stack); + this.result = result.getResult(); + + if (!this.result.isAccepted()) { + return super.dispenseSilently(source, stack); + } + + return result.getValue(); + } + + @Override + protected void playSound(BlockPointer pointer) { + if (!result.isAccepted()) { + super.playSound(pointer); + } + } + + @Override + protected void spawnParticles(BlockPointer pointer, Direction side) { + if (!result.isAccepted()) { + super.spawnParticles(pointer, side); + } + } + }; + } + + /** + * Called to dispense this stack. + */ + TypedActionResult dispenseStack(BlockPointer source, ItemStack stack); +} diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index 6989a457..a52350f4 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -14,6 +14,8 @@ "item.unicopia.friendship_bracelet": "Bangle of Comradery", "item.unicopia.friendship_bracelet.issuer": "Signed by %s", "item.unicopia.friendship_bracelet.glowing": "Glowing", + + "item.unicopia.spellbook": "Spellbook", "item.unicopia.butterfly_spawn_egg": "Butterfly Spawn Egg", "item.unicopia.butterfly": "Butterfly", @@ -79,6 +81,7 @@ "entity.unicopia.butterfly": "Butterfly", "entity.unicopia.cast_spell": "Cast Spell", "entity.unicopia.cast_spell.by": "a spell cast by %s", + "entity.unicopia.spellbook": "Spellbook", "unicopia.effect.tribe.stage.initial": "It appears to have no effect.", "unicopia.effect.tribe.stage.crawling": "You feel the skin crawling on your back.", diff --git a/src/main/resources/assets/unicopia/models/item/spellbook.json b/src/main/resources/assets/unicopia/models/item/spellbook.json new file mode 100644 index 00000000..2f2a4302 --- /dev/null +++ b/src/main/resources/assets/unicopia/models/item/spellbook.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "unicopia:item/spellbook" + } +} diff --git a/src/main/resources/assets/unicopia/textures/entity/spellbook/blue.png b/src/main/resources/assets/unicopia/textures/entity/spellbook/blue.png new file mode 100644 index 00000000..40e640f5 Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/entity/spellbook/blue.png differ diff --git a/src/main/resources/assets/unicopia/textures/entity/spellbook/normal.png b/src/main/resources/assets/unicopia/textures/entity/spellbook/normal.png new file mode 100644 index 00000000..6f0afa4f Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/entity/spellbook/normal.png differ diff --git a/src/main/resources/assets/unicopia/textures/item/spellbook.png b/src/main/resources/assets/unicopia/textures/item/spellbook.png new file mode 100644 index 00000000..992380b0 Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/spellbook.png differ