From 0fad11c34643eb7630375f170650e695ea763b73 Mon Sep 17 00:00:00 2001 From: Sollace Date: Sat, 12 Aug 2023 20:43:37 +0100 Subject: [PATCH] Add item textures and basket/balloon designs, and try to prevent players from falling out --- .../entity/AirBalloonEntityRenderer.java | 20 +-- .../unicopia/entity/AirBalloonEntity.java | 125 ++++++++++++++---- .../unicopia/entity/Living.java | 45 ++++--- .../unicopia/item/BasketItem.java | 7 +- .../unicopia/item/HotAirBalloonItem.java | 24 ++++ .../minelittlepony/unicopia/item/UItems.java | 5 +- .../resources/assets/unicopia/lang/en_us.json | 3 + .../unicopia/models/item/giant_balloon.json | 6 + .../unicopia/models/item/oak_basket.json | 6 + .../{basket.png => basket/oak.png} | Bin .../{canopy.png => canopy/luna.png} | Bin .../unicopia/textures/item/giant_balloon.png | Bin 0 -> 6670 bytes .../unicopia/textures/item/oak_basket.png | Bin 0 -> 6555 bytes 13 files changed, 180 insertions(+), 61 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/item/HotAirBalloonItem.java create mode 100644 src/main/resources/assets/unicopia/models/item/giant_balloon.json create mode 100644 src/main/resources/assets/unicopia/models/item/oak_basket.json rename src/main/resources/assets/unicopia/textures/entity/air_balloon/{basket.png => basket/oak.png} (100%) rename src/main/resources/assets/unicopia/textures/entity/air_balloon/{canopy.png => canopy/luna.png} (100%) create mode 100644 src/main/resources/assets/unicopia/textures/item/giant_balloon.png create mode 100644 src/main/resources/assets/unicopia/textures/item/oak_basket.png diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/entity/AirBalloonEntityRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/entity/AirBalloonEntityRenderer.java index 4cfeeb37..27c61abb 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/entity/AirBalloonEntityRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/entity/AirBalloonEntityRenderer.java @@ -1,5 +1,6 @@ package com.minelittlepony.unicopia.client.render.entity; +import java.util.function.Function; import java.util.function.Predicate; import com.minelittlepony.unicopia.Unicopia; @@ -19,8 +20,8 @@ import net.minecraft.util.math.Box; public class AirBalloonEntityRenderer extends MobEntityRenderer { public AirBalloonEntityRenderer(EntityRendererFactory.Context context) { super(context, new AirBalloonEntityModel(AirBalloonEntityModel.getBasketModelData().createModel()), 0); - addFeature(new BalloonFeature("burner", new AirBalloonEntityModel(AirBalloonEntityModel.getBurnerModelData().createModel()), this, AirBalloonEntity::hasBurner)); - addFeature(new BalloonFeature("canopy", new AirBalloonEntityModel(AirBalloonEntityModel.getCanopyModelData().createModel()), this, AirBalloonEntity::hasBalloon)); + addFeature(new BalloonFeature(new AirBalloonEntityModel(AirBalloonEntityModel.getBurnerModelData().createModel()), this, AirBalloonEntity::hasBurner, e -> getComponentTexture("burner"))); + addFeature(new BalloonFeature(new AirBalloonEntityModel(AirBalloonEntityModel.getCanopyModelData().createModel()), this, AirBalloonEntity::hasBalloon, e -> getComponentTexture("canopy/" + e.getDesign().asString()))); } @Override @@ -36,7 +37,7 @@ public class AirBalloonEntityRenderer extends MobEntityRenderer { private final AirBalloonEntityModel model; private final Predicate visibilityTest; - private final String componentName; + private final Function textureFunc; - public BalloonFeature(String componentName, AirBalloonEntityModel model, + public BalloonFeature(AirBalloonEntityModel model, FeatureRendererContext context, - Predicate visibilityTest) { + Predicate visibilityTest, + Function textureFunc) { super(context); - this.componentName = componentName; this.model = model; this.visibilityTest = visibilityTest; + this.textureFunc = textureFunc; } @Override public void render(MatrixStack matrices, VertexConsumerProvider vertices, int light, AirBalloonEntity entity, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float yaw, float pitch) { if (visibilityTest.test(entity)) { - render(getModel(), model, getComponentTexture(entity, componentName), matrices, vertices, light, entity, limbAngle, limbDistance, 0, yaw, pitch, tickDelta, 1, 1, 1); + render(getModel(), model, textureFunc.apply(entity), matrices, vertices, light, entity, limbAngle, limbDistance, 0, yaw, pitch, tickDelta, 1, 1, 1); } } } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/AirBalloonEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/AirBalloonEntity.java index 5bb79eef..948431c6 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/AirBalloonEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/AirBalloonEntity.java @@ -5,36 +5,42 @@ import net.minecraft.entity.*; import net.minecraft.entity.data.*; import net.minecraft.entity.mob.FlyingEntity; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.vehicle.BoatEntity; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.nbt.NbtCompound; import net.minecraft.particle.ParticleTypes; import net.minecraft.sound.SoundEvents; -import net.minecraft.text.Text; import net.minecraft.util.ActionResult; import net.minecraft.util.Hand; +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; import net.minecraft.util.shape.VoxelShapes; import net.minecraft.world.World; +import net.minecraft.world.event.GameEvent; import java.util.List; +import java.util.Locale; import java.util.function.Consumer; +import java.util.function.IntFunction; import com.minelittlepony.unicopia.entity.collision.EntityCollisions; import com.minelittlepony.unicopia.entity.collision.MultiBox; import com.minelittlepony.unicopia.entity.duck.EntityDuck; -import com.minelittlepony.unicopia.item.UItems; +import com.minelittlepony.unicopia.item.HotAirBalloonItem; import com.minelittlepony.unicopia.server.world.WeatherConditions; public class AirBalloonEntity extends FlyingEntity implements EntityCollisions.ComplexCollidable, MultiBoundingBoxEntity { - private static final byte HAS_BALLOON = 1; private static final byte HAS_BURNER = 2; private static final byte BURNER_ACTIVE = 4; - private static final TrackedData FLAGS = DataTracker.registerData(AirBalloonEntity.class, TrackedDataHandlerRegistry.INTEGER); + private static final TrackedData BURNER_FLAGS = DataTracker.registerData(AirBalloonEntity.class, TrackedDataHandlerRegistry.INTEGER); private static final TrackedData BOOSTING = DataTracker.registerData(AirBalloonEntity.class, TrackedDataHandlerRegistry.INTEGER); private static final TrackedData INFLATION = DataTracker.registerData(AirBalloonEntity.class, TrackedDataHandlerRegistry.INTEGER); + private static final TrackedData BASKET_TYPE = DataTracker.registerData(AirBalloonEntity.class, TrackedDataHandlerRegistry.INTEGER); + private static final TrackedData BALLOON_DESIGN = DataTracker.registerData(AirBalloonEntity.class, TrackedDataHandlerRegistry.INTEGER); private boolean prevBoosting; private int prevInflation; @@ -43,23 +49,38 @@ public class AirBalloonEntity extends FlyingEntity implements EntityCollisions.C public AirBalloonEntity(EntityType type, World world) { super(type, world); + intersectionChecked = true; setPersistent(); } @Override protected void initDataTracker() { super.initDataTracker(); - dataTracker.startTracking(FLAGS, 0); + dataTracker.startTracking(BURNER_FLAGS, 0); dataTracker.startTracking(BOOSTING, 0); dataTracker.startTracking(INFLATION, 0); + dataTracker.startTracking(BASKET_TYPE, 0); + dataTracker.startTracking(BALLOON_DESIGN, 0); + } + + public BoatEntity.Type getBasketType() { + return BoatEntity.Type.getType(dataTracker.get(BASKET_TYPE)); + } + + public void setBasketType(BoatEntity.Type type) { + dataTracker.set(BASKET_TYPE, type.ordinal()); + } + + public BalloonDesign getDesign() { + return BalloonDesign.getType(dataTracker.get(BALLOON_DESIGN)); + } + + public void setDesign(BalloonDesign design) { + dataTracker.set(BALLOON_DESIGN, design.ordinal()); } public boolean hasBalloon() { - return getFlag(HAS_BALLOON); - } - - public void setHasBalloon(boolean hasBalloon) { - setFlag(HAS_BALLOON, hasBalloon); + return getDesign() != BalloonDesign.NONE; } public boolean hasBurner() { @@ -87,7 +108,7 @@ public class AirBalloonEntity extends FlyingEntity implements EntityCollisions.C } public boolean isBurnerActive() { - return getFlag((byte)(HAS_BURNER | BURNER_ACTIVE | HAS_BALLOON)); + return hasBalloon() && getFlag((byte)(HAS_BURNER | BURNER_ACTIVE)); } public void setBurnerActive(boolean burnerActive) { @@ -103,12 +124,12 @@ public class AirBalloonEntity extends FlyingEntity implements EntityCollisions.C } private boolean getFlag(byte flag) { - return (dataTracker.get(FLAGS).intValue() & flag) == flag; + return (dataTracker.get(BURNER_FLAGS).intValue() & flag) == flag; } private void setFlag(byte flag, boolean val) { - int v = dataTracker.get(FLAGS); - dataTracker.set(FLAGS, val ? (v | flag) : (v & ~flag)); + int v = dataTracker.get(BURNER_FLAGS); + dataTracker.set(BURNER_FLAGS, val ? (v | flag) : (v & ~flag)); } private boolean isAirworthy() { @@ -212,20 +233,23 @@ public class AirBalloonEntity extends FlyingEntity implements EntityCollisions.C prevBoosting = boosting; oldPosition = getPos(); - for (Box box : getBoundingBoxes()) { - for (Entity e : getWorld().getOtherEntities(this, box.expand(0, 0.5, 0).stretch(getVelocity().multiply(-1)))) { - updatePassenger(e, box, e.getY() > getY() + 3); - } - } - if (getFireTicks() > 0) { setFireTicks(1); } + updatePassengers(); super.tick(); setBoundingBox(MultiBox.of(getBoundingBox(), getBoundingBoxes())); } + private void updatePassengers() { + for (Box box : getBoundingBoxes()) { + for (Entity e : getWorld().getOtherEntities(this, box.expand(getVelocity().length()).expand(0, 0.5, 0))) { + updatePassenger(e, box, e.getY() > getY() + 3); + } + } + } + private void updatePassenger(Entity e, Box box, boolean inBalloon) { double height = box.getYLength(); @@ -239,7 +263,14 @@ public class AirBalloonEntity extends FlyingEntity implements EntityCollisions.C } } - e.setVelocity(e.getVelocity().multiply(0.1, 0.5, 0.1)); + if (manualVelocity.length() > 0.01 || getVelocity().length() > 0.3) { + e.setVelocity(e.getVelocity().multiply(0.1, 0.5, 0.1)); + } + + if (getVelocity().y < 0) { + e.addVelocity(0, getVelocity().y, 0); + Living.updateVelocity(e); + } if (inBalloon && !e.isSneaky() && Math.abs(e.getVelocity().y) > 0.079) { e.setVelocity(e.getVelocity().multiply(1, e.getVelocity().y < 0 ? -0.9 : 1.2, 1).add(0, 0.8, 0)); @@ -257,8 +288,10 @@ public class AirBalloonEntity extends FlyingEntity implements EntityCollisions.C if (getWorld().isClient) { if (e.distanceTraveled > ((EntityDuck)e).getNextStepSoundDistance()) { e.distanceTraveled--; - e.playSound(inBalloon ? SoundEvents.BLOCK_WOOL_STEP : SoundEvents.BLOCK_BAMBOO_STEP, 0.5F, 1); + if (!e.isSneaky()) { + getWorld().emitGameEvent(e, GameEvent.STEP, getBlockPos()); + } } } } @@ -276,6 +309,7 @@ public class AirBalloonEntity extends FlyingEntity implements EntityCollisions.C } stack.damage(1, player, p -> p.sendEquipmentBreakStatus(hand == Hand.MAIN_HAND ? EquipmentSlot.MAINHAND : EquipmentSlot.OFFHAND)); playSound(SoundEvents.ITEM_FLINTANDSTEEL_USE, 1, 1); + getWorld().emitGameEvent(this, GameEvent.ENTITY_INTERACT, getBlockPos()); return ActionResult.SUCCESS; } @@ -287,11 +321,11 @@ public class AirBalloonEntity extends FlyingEntity implements EntityCollisions.C } } else if (stack.isEmpty() && isBurnerActive()) { setBoostTicks(50); + getWorld().emitGameEvent(this, GameEvent.ENTITY_INTERACT, getBlockPos()); } } } - player.sendMessage(Text.literal(hitPos + "")); return ActionResult.PASS; } @@ -299,14 +333,13 @@ public class AirBalloonEntity extends FlyingEntity implements EntityCollisions.C protected ActionResult interactMob(PlayerEntity player, Hand hand) { ItemStack stack = player.getStackInHand(hand); - - - if (stack.isOf(UItems.LARGE_BALLOON) && !hasBalloon()) { + if (stack.getItem() instanceof HotAirBalloonItem balloon && !hasBalloon()) { if (!player.getAbilities().creativeMode) { stack.decrement(1); } playSound(SoundEvents.ITEM_ARMOR_EQUIP_LEATHER, 1, 1); - setHasBalloon(true); + getWorld().emitGameEvent(this, GameEvent.ENTITY_INTERACT, getBlockPos()); + setDesign(HotAirBalloonItem.getDesign(getWorld(), stack)); return ActionResult.SUCCESS; } @@ -315,6 +348,7 @@ public class AirBalloonEntity extends FlyingEntity implements EntityCollisions.C stack.decrement(1); } playSound(SoundEvents.ENTITY_IRON_GOLEM_DAMAGE, 0.2F, 1); + getWorld().emitGameEvent(this, GameEvent.ENTITY_INTERACT, getBlockPos()); setHasBurner(true); return ActionResult.SUCCESS; } @@ -334,6 +368,7 @@ public class AirBalloonEntity extends FlyingEntity implements EntityCollisions.C @Override public void pushAwayFrom(Entity entity) { + } @Override @@ -341,6 +376,12 @@ public class AirBalloonEntity extends FlyingEntity implements EntityCollisions.C } + @Override + protected Entity.MoveEffect getMoveEffect() { + return Entity.MoveEffect.EVENTS; + } + + @Override public Box getVisibilityBoundingBox() { if (hasBalloon()) { @@ -391,7 +432,8 @@ public class AirBalloonEntity extends FlyingEntity implements EntityCollisions.C @Override public void readCustomDataFromNbt(NbtCompound compound) { super.readCustomDataFromNbt(compound); - setHasBalloon(compound.getBoolean("hasBalloon")); + setBasketType(BoatEntity.Type.getType(compound.getString("basketType"))); + setDesign(BalloonDesign.getType(compound.getString("design"))); setHasBurner(compound.getBoolean("hasBurner")); setBurnerActive(compound.getBoolean("burnerActive")); setBoostTicks(compound.getInt("boostTicks")); @@ -402,12 +444,37 @@ public class AirBalloonEntity extends FlyingEntity implements EntityCollisions.C @Override public void writeCustomDataToNbt(NbtCompound compound) { super.writeCustomDataToNbt(compound); - compound.putBoolean("hasBalloon", hasBalloon()); + compound.putString("design", getDesign().asString()); + compound.putString("basket", getBasketType().asString()); compound.putBoolean("hasBurner", hasBurner()); compound.putBoolean("burnerActive", isBurnerActive()); compound.putInt("boostTicks", getBoostTicks()); compound.putInt("inflationAmount", getInflation()); } + + @SuppressWarnings("deprecation") + public enum BalloonDesign implements StringIdentifiable { + NONE, + LUNA; + + public static final StringIdentifiable.Codec CODEC = StringIdentifiable.createCodec(BalloonDesign::values); + private static final IntFunction BY_ID = ValueLists.createIdToValueFunction(Enum::ordinal, values(), ValueLists.OutOfBoundsHandling.ZERO); + + private final String name = name().toLowerCase(Locale.ROOT); + + @Override + public String asString() { + return name; + } + + public static BalloonDesign getType(int type) { + return BY_ID.apply(type); + } + + public static BalloonDesign getType(String name) { + return CODEC.byId(name, LUNA); + } + } } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Living.java b/src/main/java/com/minelittlepony/unicopia/entity/Living.java index 8dce0045..5679cd66 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Living.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Living.java @@ -77,6 +77,7 @@ public abstract class Living implements Equine, Caste @Nullable private Vec3d supportPositionOffset; + private int ticksOutsideVehicle; @Nullable private Caster attacker; @@ -181,6 +182,9 @@ public abstract class Living implements Equine, Caste public void setSupportingEntity(Entity supportingEntity) { this.supportingEntity = supportingEntity; + if (supportingEntity != null) { + ticksOutsideVehicle = 0; + } } public void setPositionOffset(@Nullable Vec3d positionOffset) { @@ -191,19 +195,6 @@ public abstract class Living implements Equine, Caste setPositionOffset(supportingEntity == null ? null : entity.getPos().subtract(supportingEntity.getPos())); } - public static void checkGroundCollission(Entity entity, Box box) { - double height = box.getYLength(); - - if (height < 3 || entity.getBoundingBox().minY > box.minY + height / 2D) { - if (entity.getBoundingBox().minY < box.maxY) { - entity.setPos(entity.getX(), box.maxY - 0.002, entity.getZ()); - } - if (entity.getBoundingBox().minY > box.maxY) { - entity.setPos(entity.getX(), box.maxY - 0.002, entity.getZ()); - } - } - } - public void updateRelativePosition(Box box) { if (supportingEntity == null || supportPositionOffset == null) { return; @@ -251,11 +242,16 @@ public abstract class Living implements Equine, Caste public void updateSupportingEntity() { if (supportingEntity != null) { - Box ownBox = entity.getBoundingBox().expand(0.1); + Box ownBox = entity.getBoundingBox() + .stretch(entity.getVelocity()) + .expand(0.1, 0.5, 0.1) + .stretch(supportingEntity.getVelocity().multiply(-2)); - MultiBoundingBoxEntity.getBoundingBoxes(supportingEntity).stream().filter(box -> { - return box.expand(0, 0.5, 0).intersects(ownBox); - }).findFirst().ifPresentOrElse(box -> { + MultiBoundingBoxEntity.getBoundingBoxes(supportingEntity).stream() + .filter(box -> box.stretch(supportingEntity.getVelocity()).expand(0, 0.5, 0).intersects(ownBox)) + .findFirst() + .ifPresentOrElse(box -> { + ticksOutsideVehicle = 0; if (supportPositionOffset == null) { updatePositionOffset(); } else { @@ -265,8 +261,14 @@ public abstract class Living implements Equine, Caste entity.verticalCollision = true; entity.groundCollision = true; }, () -> { - supportingEntity = null; - supportPositionOffset = null; + // Rubberband passengers to try and prevent players falling out when the velocity changes suddenly + if (ticksOutsideVehicle++ > 30) { + supportingEntity = null; + supportPositionOffset = null; + Unicopia.LOGGER.info("Entity left vehicle"); + } else { + supportPositionOffset = supportPositionOffset.multiply(0.25, 1, 0.25); + } }); } @@ -320,7 +322,10 @@ public abstract class Living implements Equine, Caste } updateDragonBreath(); - updatePositionOffset(); + + if (ticksOutsideVehicle == 0) { + updatePositionOffset(); + } } public void updateAttributeModifier(UUID id, EntityAttribute attribute, float desiredValue, Float2ObjectFunction modifierSupplier, boolean permanent) { diff --git a/src/main/java/com/minelittlepony/unicopia/item/BasketItem.java b/src/main/java/com/minelittlepony/unicopia/item/BasketItem.java index 6161eb58..35ee94f6 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/BasketItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/BasketItem.java @@ -11,6 +11,7 @@ import com.minelittlepony.unicopia.util.Dispensable; import net.minecraft.block.DispenserBlock; import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.vehicle.BoatEntity; import net.minecraft.item.BoatItem; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; @@ -31,8 +32,11 @@ public class BasketItem extends Item implements Dispensable { private static final Predicate RIDERS = EntityPredicates.EXCEPT_SPECTATOR.and(Entity::canHit); private static final double REACH = 5; - public BasketItem(Item.Settings settings) { + private final BoatEntity.Type type; + + public BasketItem(BoatEntity.Type type, Item.Settings settings) { super(settings); + this.type = type; DispenserBlock.registerBehavior(this, createDispenserBehaviour()); } @@ -71,6 +75,7 @@ public class BasketItem extends Item implements Dispensable { entity.updatePositionAndAngles(x, y, z, 0, 0); entity.setHeadYaw(yaw); entity.setBodyYaw(yaw); + entity.setBasketType(type); if (!world.isSpaceEmpty(entity, entity.getBoundingBox())) { return TypedActionResult.fail(stack); } diff --git a/src/main/java/com/minelittlepony/unicopia/item/HotAirBalloonItem.java b/src/main/java/com/minelittlepony/unicopia/item/HotAirBalloonItem.java new file mode 100644 index 00000000..dca94801 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/item/HotAirBalloonItem.java @@ -0,0 +1,24 @@ +package com.minelittlepony.unicopia.item; + +import com.minelittlepony.unicopia.entity.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); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/item/UItems.java b/src/main/java/com/minelittlepony/unicopia/item/UItems.java index 8e6aa552..5e6a382d 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/UItems.java +++ b/src/main/java/com/minelittlepony/unicopia/item/UItems.java @@ -11,6 +11,7 @@ import com.minelittlepony.unicopia.item.group.ItemGroupRegistry; import com.minelittlepony.unicopia.item.group.UItemGroups; import com.minelittlepony.unicopia.item.toxin.UFoodComponents; +import net.minecraft.entity.vehicle.BoatEntity; import net.minecraft.item.*; import net.minecraft.item.Item.Settings; import net.fabricmc.fabric.api.item.v1.FabricItemSettings; @@ -118,8 +119,8 @@ public interface UItems { Item BUTTERFLY = register("butterfly", new Item(new Item.Settings().food(UFoodComponents.INSECTS)), ItemGroups.FOOD_AND_DRINK); Item SPELLBOOK = register("spellbook", new SpellbookItem(new Item.Settings().maxCount(1).rarity(Rarity.UNCOMMON)), ItemGroups.TOOLS); - Item BASKET = register("basket", new BasketItem(new Item.Settings().maxCount(1)), ItemGroups.FUNCTIONAL); - Item LARGE_BALLOON = register("large_balloon", new Item(new Item.Settings().maxCount(1)), ItemGroups.FUNCTIONAL); + Item OAK_BASKET = register("oak_basket", new BasketItem(BoatEntity.Type.OAK, new Item.Settings().maxCount(1)), ItemGroups.FUNCTIONAL); + Item GIANT_BALLOON = register("giant_balloon", new HotAirBalloonItem(new Item.Settings().maxCount(1)), ItemGroups.FUNCTIONAL); AmuletItem PEGASUS_AMULET = register("pegasus_amulet", new PegasusAmuletItem(new FabricItemSettings() .maxCount(1) diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index e0767889..f96d69d2 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -23,6 +23,9 @@ "item.unicopia.friendship_bracelet.issuer": "Signed by %s", "item.unicopia.friendship_bracelet.glowing": "Glowing", + "item.unicopia.oak_basket": "Oak Basket", + "item.unicopia.giant_balloon": "Giant Balloon", + "item.unicopia.spellbook": "Spellbook", "emi.category.unicopia.spellbook": "Spellbook", diff --git a/src/main/resources/assets/unicopia/models/item/giant_balloon.json b/src/main/resources/assets/unicopia/models/item/giant_balloon.json new file mode 100644 index 00000000..4df680ac --- /dev/null +++ b/src/main/resources/assets/unicopia/models/item/giant_balloon.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "unicopia:item/giant_balloon" + } +} diff --git a/src/main/resources/assets/unicopia/models/item/oak_basket.json b/src/main/resources/assets/unicopia/models/item/oak_basket.json new file mode 100644 index 00000000..6302a186 --- /dev/null +++ b/src/main/resources/assets/unicopia/models/item/oak_basket.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "unicopia:item/oak_basket" + } +} diff --git a/src/main/resources/assets/unicopia/textures/entity/air_balloon/basket.png b/src/main/resources/assets/unicopia/textures/entity/air_balloon/basket/oak.png similarity index 100% rename from src/main/resources/assets/unicopia/textures/entity/air_balloon/basket.png rename to src/main/resources/assets/unicopia/textures/entity/air_balloon/basket/oak.png diff --git a/src/main/resources/assets/unicopia/textures/entity/air_balloon/canopy.png b/src/main/resources/assets/unicopia/textures/entity/air_balloon/canopy/luna.png similarity index 100% rename from src/main/resources/assets/unicopia/textures/entity/air_balloon/canopy.png rename to src/main/resources/assets/unicopia/textures/entity/air_balloon/canopy/luna.png diff --git a/src/main/resources/assets/unicopia/textures/item/giant_balloon.png b/src/main/resources/assets/unicopia/textures/item/giant_balloon.png new file mode 100644 index 0000000000000000000000000000000000000000..31c7d9eac8097f56525e5e7d276954efcbd8c698 GIT binary patch literal 6670 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 H-Rge