diff --git a/src/main/java/org/teacon/powertool/entity/MartingEntity.java b/src/main/java/org/teacon/powertool/entity/MartingEntity.java index ce5c771..1eb61a1 100644 --- a/src/main/java/org/teacon/powertool/entity/MartingEntity.java +++ b/src/main/java/org/teacon/powertool/entity/MartingEntity.java @@ -1,29 +1,55 @@ package org.teacon.powertool.entity; import net.minecraft.client.model.geom.ModelLayerLocation; +import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.MoverType; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.*; +import net.minecraft.world.entity.ai.attributes.AttributeMap; +import net.minecraft.world.entity.ai.attributes.AttributeSupplier; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.vehicle.VehicleEntity; import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.GameRules; import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.PowderSnowBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.entity.EntityTypeTest; +import net.minecraft.world.level.gameevent.GameEvent; +import net.minecraft.world.phys.Vec2; +import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.teacon.powertool.PowerTool; import org.teacon.powertool.client.renders.entity.model.MartingEntityModel; import org.teacon.powertool.item.PowerToolItems; +import org.w3c.dom.Attr; +import java.util.List; +import java.util.Objects; import java.util.function.Supplier; /** * MalayP asked me to write a Karting Car. + * * @author qyl27 */ -public class MartingEntity extends VehicleEntity { +public class MartingEntity extends LivingEntity { + + // Rotate degrees of the steering wheel, negative for left, positive for right. + // Todo: each wheel speed depends on the steering wheel. + public static final EntityDataAccessor DATA_ID_STEERING_WHEEL_ROTATE_DEGREE = SynchedEntityData.defineId(MartingEntity.class, EntityDataSerializers.FLOAT); + + public static final EntityDataAccessor DATA_ID_DAMAGE = SynchedEntityData.defineId(MartingEntity.class, EntityDataSerializers.FLOAT); // Todo: wheel speed should depends on velocity. public static final double WHEEL_ROTATE_DEGREE_PER_TICK = 18; // 360 / 20 @@ -33,27 +59,21 @@ public class MartingEntity extends VehicleEntity { // private Variant variant = Variant.RED; - private int remainingLifeTimeTicks = MAX_REMAINING_LIFE_TIME_TICKS; + private AttributeMap attributeMap; // // - // Rotate degrees of the steering wheel, negative for left, positive for right. - // Todo: each wheel speed depends on the steering wheel. - private static final EntityDataAccessor DATA_ID_STEERING_WHEEL_ROTATE_DEGREE = SynchedEntityData.defineId(MartingEntity.class, EntityDataSerializers.FLOAT); - private double wheelRotateDegree = 0; // Wheels rotate degrees, client only // - public MartingEntity(EntityType entityType, Level level) { + public MartingEntity(EntityType entityType, Level level) { super(entityType, level); } - // - public void setVariant(Variant variant) { this.variant = variant; } @@ -62,14 +82,32 @@ public Variant getVariant() { return variant; } + // + + @Override + public @NotNull Iterable getArmorSlots() { + return List.of(); + } + @Override - protected @NotNull Item getDropItem() { - return variant.getItemSupplier().get(); + public @NotNull ItemStack getItemBySlot(@NotNull EquipmentSlot equipmentSlot) { + return ItemStack.EMPTY; + } + + @Override + public void setItemSlot(@NotNull EquipmentSlot equipmentSlot, @NotNull ItemStack itemStack) { + } + + @Override + public @NotNull HumanoidArm getMainArm() { + return HumanoidArm.RIGHT; } @Override public void tick() { - if (!level().isClientSide) { + super.tick(); + + if (!level().isClientSide()) { if (remainingLifeTimeTicks < 0) { discard(); } @@ -79,52 +117,113 @@ public void tick() { } else { remainingLifeTimeTicks -= 1; } + } else { + updateWheelsAnimation(); + } + } - applyGravity(); - updateInWaterStateAndDoFluidPushing(); + @Override + public boolean hurt(@NotNull DamageSource source, float amount) { + if (!this.level().isClientSide && !this.isRemoved()) { + if (this.isInvulnerableTo(source)) { + return false; + } else { + this.hurtTime = 10; + this.markHurt(); + this.setDamage(this.getDamage() + amount * 10.0F); + this.gameEvent(GameEvent.ENTITY_DAMAGE, source.getEntity()); + boolean flag = source.getEntity() instanceof Player && ((Player) source.getEntity()).getAbilities().instabuild; + if ((flag || !(this.getDamage() > 40.0F)) && !this.shouldSourceDestroy(source)) { + if (flag) { + this.discard(); + } + } else { + this.destroy(source); + } - move(MoverType.SELF, getDeltaMovement()); - } else { - if (!getPassengers().isEmpty()) { - wheelRotateDegree += WHEEL_ROTATE_DEGREE_PER_TICK; - wheelRotateDegree %= 360; + return true; } + } else { + return true; } + } - super.tick(); + boolean shouldSourceDestroy(DamageSource source) { + return false; + } + + public void destroy(Item dropItem) { + this.kill(); + if (this.level().getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS)) { + ItemStack itemstack = new ItemStack(dropItem); + itemstack.set(DataComponents.CUSTOM_NAME, this.getCustomName()); + this.spawnAtLocation(itemstack); + } + } + + protected void destroy(DamageSource source) { + this.destroy(this.getDropItem()); } // - // + // @Override - protected double getDefaultGravity() { - return 0.04; + public boolean showVehicleHealth() { + return false; } @Override - public boolean canBeCollidedWith() { - return true; + public @NotNull InteractionResult interact(@NotNull Player player, @NotNull InteractionHand hand) { + var result = super.interact(player, hand); + if (result != InteractionResult.PASS) { + return result; + } + + if (player.isSecondaryUseActive()) { + return InteractionResult.PASS; + } + + if (!level().isClientSide()) { + return player.startRiding(this) ? InteractionResult.CONSUME : InteractionResult.PASS; + } else { + return InteractionResult.SUCCESS; + } } - @Override - public boolean isPushable() { - return true; + protected @NotNull Item getDropItem() { + return variant.getItemSupplier().get(); } @Override - public boolean isPickable() { - return true; + public void onPassengerTurned(@NotNull Entity passenger) { + super.onPassengerTurned(passenger); + + setYRot(passenger.getYRot()); + } + + protected void updateWheelsAnimation() { + // Todo: update wheels speeds. + if (!getPassengers().isEmpty()) { + wheelRotateDegree += WHEEL_ROTATE_DEGREE_PER_TICK; + wheelRotateDegree %= 360; + } } @Override - public boolean canCollideWith(@NotNull Entity entity) { - return canVehicleCollide(this, entity); + public @Nullable LivingEntity getControllingPassenger() { + if (getFirstPassenger() instanceof Player player) { + return player; + } + return super.getControllingPassenger(); } - public static boolean canVehicleCollide(@NotNull Entity vehicle, @NotNull Entity entity) { - return (entity.canBeCollidedWith() || entity.isPushable()) && !vehicle.isPassengerOfSameVehicle(entity); + @Override + protected @NotNull Vec3 getRiddenInput(@NotNull Player player, @NotNull Vec3 travelVector) { + float deltaDirection = player.xxa * 0.5F; + float deltaForward = player.zza * 1.5F; + return new Vec3(deltaDirection, 0.0F, deltaForward); } // @@ -132,20 +231,78 @@ public static boolean canVehicleCollide(@NotNull Entity vehicle, @NotNull Entity // @Override - protected void readAdditionalSaveData(@NotNull CompoundTag compound) { - var variant = compound.getString("variant"); - this.variant = Variant.from(variant); + public void readAdditionalSaveData(@NotNull CompoundTag compound) { + if (compound.contains("variant")) { + var variant = compound.getString("variant"); + setVariant(Variant.from(variant)); + } + + if (compound.contains("lifetimeRemain")) { + remainingLifeTimeTicks = compound.getInt("lifetimeRemain"); + } } @Override - protected void addAdditionalSaveData(@NotNull CompoundTag compound) { + public void addAdditionalSaveData(@NotNull CompoundTag compound) { compound.putString("variant", variant.getName()); + compound.putInt("lifetimeRemain", remainingLifeTimeTicks); } @Override protected void defineSynchedData(SynchedEntityData.@NotNull Builder builder) { super.defineSynchedData(builder); builder.define(DATA_ID_STEERING_WHEEL_ROTATE_DEGREE, 0F); + builder.define(DATA_ID_DAMAGE, 0F); + } + + public float getDamage() { + return entityData.get(DATA_ID_DAMAGE); + } + + public void setDamage(float value) { + entityData.set(DATA_ID_DAMAGE, value); + } + + + @Override + public @NotNull AttributeMap getAttributes() { + if (attributeMap == null) { + attributeMap = new AttributeMap(createAttributes()); + } + return attributeMap; + } + + public static AttributeSupplier createAttributes() { + return AttributeSupplier.builder() + .add(Attributes.MAX_HEALTH, 1) + .add(Attributes.STEP_HEIGHT, 1) + .add(Attributes.MOVEMENT_SPEED, 0.25) + .add(Attributes.SCALE) + .add(Attributes.GRAVITY) + .add(Attributes.MOVEMENT_EFFICIENCY) + .add(Attributes.SAFE_FALL_DISTANCE, 30) + .add(Attributes.FALL_DAMAGE_MULTIPLIER) + .build(); + } + + @Override + public float getSpeed() { + return (float) getAttributeValue(Attributes.MOVEMENT_SPEED); + } + + @Override + public void setSpeed(float speed) { + Objects.requireNonNull(getAttribute(Attributes.MOVEMENT_SPEED)).setBaseValue(speed); + } + + @Override + public float getHealth() { + return getDamage(); + } + + @Override + public void setHealth(float health) { + setDamage(health); } // diff --git a/src/main/resources/assets/powertool/lang/en_us.json b/src/main/resources/assets/powertool/lang/en_us.json index 9697802..842a077 100644 --- a/src/main/resources/assets/powertool/lang/en_us.json +++ b/src/main/resources/assets/powertool/lang/en_us.json @@ -140,6 +140,7 @@ "powertool.gui.display_mode_disabled": "Disabled display mode on %s", "powertool.gui.display_mode_error": "Could not enable display mode on %s because it has no ability to open any screen. Or press shift key and click again to force enable display mode.", + "entity.powertool.marting_car": "Marting Car", "item.powertool.marting_car_red": "Marting Car (Red)", "item.powertool.marting_car_green": "Marting Car (Green)", "item.powertool.marting_car_blue": "Marting Car (Blue)", diff --git a/src/main/resources/assets/powertool/lang/zh_cn.json b/src/main/resources/assets/powertool/lang/zh_cn.json index e666412..f1d90f1 100644 --- a/src/main/resources/assets/powertool/lang/zh_cn.json +++ b/src/main/resources/assets/powertool/lang/zh_cn.json @@ -141,6 +141,7 @@ "powertool.gui.display_mode_disabled": "已在%s上禁用展示模式", "powertool.gui.display_mode_error": "无法在%s上启用展示模式,因为它无法打开任何可交互界面.按下shift键强制启用展示模式.", + "entity.powertool.marting_car": "马丁车", "item.powertool.marting_car_red": "马丁车(红色)", "item.powertool.marting_car_green": "马丁车(绿色)", "item.powertool.marting_car_blue": "马丁车(蓝色)",