Add item textures and basket/balloon designs, and try to prevent players from falling out

This commit is contained in:
Sollace 2023-08-12 20:43:37 +01:00
parent f7777358e2
commit 0fad11c346
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
13 changed files with 180 additions and 61 deletions

View file

@ -1,5 +1,6 @@
package com.minelittlepony.unicopia.client.render.entity; package com.minelittlepony.unicopia.client.render.entity;
import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.Unicopia;
@ -19,8 +20,8 @@ import net.minecraft.util.math.Box;
public class AirBalloonEntityRenderer extends MobEntityRenderer<AirBalloonEntity, AirBalloonEntityModel> { public class AirBalloonEntityRenderer extends MobEntityRenderer<AirBalloonEntity, AirBalloonEntityModel> {
public AirBalloonEntityRenderer(EntityRendererFactory.Context context) { public AirBalloonEntityRenderer(EntityRendererFactory.Context context) {
super(context, new AirBalloonEntityModel(AirBalloonEntityModel.getBasketModelData().createModel()), 0); super(context, new AirBalloonEntityModel(AirBalloonEntityModel.getBasketModelData().createModel()), 0);
addFeature(new BalloonFeature("burner", new AirBalloonEntityModel(AirBalloonEntityModel.getBurnerModelData().createModel()), this, AirBalloonEntity::hasBurner)); addFeature(new BalloonFeature(new AirBalloonEntityModel(AirBalloonEntityModel.getBurnerModelData().createModel()), this, AirBalloonEntity::hasBurner, e -> getComponentTexture("burner")));
addFeature(new BalloonFeature("canopy", new AirBalloonEntityModel(AirBalloonEntityModel.getCanopyModelData().createModel()), this, AirBalloonEntity::hasBalloon)); addFeature(new BalloonFeature(new AirBalloonEntityModel(AirBalloonEntityModel.getCanopyModelData().createModel()), this, AirBalloonEntity::hasBalloon, e -> getComponentTexture("canopy/" + e.getDesign().asString())));
} }
@Override @Override
@ -36,7 +37,7 @@ public class AirBalloonEntityRenderer extends MobEntityRenderer<AirBalloonEntity
@Override @Override
public Identifier getTexture(AirBalloonEntity entity) { public Identifier getTexture(AirBalloonEntity entity) {
return getComponentTexture(entity, "basket"); return getComponentTexture("basket/" + entity.getBasketType().asString());
} }
@Override @Override
@ -44,29 +45,30 @@ public class AirBalloonEntityRenderer extends MobEntityRenderer<AirBalloonEntity
return 0; return 0;
} }
private Identifier getComponentTexture(AirBalloonEntity entity, String componentName) { private Identifier getComponentTexture(String componentName) {
return Unicopia.id("textures/entity/air_balloon/" + componentName + ".png"); return Unicopia.id("textures/entity/air_balloon/" + componentName + ".png");
} }
final class BalloonFeature extends FeatureRenderer<AirBalloonEntity, AirBalloonEntityModel> { final class BalloonFeature extends FeatureRenderer<AirBalloonEntity, AirBalloonEntityModel> {
private final AirBalloonEntityModel model; private final AirBalloonEntityModel model;
private final Predicate<AirBalloonEntity> visibilityTest; private final Predicate<AirBalloonEntity> visibilityTest;
private final String componentName; private final Function<AirBalloonEntity, Identifier> textureFunc;
public BalloonFeature(String componentName, AirBalloonEntityModel model, public BalloonFeature(AirBalloonEntityModel model,
FeatureRendererContext<AirBalloonEntity, AirBalloonEntityModel> context, FeatureRendererContext<AirBalloonEntity, AirBalloonEntityModel> context,
Predicate<AirBalloonEntity> visibilityTest) { Predicate<AirBalloonEntity> visibilityTest,
Function<AirBalloonEntity, Identifier> textureFunc) {
super(context); super(context);
this.componentName = componentName;
this.model = model; this.model = model;
this.visibilityTest = visibilityTest; this.visibilityTest = visibilityTest;
this.textureFunc = textureFunc;
} }
@Override @Override
public void render(MatrixStack matrices, VertexConsumerProvider vertices, int light, AirBalloonEntity entity, public void render(MatrixStack matrices, VertexConsumerProvider vertices, int light, AirBalloonEntity entity,
float limbAngle, float limbDistance, float tickDelta, float animationProgress, float yaw, float pitch) { float limbAngle, float limbDistance, float tickDelta, float animationProgress, float yaw, float pitch) {
if (visibilityTest.test(entity)) { 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);
} }
} }
} }

View file

@ -5,36 +5,42 @@ import net.minecraft.entity.*;
import net.minecraft.entity.data.*; import net.minecraft.entity.data.*;
import net.minecraft.entity.mob.FlyingEntity; import net.minecraft.entity.mob.FlyingEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.vehicle.BoatEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.Items; import net.minecraft.item.Items;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
import net.minecraft.particle.ParticleTypes; import net.minecraft.particle.ParticleTypes;
import net.minecraft.sound.SoundEvents; import net.minecraft.sound.SoundEvents;
import net.minecraft.text.Text;
import net.minecraft.util.ActionResult; import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand; 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.*;
import net.minecraft.util.math.random.Random; import net.minecraft.util.math.random.Random;
import net.minecraft.util.shape.VoxelShape; import net.minecraft.util.shape.VoxelShape;
import net.minecraft.util.shape.VoxelShapes; import net.minecraft.util.shape.VoxelShapes;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.event.GameEvent;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.IntFunction;
import com.minelittlepony.unicopia.entity.collision.EntityCollisions; import com.minelittlepony.unicopia.entity.collision.EntityCollisions;
import com.minelittlepony.unicopia.entity.collision.MultiBox; import com.minelittlepony.unicopia.entity.collision.MultiBox;
import com.minelittlepony.unicopia.entity.duck.EntityDuck; 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; import com.minelittlepony.unicopia.server.world.WeatherConditions;
public class AirBalloonEntity extends FlyingEntity implements EntityCollisions.ComplexCollidable, MultiBoundingBoxEntity { 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 HAS_BURNER = 2;
private static final byte BURNER_ACTIVE = 4; private static final byte BURNER_ACTIVE = 4;
private static final TrackedData<Integer> FLAGS = DataTracker.registerData(AirBalloonEntity.class, TrackedDataHandlerRegistry.INTEGER); private static final TrackedData<Integer> BURNER_FLAGS = DataTracker.registerData(AirBalloonEntity.class, TrackedDataHandlerRegistry.INTEGER);
private static final TrackedData<Integer> BOOSTING = DataTracker.registerData(AirBalloonEntity.class, TrackedDataHandlerRegistry.INTEGER); private static final TrackedData<Integer> BOOSTING = DataTracker.registerData(AirBalloonEntity.class, TrackedDataHandlerRegistry.INTEGER);
private static final TrackedData<Integer> INFLATION = DataTracker.registerData(AirBalloonEntity.class, TrackedDataHandlerRegistry.INTEGER); private static final TrackedData<Integer> INFLATION = DataTracker.registerData(AirBalloonEntity.class, TrackedDataHandlerRegistry.INTEGER);
private static final TrackedData<Integer> BASKET_TYPE = DataTracker.registerData(AirBalloonEntity.class, TrackedDataHandlerRegistry.INTEGER);
private static final TrackedData<Integer> BALLOON_DESIGN = DataTracker.registerData(AirBalloonEntity.class, TrackedDataHandlerRegistry.INTEGER);
private boolean prevBoosting; private boolean prevBoosting;
private int prevInflation; private int prevInflation;
@ -43,23 +49,38 @@ public class AirBalloonEntity extends FlyingEntity implements EntityCollisions.C
public AirBalloonEntity(EntityType<? extends AirBalloonEntity> type, World world) { public AirBalloonEntity(EntityType<? extends AirBalloonEntity> type, World world) {
super(type, world); super(type, world);
intersectionChecked = true;
setPersistent(); setPersistent();
} }
@Override @Override
protected void initDataTracker() { protected void initDataTracker() {
super.initDataTracker(); super.initDataTracker();
dataTracker.startTracking(FLAGS, 0); dataTracker.startTracking(BURNER_FLAGS, 0);
dataTracker.startTracking(BOOSTING, 0); dataTracker.startTracking(BOOSTING, 0);
dataTracker.startTracking(INFLATION, 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() { public boolean hasBalloon() {
return getFlag(HAS_BALLOON); return getDesign() != BalloonDesign.NONE;
}
public void setHasBalloon(boolean hasBalloon) {
setFlag(HAS_BALLOON, hasBalloon);
} }
public boolean hasBurner() { public boolean hasBurner() {
@ -87,7 +108,7 @@ public class AirBalloonEntity extends FlyingEntity implements EntityCollisions.C
} }
public boolean isBurnerActive() { 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) { public void setBurnerActive(boolean burnerActive) {
@ -103,12 +124,12 @@ public class AirBalloonEntity extends FlyingEntity implements EntityCollisions.C
} }
private boolean getFlag(byte flag) { 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) { private void setFlag(byte flag, boolean val) {
int v = dataTracker.get(FLAGS); int v = dataTracker.get(BURNER_FLAGS);
dataTracker.set(FLAGS, val ? (v | flag) : (v & ~flag)); dataTracker.set(BURNER_FLAGS, val ? (v | flag) : (v & ~flag));
} }
private boolean isAirworthy() { private boolean isAirworthy() {
@ -212,20 +233,23 @@ public class AirBalloonEntity extends FlyingEntity implements EntityCollisions.C
prevBoosting = boosting; prevBoosting = boosting;
oldPosition = getPos(); 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) { if (getFireTicks() > 0) {
setFireTicks(1); setFireTicks(1);
} }
updatePassengers();
super.tick(); super.tick();
setBoundingBox(MultiBox.of(getBoundingBox(), getBoundingBoxes())); 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) { private void updatePassenger(Entity e, Box box, boolean inBalloon) {
double height = box.getYLength(); 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) { 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)); 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 (getWorld().isClient) {
if (e.distanceTraveled > ((EntityDuck)e).getNextStepSoundDistance()) { if (e.distanceTraveled > ((EntityDuck)e).getNextStepSoundDistance()) {
e.distanceTraveled--; e.distanceTraveled--;
e.playSound(inBalloon ? SoundEvents.BLOCK_WOOL_STEP : SoundEvents.BLOCK_BAMBOO_STEP, 0.5F, 1); 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)); stack.damage(1, player, p -> p.sendEquipmentBreakStatus(hand == Hand.MAIN_HAND ? EquipmentSlot.MAINHAND : EquipmentSlot.OFFHAND));
playSound(SoundEvents.ITEM_FLINTANDSTEEL_USE, 1, 1); playSound(SoundEvents.ITEM_FLINTANDSTEEL_USE, 1, 1);
getWorld().emitGameEvent(this, GameEvent.ENTITY_INTERACT, getBlockPos());
return ActionResult.SUCCESS; return ActionResult.SUCCESS;
} }
@ -287,11 +321,11 @@ public class AirBalloonEntity extends FlyingEntity implements EntityCollisions.C
} }
} else if (stack.isEmpty() && isBurnerActive()) { } else if (stack.isEmpty() && isBurnerActive()) {
setBoostTicks(50); setBoostTicks(50);
getWorld().emitGameEvent(this, GameEvent.ENTITY_INTERACT, getBlockPos());
} }
} }
} }
player.sendMessage(Text.literal(hitPos + ""));
return ActionResult.PASS; return ActionResult.PASS;
} }
@ -299,14 +333,13 @@ public class AirBalloonEntity extends FlyingEntity implements EntityCollisions.C
protected ActionResult interactMob(PlayerEntity player, Hand hand) { protected ActionResult interactMob(PlayerEntity player, Hand hand) {
ItemStack stack = player.getStackInHand(hand); ItemStack stack = player.getStackInHand(hand);
if (stack.getItem() instanceof HotAirBalloonItem balloon && !hasBalloon()) {
if (stack.isOf(UItems.LARGE_BALLOON) && !hasBalloon()) {
if (!player.getAbilities().creativeMode) { if (!player.getAbilities().creativeMode) {
stack.decrement(1); stack.decrement(1);
} }
playSound(SoundEvents.ITEM_ARMOR_EQUIP_LEATHER, 1, 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; return ActionResult.SUCCESS;
} }
@ -315,6 +348,7 @@ public class AirBalloonEntity extends FlyingEntity implements EntityCollisions.C
stack.decrement(1); stack.decrement(1);
} }
playSound(SoundEvents.ENTITY_IRON_GOLEM_DAMAGE, 0.2F, 1); playSound(SoundEvents.ENTITY_IRON_GOLEM_DAMAGE, 0.2F, 1);
getWorld().emitGameEvent(this, GameEvent.ENTITY_INTERACT, getBlockPos());
setHasBurner(true); setHasBurner(true);
return ActionResult.SUCCESS; return ActionResult.SUCCESS;
} }
@ -334,6 +368,7 @@ public class AirBalloonEntity extends FlyingEntity implements EntityCollisions.C
@Override @Override
public void pushAwayFrom(Entity entity) { public void pushAwayFrom(Entity entity) {
} }
@Override @Override
@ -341,6 +376,12 @@ public class AirBalloonEntity extends FlyingEntity implements EntityCollisions.C
} }
@Override
protected Entity.MoveEffect getMoveEffect() {
return Entity.MoveEffect.EVENTS;
}
@Override @Override
public Box getVisibilityBoundingBox() { public Box getVisibilityBoundingBox() {
if (hasBalloon()) { if (hasBalloon()) {
@ -391,7 +432,8 @@ public class AirBalloonEntity extends FlyingEntity implements EntityCollisions.C
@Override @Override
public void readCustomDataFromNbt(NbtCompound compound) { public void readCustomDataFromNbt(NbtCompound compound) {
super.readCustomDataFromNbt(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")); setHasBurner(compound.getBoolean("hasBurner"));
setBurnerActive(compound.getBoolean("burnerActive")); setBurnerActive(compound.getBoolean("burnerActive"));
setBoostTicks(compound.getInt("boostTicks")); setBoostTicks(compound.getInt("boostTicks"));
@ -402,12 +444,37 @@ public class AirBalloonEntity extends FlyingEntity implements EntityCollisions.C
@Override @Override
public void writeCustomDataToNbt(NbtCompound compound) { public void writeCustomDataToNbt(NbtCompound compound) {
super.writeCustomDataToNbt(compound); super.writeCustomDataToNbt(compound);
compound.putBoolean("hasBalloon", hasBalloon()); compound.putString("design", getDesign().asString());
compound.putString("basket", getBasketType().asString());
compound.putBoolean("hasBurner", hasBurner()); compound.putBoolean("hasBurner", hasBurner());
compound.putBoolean("burnerActive", isBurnerActive()); compound.putBoolean("burnerActive", isBurnerActive());
compound.putInt("boostTicks", getBoostTicks()); compound.putInt("boostTicks", getBoostTicks());
compound.putInt("inflationAmount", getInflation()); compound.putInt("inflationAmount", getInflation());
} }
@SuppressWarnings("deprecation")
public enum BalloonDesign implements StringIdentifiable {
NONE,
LUNA;
public static final StringIdentifiable.Codec<BalloonDesign> CODEC = StringIdentifiable.createCodec(BalloonDesign::values);
private static final IntFunction<BalloonDesign> BY_ID = ValueLists.<BalloonDesign>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);
}
}
} }

View file

@ -77,6 +77,7 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
@Nullable @Nullable
private Vec3d supportPositionOffset; private Vec3d supportPositionOffset;
private int ticksOutsideVehicle;
@Nullable @Nullable
private Caster<?> attacker; private Caster<?> attacker;
@ -181,6 +182,9 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
public void setSupportingEntity(Entity supportingEntity) { public void setSupportingEntity(Entity supportingEntity) {
this.supportingEntity = supportingEntity; this.supportingEntity = supportingEntity;
if (supportingEntity != null) {
ticksOutsideVehicle = 0;
}
} }
public void setPositionOffset(@Nullable Vec3d positionOffset) { public void setPositionOffset(@Nullable Vec3d positionOffset) {
@ -191,19 +195,6 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
setPositionOffset(supportingEntity == null ? null : entity.getPos().subtract(supportingEntity.getPos())); 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) { public void updateRelativePosition(Box box) {
if (supportingEntity == null || supportPositionOffset == null) { if (supportingEntity == null || supportPositionOffset == null) {
return; return;
@ -251,11 +242,16 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
public void updateSupportingEntity() { public void updateSupportingEntity() {
if (supportingEntity != null) { 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 -> { MultiBoundingBoxEntity.getBoundingBoxes(supportingEntity).stream()
return box.expand(0, 0.5, 0).intersects(ownBox); .filter(box -> box.stretch(supportingEntity.getVelocity()).expand(0, 0.5, 0).intersects(ownBox))
}).findFirst().ifPresentOrElse(box -> { .findFirst()
.ifPresentOrElse(box -> {
ticksOutsideVehicle = 0;
if (supportPositionOffset == null) { if (supportPositionOffset == null) {
updatePositionOffset(); updatePositionOffset();
} else { } else {
@ -265,8 +261,14 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
entity.verticalCollision = true; entity.verticalCollision = true;
entity.groundCollision = true; entity.groundCollision = true;
}, () -> { }, () -> {
supportingEntity = null; // Rubberband passengers to try and prevent players falling out when the velocity changes suddenly
supportPositionOffset = null; 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<T extends LivingEntity> implements Equine<T>, Caste
} }
updateDragonBreath(); updateDragonBreath();
updatePositionOffset();
if (ticksOutsideVehicle == 0) {
updatePositionOffset();
}
} }
public void updateAttributeModifier(UUID id, EntityAttribute attribute, float desiredValue, Float2ObjectFunction<EntityAttributeModifier> modifierSupplier, boolean permanent) { public void updateAttributeModifier(UUID id, EntityAttribute attribute, float desiredValue, Float2ObjectFunction<EntityAttributeModifier> modifierSupplier, boolean permanent) {

View file

@ -11,6 +11,7 @@ import com.minelittlepony.unicopia.util.Dispensable;
import net.minecraft.block.DispenserBlock; import net.minecraft.block.DispenserBlock;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.vehicle.BoatEntity;
import net.minecraft.item.BoatItem; import net.minecraft.item.BoatItem;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
@ -31,8 +32,11 @@ public class BasketItem extends Item implements Dispensable {
private static final Predicate<Entity> RIDERS = EntityPredicates.EXCEPT_SPECTATOR.and(Entity::canHit); private static final Predicate<Entity> RIDERS = EntityPredicates.EXCEPT_SPECTATOR.and(Entity::canHit);
private static final double REACH = 5; 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); super(settings);
this.type = type;
DispenserBlock.registerBehavior(this, createDispenserBehaviour()); DispenserBlock.registerBehavior(this, createDispenserBehaviour());
} }
@ -71,6 +75,7 @@ public class BasketItem extends Item implements Dispensable {
entity.updatePositionAndAngles(x, y, z, 0, 0); entity.updatePositionAndAngles(x, y, z, 0, 0);
entity.setHeadYaw(yaw); entity.setHeadYaw(yaw);
entity.setBodyYaw(yaw); entity.setBodyYaw(yaw);
entity.setBasketType(type);
if (!world.isSpaceEmpty(entity, entity.getBoundingBox())) { if (!world.isSpaceEmpty(entity, entity.getBoundingBox())) {
return TypedActionResult.fail(stack); return TypedActionResult.fail(stack);
} }

View file

@ -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);
}
}

View file

@ -11,6 +11,7 @@ import com.minelittlepony.unicopia.item.group.ItemGroupRegistry;
import com.minelittlepony.unicopia.item.group.UItemGroups; import com.minelittlepony.unicopia.item.group.UItemGroups;
import com.minelittlepony.unicopia.item.toxin.UFoodComponents; import com.minelittlepony.unicopia.item.toxin.UFoodComponents;
import net.minecraft.entity.vehicle.BoatEntity;
import net.minecraft.item.*; import net.minecraft.item.*;
import net.minecraft.item.Item.Settings; import net.minecraft.item.Item.Settings;
import net.fabricmc.fabric.api.item.v1.FabricItemSettings; 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 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 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 OAK_BASKET = register("oak_basket", new BasketItem(BoatEntity.Type.OAK, new Item.Settings().maxCount(1)), ItemGroups.FUNCTIONAL);
Item LARGE_BALLOON = register("large_balloon", new Item(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() AmuletItem PEGASUS_AMULET = register("pegasus_amulet", new PegasusAmuletItem(new FabricItemSettings()
.maxCount(1) .maxCount(1)

View file

@ -23,6 +23,9 @@
"item.unicopia.friendship_bracelet.issuer": "Signed by %s", "item.unicopia.friendship_bracelet.issuer": "Signed by %s",
"item.unicopia.friendship_bracelet.glowing": "Glowing", "item.unicopia.friendship_bracelet.glowing": "Glowing",
"item.unicopia.oak_basket": "Oak Basket",
"item.unicopia.giant_balloon": "Giant Balloon",
"item.unicopia.spellbook": "Spellbook", "item.unicopia.spellbook": "Spellbook",
"emi.category.unicopia.spellbook": "Spellbook", "emi.category.unicopia.spellbook": "Spellbook",

View file

@ -0,0 +1,6 @@
{
"parent": "item/generated",
"textures": {
"layer0": "unicopia:item/giant_balloon"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "item/generated",
"textures": {
"layer0": "unicopia:item/oak_basket"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB