diff --git a/src/client/java/net/rotgruengelb/forestal/ForestalClient.java b/src/client/java/net/rotgruengelb/forestal/ForestalClient.java index bc70e1c..06941d9 100644 --- a/src/client/java/net/rotgruengelb/forestal/ForestalClient.java +++ b/src/client/java/net/rotgruengelb/forestal/ForestalClient.java @@ -3,6 +3,7 @@ import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.rendering.v1.EntityRendererRegistry; import net.rotgruengelb.forestal.client.particle.ForestalParticleFactories; +import net.rotgruengelb.forestal.client.render.entity.DeerEntityRenderer; import net.rotgruengelb.forestal.client.render.entity.GrizzlyBearEntityRenderer; import net.rotgruengelb.forestal.entity.ForestalEntities; @@ -11,6 +12,8 @@ public class ForestalClient implements ClientModInitializer { public void onInitializeClient() { EntityRendererRegistry.register(ForestalEntities.GRIZZLY_BEAR, GrizzlyBearEntityRenderer::new); +// EntityRendererRegistry.register(ForestalEntities.DEER, DeerEntityRenderer::new); + ForestalParticleFactories.registerModParticleFactories(); } } \ No newline at end of file diff --git a/src/client/java/net/rotgruengelb/forestal/client/render/entity/DeerEntityRenderer.java b/src/client/java/net/rotgruengelb/forestal/client/render/entity/DeerEntityRenderer.java new file mode 100644 index 0000000..ab47b87 --- /dev/null +++ b/src/client/java/net/rotgruengelb/forestal/client/render/entity/DeerEntityRenderer.java @@ -0,0 +1,33 @@ +package net.rotgruengelb.forestal.client.render.entity; + +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.entity.EntityRendererFactory; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.Identifier; +import net.rotgruengelb.forestal.Forestal; +import net.rotgruengelb.forestal.client.render.entity.model.DeerEntityModel; +import net.rotgruengelb.forestal.entity.DeerEntity; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +public class DeerEntityRenderer extends GeoEntityRenderer { + + public DeerEntityRenderer(EntityRendererFactory.Context renderManager) { + super(renderManager, new DeerEntityModel()); + } + + @Override + public Identifier getTextureLocation(DeerEntity grizzlyBear) { + return new Identifier(Forestal.MOD_ID, "textures/entity/deer.png"); + } + + @Override + public void render(DeerEntity deerEntity, float entityYaw, float partialTick, MatrixStack poseStack, VertexConsumerProvider bufferSource, int packedLight) { + if (deerEntity.isBaby()) { + poseStack.scale(0.6F, 0.6F, 0.6F); + } + if (deerEntity.isSleeping()) { + poseStack.translate(0, -0.5, 0); + } + super.render(deerEntity, entityYaw, partialTick, poseStack, bufferSource, packedLight); + } +} diff --git a/src/client/java/net/rotgruengelb/forestal/client/render/entity/GrizzlyBearEntityRenderer.java b/src/client/java/net/rotgruengelb/forestal/client/render/entity/GrizzlyBearEntityRenderer.java index 3f734e5..4d1dccb 100644 --- a/src/client/java/net/rotgruengelb/forestal/client/render/entity/GrizzlyBearEntityRenderer.java +++ b/src/client/java/net/rotgruengelb/forestal/client/render/entity/GrizzlyBearEntityRenderer.java @@ -24,13 +24,13 @@ public Identifier getTextureLocation(GrizzlyBearEntity grizzlyBear) { } @Override - public void render(GrizzlyBearEntity grizzlyBear, float entityYaw, float partialTick, MatrixStack poseStack, VertexConsumerProvider bufferSource, int packedLight) { - if (grizzlyBear.isBaby()) { + public void render(GrizzlyBearEntity grizzlyBearEntity, float entityYaw, float partialTick, MatrixStack poseStack, VertexConsumerProvider bufferSource, int packedLight) { + if (grizzlyBearEntity.isBaby()) { poseStack.scale(0.6F, 0.6F, 0.6F); } - if (grizzlyBear.isSleeping()) { + if (grizzlyBearEntity.isSleeping()) { poseStack.translate(0, -0.5, 0); } - super.render(grizzlyBear, entityYaw, partialTick, poseStack, bufferSource, packedLight); + super.render(grizzlyBearEntity, entityYaw, partialTick, poseStack, bufferSource, packedLight); } } diff --git a/src/client/java/net/rotgruengelb/forestal/client/render/entity/model/DeerEntityModel.java b/src/client/java/net/rotgruengelb/forestal/client/render/entity/model/DeerEntityModel.java new file mode 100644 index 0000000..029de9f --- /dev/null +++ b/src/client/java/net/rotgruengelb/forestal/client/render/entity/model/DeerEntityModel.java @@ -0,0 +1,39 @@ +package net.rotgruengelb.forestal.client.render.entity.model; + +import net.minecraft.util.Identifier; +import net.minecraft.util.math.MathHelper; +import net.rotgruengelb.forestal.Forestal; +import net.rotgruengelb.forestal.entity.DeerEntity; +import software.bernie.geckolib.constant.DataTickets; +import software.bernie.geckolib.core.animatable.model.CoreGeoBone; +import software.bernie.geckolib.core.animation.AnimationState; +import software.bernie.geckolib.model.GeoModel; +import software.bernie.geckolib.model.data.EntityModelData; + +public class DeerEntityModel extends GeoModel { + @Override + public Identifier getModelResource(DeerEntity animatable) { + return new Identifier(Forestal.MOD_ID, "geo/deer.geo.json"); + } + + @Override + public Identifier getTextureResource(DeerEntity grizzlyBear) { + return new Identifier(Forestal.MOD_ID, "textures/entity/deer.png"); + } + + @Override + public Identifier getAnimationResource(DeerEntity animatable) { + return new Identifier(Forestal.MOD_ID, "animations/deer.animation.json"); + } + + @Override + public void setCustomAnimations(DeerEntity animatable, long instanceId, AnimationState animationState) { + CoreGeoBone head = getAnimationProcessor().getBone("head"); + + if (head != null) { + EntityModelData entityData = animationState.getData(DataTickets.ENTITY_MODEL_DATA); + head.setRotX(entityData.headPitch() * MathHelper.RADIANS_PER_DEGREE); + head.setRotY(entityData.netHeadYaw() * MathHelper.RADIANS_PER_DEGREE); + } + } +} diff --git a/src/main/java/net/rotgruengelb/forestal/block/ForestalBlocks.java b/src/main/java/net/rotgruengelb/forestal/block/ForestalBlocks.java index 1080eb5..d44c10c 100644 --- a/src/main/java/net/rotgruengelb/forestal/block/ForestalBlocks.java +++ b/src/main/java/net/rotgruengelb/forestal/block/ForestalBlocks.java @@ -3,6 +3,7 @@ import net.fabricmc.fabric.api.item.v1.FabricItemSettings; import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; import net.minecraft.block.Block; +import net.minecraft.block.Blocks; import net.minecraft.item.BlockItem; import net.minecraft.registry.Registries; import net.minecraft.registry.Registry; @@ -14,6 +15,8 @@ public class ForestalBlocks { public static final Block GRIZZLY_PLUSHIE = registerBlock("grizzly_plushie", new PlushieBlock(FabricBlockSettings.create() .nonOpaque().breakInstantly().noBlockBreakParticles().sounds(BlockSoundGroup.WOOL))); + public static final Block PUFFED_DANDELION = registerBlock("puffed_dandelion", + new PuffedDandelionBlock(FabricBlockSettings.copyOf(Blocks.DANDELION))); private static Block registerBlockNoItem(String name, Block block) { return Registry.register(Registries.BLOCK, new Identifier(Forestal.MOD_ID, name), block); diff --git a/src/main/java/net/rotgruengelb/forestal/block/PuffedDandelionBlock.java b/src/main/java/net/rotgruengelb/forestal/block/PuffedDandelionBlock.java new file mode 100644 index 0000000..1d4a49d --- /dev/null +++ b/src/main/java/net/rotgruengelb/forestal/block/PuffedDandelionBlock.java @@ -0,0 +1,34 @@ +package net.rotgruengelb.forestal.block; + +import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; +import net.minecraft.block.BlockState; +import net.minecraft.block.CherryLeavesBlock; +import net.minecraft.block.FlowerBlock; +import net.minecraft.client.util.ParticleUtil; +import net.minecraft.entity.effect.StatusEffects; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.random.Random; +import net.minecraft.world.World; + +public class PuffedDandelionBlock extends FlowerBlock { + + public PuffedDandelionBlock(FabricBlockSettings settings) { + super(StatusEffects.SATURATION, 7, settings); + } + + @Override + public void randomDisplayTick(BlockState state, World world, BlockPos pos, Random random) { + super.randomDisplayTick(state, world, pos, random); + if (random.nextInt(10) != 0) { + return; + } + BlockPos blockPos = pos.down(); + BlockState blockState = world.getBlockState(blockPos); + if (CherryLeavesBlock.isFaceFullSquare(blockState.getCollisionShape(world, blockPos), Direction.UP)) { + return; + } + ParticleUtil.spawnParticle(world, pos, random, ParticleTypes.CHERRY_LEAVES); + } +} diff --git a/src/main/java/net/rotgruengelb/forestal/entity/BearEntity.java b/src/main/java/net/rotgruengelb/forestal/entity/BearEntity.java new file mode 100644 index 0000000..e3dea8b --- /dev/null +++ b/src/main/java/net/rotgruengelb/forestal/entity/BearEntity.java @@ -0,0 +1,256 @@ +package net.rotgruengelb.forestal.entity; + +import net.minecraft.block.BlockState; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.SpawnReason; +import net.minecraft.entity.ai.goal.*; +import net.minecraft.entity.attribute.DefaultAttributeContainer; +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; +import net.minecraft.entity.mob.MobEntity; +import net.minecraft.entity.passive.AnimalEntity; +import net.minecraft.entity.passive.PassiveEntity; +import net.minecraft.entity.passive.VillagerEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.recipe.Ingredient; +import net.minecraft.registry.tag.BlockTags; +import net.minecraft.registry.tag.TagKey; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.sound.SoundEvent; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.random.Random; +import net.minecraft.world.ServerWorldAccess; +import net.minecraft.world.World; +import net.rotgruengelb.forestal.sound.ForestalSoundEvents; +import org.jetbrains.annotations.Nullable; + +import java.util.EnumSet; + +public class BearEntity extends AnimalEntity { + + public static final SoundEvent SOUND_DEATH = ForestalSoundEvents.ENTITY_GRIZZLY_BEAR_DEATH; + private static final TrackedData BEAR_FLAGS = DataTracker.registerData(BearEntity.class, TrackedDataHandlerRegistry.BYTE); + private static final int SLEEPING_FLAG = 1; + public static SoundEvent SOUND_AMBIENT_BABY; + public static SoundEvent SOUND_AMBIENT; + public static SoundEvent SOUND_STEP; + public static SoundEvent SOUND_HURT; + public static TagKey FOOD_TAG; + + public BearEntity(EntityType entityType, World world) { + super(entityType, world); + setStepHeight(1.0f); + } + + public static DefaultAttributeContainer.Builder createBearAttributes() { + return MobEntity.createMobAttributes().add(EntityAttributes.GENERIC_MAX_HEALTH, 30.0) + .add(EntityAttributes.GENERIC_FOLLOW_RANGE, 20.0) + .add(EntityAttributes.GENERIC_MOVEMENT_SPEED, 0.25) + .add(EntityAttributes.GENERIC_ATTACK_DAMAGE, 6.0); + } + + public static boolean isValidBearSpawn(EntityType entityType, ServerWorldAccess world, SpawnReason spawnReason, BlockPos pos, Random random) { + boolean bl = SpawnReason.isTrialSpawner(spawnReason) || AnimalEntity.isLightLevelValidForNaturalSpawn(world, pos); + return (world.getBlockState(pos.down()) + .isIn(BlockTags.ANIMALS_SPAWNABLE_ON) || world.getBlockState(pos.down()) + .isIn(BlockTags.ICE)) && bl; + } + + public boolean isSleeping() { + return this.getBearFlag(SLEEPING_FLAG); + } + + void setSleeping(boolean sleeping) { + this.setBearFlag(SLEEPING_FLAG, sleeping); + } + + private boolean getBearFlag(int bitmask) { + return (this.dataTracker.get(BEAR_FLAGS) & bitmask) != 0; + } + + private void setBearFlag(int mask, boolean value) { + if (value) { + this.dataTracker.set(BEAR_FLAGS, (byte) (this.dataTracker.get(BEAR_FLAGS) | mask)); + } else { + this.dataTracker.set(BEAR_FLAGS, (byte) (this.dataTracker.get(BEAR_FLAGS) & ~mask)); + } + + } + + @Nullable + @Override + public PassiveEntity createChild(ServerWorld world, PassiveEntity entity) { + return (PassiveEntity) entity.getType().create(world); + } + + protected void initDataTracker() { + super.initDataTracker(); + this.dataTracker.startTracking(BEAR_FLAGS, (byte) 0); + } + + @Override + protected void playStepSound(BlockPos pos, BlockState state) { + this.playSound(SOUND_STEP, 0.15f, 1.0f); + } + + public boolean isBreedingItem(ItemStack stack) { + return stack.isIn(FOOD_TAG); + } + + @Override + protected SoundEvent getDeathSound() { return SOUND_DEATH; } + + @Override + public void initGoals() { + super.initGoals(); + this.goalSelector.add(0, new SwimGoal(this)); + this.goalSelector.add(1, new EscapeDangerGoal(this, 1.1)); + this.goalSelector.add(2, new AnimalMateGoal(this, 1.05)); + this.goalSelector.add(3, new TemptGoal(this, 0.9, Ingredient.fromTag(FOOD_TAG), false)); + this.goalSelector.add(4, new FindSleepingPlaceGoal(0.85)); + this.goalSelector.add(5, new SleepGoal()); + this.goalSelector.add(6, new FollowParentGoal(this, 0.95)); + this.goalSelector.add(7, new WanderAroundFarGoal(this, 0.9)); + this.goalSelector.add(8, new WanderAroundGoal(this, 0.85)); + this.goalSelector.add(9, new LookAtEntityGoal(this, PlayerEntity.class, 6.0f, 0.017f)); + this.goalSelector.add(10, new LookAtEntityGoal(this, VillagerEntity.class, 4.0f, 0.007f)); + this.goalSelector.add(11, new LookAroundGoal(this)); + } + + @Override + public void tick() { + super.tick(); + if (this.canMoveVoluntarily() && this.isTouchingWater() || this.getWorld().isDay()) { + this.setSleeping(false); + } + } + + @Override + public void tickMovement() { + if (this.isSleeping() || this.isImmobile()) { + this.jumping = false; + this.sidewaysSpeed = 0.0F; + this.forwardSpeed = 0.0F; + return; + } + super.tickMovement(); + } + + @Override + public SoundEvent getAmbientSound() { + if (this.isBaby()) { + return SOUND_AMBIENT_BABY; + } + return SOUND_AMBIENT; + } + + @Override + public void playAmbientSound() { + if (this.isSleeping()) { return; } + super.playAmbientSound(); + } + + @Override + protected SoundEvent getHurtSound(DamageSource source) { + return SOUND_HURT; + } + + public void writeCustomDataToNbt(NbtCompound nbt) { + super.writeCustomDataToNbt(nbt); + nbt.putBoolean("Sleeping", this.isSleeping()); + } + + public void readCustomDataFromNbt(NbtCompound nbt) { + super.readCustomDataFromNbt(nbt); + this.setSleeping(nbt.getBoolean("Sleeping")); + } + + private class SleepGoal extends Goal { + private static final int MAX_CALM_DOWN_TIME = toGoalTicks(280); + private int timer; + + public SleepGoal() { + super(); + this.timer = BearEntity.this.random.nextInt(MAX_CALM_DOWN_TIME); + this.setControls(EnumSet.of(Control.MOVE, Control.LOOK, Control.JUMP)); + } + + protected boolean isAtFavoredLocation() { + BlockPos blockPos = BlockPos.ofFloored(BearEntity.this.getX(), BearEntity.this.getBoundingBox().maxY, BearEntity.this.getZ()); + return !BearEntity.this.getWorld() + .isSkyVisible(blockPos) && BearEntity.this.getPathfindingFavor(blockPos) >= 0.0f; + } + + public boolean canStart() { + if (BearEntity.this.sidewaysSpeed == 0.0F && BearEntity.this.upwardSpeed == 0.0F && BearEntity.this.forwardSpeed == 0.0F && BearEntity.this.getWorld() + .isNight()) { + return this.canNotSleep() || !BearEntity.this.isSleeping(); + } else { + return false; + } + } + + public boolean shouldContinue() { + return this.canNotSleep(); + } + + private boolean canNotSleep() { + if (this.timer > 0) { + --this.timer; + return false; + } else { + return this.isAtFavoredLocation() && !BearEntity.this.inPowderSnow; // && + } + } + + public void stop() { + this.timer = BearEntity.this.random.nextInt(MAX_CALM_DOWN_TIME); + BearEntity.this.setSleeping(false); + } + + public void start() { + BearEntity.this.setJumping(false); + BearEntity.this.setSleeping(true); + BearEntity.this.getNavigation().stop(); + BearEntity.this.getMoveControl() + .moveTo(BearEntity.this.getX(), BearEntity.this.getY(), BearEntity.this.getZ(), 0.0); + } + } + + class FindSleepingPlaceGoal extends EscapeSunlightGoal { + private int timer = toGoalTicks(100); + + public FindSleepingPlaceGoal(double speed) { + super(BearEntity.this, speed); + } + + public boolean canStart() { + if (!BearEntity.this.isSleeping() && BearEntity.this.getWorld().isNight()) { + if (BearEntity.this.getWorld().isSkyVisible(this.mob.getBlockPos())) { + return this.targetShadedPos(); + } else if (this.timer > 0) { + --this.timer; + return false; + } else { + this.timer = 100; + BlockPos blockPos = this.mob.getBlockPos(); + return BearEntity.this.getWorld() + .isSkyVisible(blockPos) && !((ServerWorld) BearEntity.this.getWorld()).isNearOccupiedPointOfInterest(blockPos) && this.targetShadedPos(); + } + } else { + return false; + } + } + + public void start() { + BearEntity.this.setSleeping(false); + super.start(); + } + } +} diff --git a/src/main/java/net/rotgruengelb/forestal/entity/DeerEntity.java b/src/main/java/net/rotgruengelb/forestal/entity/DeerEntity.java new file mode 100644 index 0000000..d404795 --- /dev/null +++ b/src/main/java/net/rotgruengelb/forestal/entity/DeerEntity.java @@ -0,0 +1,324 @@ +package net.rotgruengelb.forestal.entity; + +import com.google.common.collect.Lists; +import net.minecraft.block.BlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.SpawnReason; +import net.minecraft.entity.ai.TargetPredicate; +import net.minecraft.entity.ai.goal.*; +import net.minecraft.entity.attribute.DefaultAttributeContainer; +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; +import net.minecraft.entity.mob.HostileEntity; +import net.minecraft.entity.mob.MobEntity; +import net.minecraft.entity.passive.*; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtElement; +import net.minecraft.nbt.NbtHelper; +import net.minecraft.nbt.NbtList; +import net.minecraft.predicate.entity.EntityPredicates; +import net.minecraft.registry.tag.BlockTags; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.sound.SoundEvent; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.random.Random; +import net.minecraft.world.ServerWorldAccess; +import net.minecraft.world.World; +import net.rotgruengelb.forestal.sound.ForestalSoundEvents; +import net.rotgruengelb.forestal.util.ForestalTags; +import org.jetbrains.annotations.Nullable; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.core.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.core.animatable.instance.SingletonAnimatableInstanceCache; +import software.bernie.geckolib.core.animation.*; +import software.bernie.geckolib.core.object.PlayState; + +import java.util.*; +import java.util.function.Predicate; + +public class DeerEntity extends AnimalEntity implements GeoEntity { + + private static final TrackedData DEER_FLAGS = DataTracker.registerData(DeerEntity.class, TrackedDataHandlerRegistry.BYTE); + private static final int SITTING_FLAG = 1; + private static final Predicate NOTICEABLE_PLAYER_FILTER = entity -> !entity.isSneaky() && EntityPredicates.EXCEPT_CREATIVE_OR_SPECTATOR.test(entity); + private static final TrackedData> TRUSTED = DataTracker.registerData(DeerEntity.class, TrackedDataHandlerRegistry.OPTIONAL_UUID); + private final AnimatableInstanceCache cache = new SingletonAnimatableInstanceCache(this); + + public DeerEntity(EntityType entityType, World world) { + super(entityType, world); + setStepHeight(1.0f); + } + + public static DefaultAttributeContainer.Builder createDeerAttributes() { + return MobEntity.createMobAttributes().add(EntityAttributes.GENERIC_MAX_HEALTH, 10.0) + .add(EntityAttributes.GENERIC_FOLLOW_RANGE, 20.0) + .add(EntityAttributes.GENERIC_MOVEMENT_SPEED, 0.25) + .add(EntityAttributes.GENERIC_ATTACK_DAMAGE, 6.0); + } + + public static boolean isValidDeerSpawn(EntityType deerEntityEntityType, ServerWorldAccess world, SpawnReason spawnReason, BlockPos pos, Random random) { + boolean bl = SpawnReason.isTrialSpawner(spawnReason) || AnimalEntity.isLightLevelValidForNaturalSpawn(world, pos); + return world.getBlockState(pos.down()).isIn(BlockTags.ANIMALS_SPAWNABLE_ON) && bl; + } + + public boolean isSitting() { + return this.getDeerFlag(SITTING_FLAG); + } + + void setSitting(boolean sitting) { + this.setDeerFlag(SITTING_FLAG, sitting); + } + + private boolean getDeerFlag(int bitmask) { + return (this.dataTracker.get(DEER_FLAGS) & bitmask) != 0; + } + + private void setDeerFlag(int mask, boolean value) { + if (value) { + this.dataTracker.set(DEER_FLAGS, (byte) (this.dataTracker.get(DEER_FLAGS) | mask)); + } else { + this.dataTracker.set(DEER_FLAGS, (byte) (this.dataTracker.get(DEER_FLAGS) & ~mask)); + } + + } + + protected void initDataTracker() { + super.initDataTracker(); + this.dataTracker.startTracking(TRUSTED, Optional.empty()); + this.dataTracker.startTracking(DEER_FLAGS, (byte) 0); + } + + @Nullable + @Override + public PassiveEntity createChild(ServerWorld world, PassiveEntity entity) { +// return ForestalEntities.DEER.create(world); + return null; + } + + @Override + protected void playStepSound(BlockPos pos, BlockState state) { + this.playSound(ForestalSoundEvents.ENTITY_GRIZZLY_BEAR_STEP, 0.15f, 1.0f); + } + + public boolean isBreedingItem(ItemStack stack) { + return stack.isIn(ForestalTags.Items.GRIZZLY_BEAR_FOOD); + } + + @Override + public void initGoals() { + super.initGoals(); + this.goalSelector.add(0, new SwimGoal(this)); + this.goalSelector.add(1, new AnimalMateGoal(this, 1.0)); + this.goalSelector.add(2, new FleeEntityGoal<>(this, PlayerEntity.class, 16.0f, 1.6, 1.4, entity -> NOTICEABLE_PLAYER_FILTER.test((Entity) entity) && !this.canTrust(entity.getUuid()))); + this.goalSelector.add(2, new FleeEntityGoal<>(this, WolfEntity.class, 8.0f, 1.6, 1.4, entity -> !((WolfEntity) entity).isTamed())); + this.goalSelector.add(2, new FleeEntityGoal<>(this, PolarBearEntity.class, 8.0f, 1.6, 1.4)); + this.goalSelector.add(3, new FollowParentGoal(this, 1.15)); + this.goalSelector.add(4, new WanderAroundFarGoal(this, 1.0)); + this.goalSelector.add(5, new LookAtEntityGoal(this, PlayerEntity.class, 24.0f)); + this.goalSelector.add(6, new SitDownAndLookAroundGoal()); + } + + void addTrustedUuid(@Nullable UUID uuid) { + this.dataTracker.set(TRUSTED, Optional.ofNullable(uuid)); + } + + boolean canTrust(UUID uuid) { + return this.getTrustedUuids().contains(uuid); + } + + List getTrustedUuids() { + ArrayList list = Lists.newArrayList(); + list.add(this.dataTracker.get(TRUSTED).orElse(null)); + return list; + } + + @Override + public void tick() { + super.tick(); + if (this.canMoveVoluntarily() && this.isTouchingWater()) { + this.setSitting(false); + } + } + + @Override + public void tickMovement() { + if (this.isSitting() || this.isImmobile()) { + this.jumping = false; + this.sidewaysSpeed = 0.0F; + this.forwardSpeed = 0.0F; + } else { + super.tickMovement(); + } + } + + @Override + public SoundEvent getAmbientSound() { + if (this.isBaby()) { + return ForestalSoundEvents.ENTITY_GRIZZLY_BEAR_AMBIENT_BABY; + } + return ForestalSoundEvents.ENTITY_GRIZZLY_BEAR_AMBIENT; + } + + @Override + public void playAmbientSound() { + if (this.isSitting()) { return; } + super.playAmbientSound(); + } + + @Override + protected SoundEvent getHurtSound(DamageSource source) { + return ForestalSoundEvents.ENTITY_GRIZZLY_BEAR_HURT; + } + + public void writeCustomDataToNbt(NbtCompound nbt) { + super.writeCustomDataToNbt(nbt); + List trustedUuids = this.getTrustedUuids(); + NbtList trustedUuidsNbtList = new NbtList(); + for (UUID uUID : trustedUuids) { + if (uUID == null) continue; + trustedUuidsNbtList.add(NbtHelper.fromUuid(uUID)); + } + nbt.put("Trusted", trustedUuidsNbtList); + nbt.putBoolean("Sitting", this.isSitting()); + } + + @Override + public ActionResult interactMob(PlayerEntity player, Hand hand) { + return super.interactMob(player, hand); + } + + public void readCustomDataFromNbt(NbtCompound nbt) { + super.readCustomDataFromNbt(nbt); + NbtList trustedUuidsNbtList = nbt.getList("Trusted", NbtElement.INT_ARRAY_TYPE); + for (NbtElement uuidNbtElement : trustedUuidsNbtList) { + this.addTrustedUuid(NbtHelper.toUuid(uuidNbtElement)); + } + this.setSitting(nbt.getBoolean("Sitting")); + } + + @Override + protected SoundEvent getDeathSound() { return ForestalSoundEvents.ENTITY_GRIZZLY_BEAR_DEATH; } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar controllers) { + controllers.add(new AnimationController<>(this, "controller", 0, this::predicate)); + } + + private PlayState predicate(AnimationState animationState) { +// if (animationState.getAnimatable().isSitting()) { +// animationState.getController().setAnimation(RawAnimation.begin() +// .then("animation.deer.sit", Animation.LoopType.LOOP)); +// } else + if (animationState.isMoving() && !this.isSitting()) { + animationState.getController().setAnimation(RawAnimation.begin() + .then("animation.deer.walk", Animation.LoopType.LOOP)); + } else { + animationState.getController().setAnimation(RawAnimation.begin() + .then("animation.deer.idle", Animation.LoopType.LOOP)); + } + + return PlayState.CONTINUE; + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { return cache; } + + private class SitDownAndLookAroundGoal extends CalmDownGoal { + private double lookX; + private double lookZ; + private int timer; + private int counter; + + public SitDownAndLookAroundGoal() { + super(); + this.setControls(EnumSet.of(Control.MOVE, Control.LOOK)); + } + + public boolean canStart() { + return DeerEntity.this.getAttacker() == null && DeerEntity.this.getRandom() + .nextFloat() < 0.02F && DeerEntity.this.getTarget() == null && DeerEntity.this.getNavigation() + .isIdle() && !this.canCalmDown(); + } + + public boolean shouldContinue() { + return this.counter > 0; + } + + public void start() { + this.chooseNewAngle(); + this.counter = 2 + DeerEntity.this.getRandom().nextInt(3); + DeerEntity.this.setSitting(true); + DeerEntity.this.getNavigation().stop(); + } + + public void stop() { + DeerEntity.this.setSitting(false); + } + + public void tick() { + --this.timer; + if (this.timer <= 0) { + --this.counter; + this.chooseNewAngle(); + } + + DeerEntity.this.getLookControl().lookAt(DeerEntity.this.getX() + this.lookX, DeerEntity.this.getEyeY(), DeerEntity.this.getZ() + this.lookZ, (float) DeerEntity.this.getMaxHeadRotation(), (float) DeerEntity.this.getMaxLookPitchChange()); + } + + private void chooseNewAngle() { + double d = 6.283185307179586 * DeerEntity.this.getRandom().nextDouble(); + this.lookX = Math.cos(d); + this.lookZ = Math.sin(d); + this.timer = this.getTickCount(80 + DeerEntity.this.getRandom().nextInt(20)); + } + } + + public class WorriableEntityFilter implements Predicate { + @Override + public boolean test(LivingEntity livingEntity) { + if (livingEntity instanceof DeerEntity) { + return false; + } + if (livingEntity instanceof HostileEntity) { + return true; + } + if (livingEntity instanceof TameableEntity) { + return !((TameableEntity) livingEntity).isTamed(); + } + if (livingEntity instanceof PlayerEntity && (livingEntity.isSpectator() || ((PlayerEntity) livingEntity).isCreative())) { + return false; + } + if (DeerEntity.this.canTrust(livingEntity.getUuid())) { + return false; + } + return !livingEntity.isSneaky(); + } + + } + + abstract class CalmDownGoal extends Goal { + private final TargetPredicate WORRIABLE_ENTITY_PREDICATE = TargetPredicate.createAttackable() + .setBaseMaxDistance(12.0).ignoreVisibility() + .setPredicate(DeerEntity.this.new WorriableEntityFilter()); + + protected boolean isAtFavoredLocation() { + BlockPos blockPos = BlockPos.ofFloored(DeerEntity.this.getX(), DeerEntity.this.getBoundingBox().maxY, DeerEntity.this.getZ()); + return DeerEntity.this.getPathfindingFavor(blockPos) >= 0.0F; + } + + protected boolean canCalmDown() { + return !DeerEntity.this.getWorld() + .getTargets(LivingEntity.class, this.WORRIABLE_ENTITY_PREDICATE, DeerEntity.this, DeerEntity.this.getBoundingBox() + .expand(12.0, 6.0, 12.0)).isEmpty(); + } + } +} diff --git a/src/main/java/net/rotgruengelb/forestal/entity/ForestalEntities.java b/src/main/java/net/rotgruengelb/forestal/entity/ForestalEntities.java index e502957..a0d0a66 100644 --- a/src/main/java/net/rotgruengelb/forestal/entity/ForestalEntities.java +++ b/src/main/java/net/rotgruengelb/forestal/entity/ForestalEntities.java @@ -14,10 +14,14 @@ public class ForestalEntities { public static final EntityType GRIZZLY_BEAR = Registry.register(Registries.ENTITY_TYPE, new Identifier(Forestal.MOD_ID, "grizzly_bear"), FabricEntityTypeBuilder.create(SpawnGroup.CREATURE, GrizzlyBearEntity::new) .dimensions(EntityDimensions.fixed(1.5f, 1.5f)).build()); +// public static final EntityType DEER = Registry.register(Registries.ENTITY_TYPE, new Identifier(Forestal.MOD_ID, "deer"), FabricEntityTypeBuilder.create(SpawnGroup.CREATURE, DeerEntity::new) +// .dimensions(EntityDimensions.fixed(1.5f, 1.5f)).build()); public static void registerModEntities() { Forestal.LOGGER.debug("Registering ForestalEntities for " + Forestal.MOD_ID); - FabricDefaultAttributeRegistry.register(ForestalEntities.GRIZZLY_BEAR, GrizzlyBearEntity.createGrizzlyBearAttributes()); +// FabricDefaultAttributeRegistry.register(ForestalEntities.DEER, DeerEntity.createDeerAttributes()); + FabricDefaultAttributeRegistry.register(ForestalEntities.GRIZZLY_BEAR, + GrizzlyBearEntity.createBearAttributes()); } } diff --git a/src/main/java/net/rotgruengelb/forestal/entity/GrizzlyBearEntity.java b/src/main/java/net/rotgruengelb/forestal/entity/GrizzlyBearEntity.java index ed38ae3..49bc52d 100644 --- a/src/main/java/net/rotgruengelb/forestal/entity/GrizzlyBearEntity.java +++ b/src/main/java/net/rotgruengelb/forestal/entity/GrizzlyBearEntity.java @@ -1,164 +1,33 @@ package net.rotgruengelb.forestal.entity; -import net.minecraft.block.BlockState; import net.minecraft.entity.EntityType; -import net.minecraft.entity.SpawnReason; -import net.minecraft.entity.ai.goal.*; -import net.minecraft.entity.attribute.DefaultAttributeContainer; -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; -import net.minecraft.entity.mob.MobEntity; import net.minecraft.entity.passive.AnimalEntity; -import net.minecraft.entity.passive.PassiveEntity; -import net.minecraft.entity.passive.VillagerEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.recipe.Ingredient; -import net.minecraft.server.world.ServerWorld; -import net.minecraft.sound.SoundEvent; import net.minecraft.util.ActionResult; import net.minecraft.util.Hand; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.random.Random; -import net.minecraft.world.ServerWorldAccess; import net.minecraft.world.World; import net.rotgruengelb.forestal.item.ForestalItems; import net.rotgruengelb.forestal.sound.ForestalSoundEvents; import net.rotgruengelb.forestal.util.ForestalTags; -import org.jetbrains.annotations.Nullable; import software.bernie.geckolib.animatable.GeoEntity; import software.bernie.geckolib.core.animatable.instance.AnimatableInstanceCache; import software.bernie.geckolib.core.animatable.instance.SingletonAnimatableInstanceCache; import software.bernie.geckolib.core.animation.*; import software.bernie.geckolib.core.object.PlayState; -import java.util.EnumSet; +public class GrizzlyBearEntity extends BearEntity implements GeoEntity { -public class GrizzlyBearEntity extends AnimalEntity implements GeoEntity { - - private static final TrackedData GRIZZLY_BEAR_FLAGS = DataTracker.registerData(GrizzlyBearEntity.class, TrackedDataHandlerRegistry.BYTE); - private static final int SLEEPING_FLAG = 1; private final AnimatableInstanceCache cache = new SingletonAnimatableInstanceCache(this); public GrizzlyBearEntity(EntityType entityType, World world) { super(entityType, world); setStepHeight(1.0f); - } - - public static DefaultAttributeContainer.Builder createGrizzlyBearAttributes() { - return MobEntity.createMobAttributes().add(EntityAttributes.GENERIC_MAX_HEALTH, 30.0) - .add(EntityAttributes.GENERIC_FOLLOW_RANGE, 20.0) - .add(EntityAttributes.GENERIC_MOVEMENT_SPEED, 0.25) - .add(EntityAttributes.GENERIC_ATTACK_DAMAGE, 6.0); - } - - public static boolean isValidGrizzlyBearSpawn(EntityType grizzlyBearEntityEntityType, ServerWorldAccess world, SpawnReason spawnReason, BlockPos pos, Random random) { - return WoodpeckerEntity.isValidGrizzlyBearSpawn(null, world, spawnReason, pos, null); - } - - public boolean isSleeping() { - return this.getGrizzlyBearFlag(SLEEPING_FLAG); - } - - void setSleeping(boolean sleeping) { - this.setGrizzlyBearFlag(SLEEPING_FLAG, sleeping); - } - - private boolean getGrizzlyBearFlag(int bitmask) { - return (this.dataTracker.get(GRIZZLY_BEAR_FLAGS) & bitmask) != 0; - } - - private void setGrizzlyBearFlag(int mask, boolean value) { - if (value) { - this.dataTracker.set(GRIZZLY_BEAR_FLAGS, (byte) (this.dataTracker.get(GRIZZLY_BEAR_FLAGS) | mask)); - } else { - this.dataTracker.set(GRIZZLY_BEAR_FLAGS, (byte) (this.dataTracker.get(GRIZZLY_BEAR_FLAGS) & ~mask)); - } - - } - - protected void initDataTracker() { - super.initDataTracker(); - this.dataTracker.startTracking(GRIZZLY_BEAR_FLAGS, (byte) 0); - } - - @Nullable - @Override - public PassiveEntity createChild(ServerWorld world, PassiveEntity entity) { - return ForestalEntities.GRIZZLY_BEAR.create(world); - } - - @Override - protected void playStepSound(BlockPos pos, BlockState state) { - this.playSound(ForestalSoundEvents.ENTITY_GRIZZLY_BEAR_STEP, 0.15f, 1.0f); - } - - public boolean isBreedingItem(ItemStack stack) { - return stack.isIn(ForestalTags.Items.GRIZZLY_BEAR_FOOD); - } - - @Override - public void initGoals() { - super.initGoals(); - this.goalSelector.add(0, new SwimGoal(this)); - this.goalSelector.add(1, new EscapeDangerGoal(this, 1.1)); - this.goalSelector.add(2, new AnimalMateGoal(this, 1.05)); - this.goalSelector.add(3, new TemptGoal(this, 0.9, Ingredient.fromTag(ForestalTags.Items.GRIZZLY_BEAR_FOOD), false)); - this.goalSelector.add(4, new FindSleepingPlaceGoal(0.85)); - this.goalSelector.add(5, new SleepGoal()); - this.goalSelector.add(6, new FollowParentGoal(this, 0.95)); - this.goalSelector.add(7, new WanderAroundFarGoal(this, 0.9)); - this.goalSelector.add(8, new WanderAroundGoal(this, 0.85)); - this.goalSelector.add(9, new LookAtEntityGoal(this, PlayerEntity.class, 6.0f, 0.017f)); - this.goalSelector.add(10, new LookAtEntityGoal(this, VillagerEntity.class, 4.0f, 0.007f)); - this.goalSelector.add(11, new LookAroundGoal(this)); - } - - @Override - public void tick() { - super.tick(); - if (this.canMoveVoluntarily() && this.isTouchingWater() || this.getWorld().isDay()) { - this.setSleeping(false); - } - } - - @Override - public void tickMovement() { - if (this.isSleeping() || this.isImmobile()) { - this.jumping = false; - this.sidewaysSpeed = 0.0F; - this.forwardSpeed = 0.0F; - } - - super.tickMovement(); - } - - @Override - public SoundEvent getAmbientSound() { - if (this.isBaby()) { - return ForestalSoundEvents.ENTITY_GRIZZLY_BEAR_AMBIENT_BABY; - } - return ForestalSoundEvents.ENTITY_GRIZZLY_BEAR_AMBIENT; - } - - @Override - public void playAmbientSound() { - if (this.isSleeping()) { return; } - super.playAmbientSound(); - } - - @Override - protected SoundEvent getHurtSound(DamageSource source) { - return ForestalSoundEvents.ENTITY_GRIZZLY_BEAR_HURT; - } - - public void writeCustomDataToNbt(NbtCompound nbt) { - super.writeCustomDataToNbt(nbt); - nbt.putBoolean("Sleeping", this.isSleeping()); + SOUND_AMBIENT_BABY = ForestalSoundEvents.ENTITY_GRIZZLY_BEAR_AMBIENT_BABY; + SOUND_AMBIENT = ForestalSoundEvents.ENTITY_GRIZZLY_BEAR_AMBIENT; + SOUND_STEP = ForestalSoundEvents.ENTITY_GRIZZLY_BEAR_STEP; + SOUND_HURT = ForestalSoundEvents.ENTITY_GRIZZLY_BEAR_HURT; + FOOD_TAG = ForestalTags.Items.GRIZZLY_BEAR_FOOD; } @Override @@ -177,14 +46,6 @@ public ActionResult interactMob(PlayerEntity player, Hand hand) { return super.interactMob(player, hand); } - public void readCustomDataFromNbt(NbtCompound nbt) { - super.readCustomDataFromNbt(nbt); - this.setSleeping(nbt.getBoolean("Sleeping")); - } - - @Override - protected SoundEvent getDeathSound() { return ForestalSoundEvents.ENTITY_GRIZZLY_BEAR_DEATH; } - @Override public void registerControllers(AnimatableManager.ControllerRegistrar controllers) { controllers.add(new AnimationController<>(this, "controller", 0, this::predicate)); @@ -205,90 +66,8 @@ private PlayState predicate(AnimationState animationState) { return PlayState.CONTINUE; } - @Override - public AnimatableInstanceCache getAnimatableInstanceCache() { return cache; } - - private class SleepGoal extends Goal { - private static final int MAX_CALM_DOWN_TIME = toGoalTicks(280); - private int timer; - - public SleepGoal() { - super(); - this.timer = GrizzlyBearEntity.this.random.nextInt(MAX_CALM_DOWN_TIME); - this.setControls(EnumSet.of(Control.MOVE, Control.LOOK, Control.JUMP)); - } - - protected boolean isAtFavoredLocation() { - BlockPos blockPos = BlockPos.ofFloored(GrizzlyBearEntity.this.getX(), GrizzlyBearEntity.this.getBoundingBox().maxY, GrizzlyBearEntity.this.getZ()); - return !GrizzlyBearEntity.this.getWorld() - .isSkyVisible(blockPos) && GrizzlyBearEntity.this.getPathfindingFavor(blockPos) >= 0.0f; - } - - public boolean canStart() { - if (GrizzlyBearEntity.this.sidewaysSpeed == 0.0F && GrizzlyBearEntity.this.upwardSpeed == 0.0F && GrizzlyBearEntity.this.forwardSpeed == 0.0F && GrizzlyBearEntity.this.getWorld() - .isNight()) { - return this.canNotSleep() || !GrizzlyBearEntity.this.isSleeping(); - } else { - return false; - } - } - - public boolean shouldContinue() { - return this.canNotSleep(); - } - - private boolean canNotSleep() { - if (this.timer > 0) { - --this.timer; - return false; - } else { - return this.isAtFavoredLocation() && !GrizzlyBearEntity.this.inPowderSnow; - } - } - - public void stop() { - this.timer = GrizzlyBearEntity.this.random.nextInt(MAX_CALM_DOWN_TIME); - GrizzlyBearEntity.this.setSleeping(false); - } - - public void start() { - GrizzlyBearEntity.this.setJumping(false); - GrizzlyBearEntity.this.setSleeping(true); - GrizzlyBearEntity.this.getNavigation().stop(); - GrizzlyBearEntity.this.getMoveControl() - .moveTo(GrizzlyBearEntity.this.getX(), GrizzlyBearEntity.this.getY(), GrizzlyBearEntity.this.getZ(), 0.0); - } - } - - class FindSleepingPlaceGoal extends EscapeSunlightGoal { - private int timer = toGoalTicks(100); - - public FindSleepingPlaceGoal(double speed) { - super(GrizzlyBearEntity.this, speed); - } - public boolean canStart() { - if (!GrizzlyBearEntity.this.isSleeping() && GrizzlyBearEntity.this.getWorld() - .isNight()) { - if (GrizzlyBearEntity.this.getWorld().isSkyVisible(this.mob.getBlockPos())) { - return this.targetShadedPos(); - } else if (this.timer > 0) { - --this.timer; - return false; - } else { - this.timer = 100; - BlockPos blockPos = this.mob.getBlockPos(); - return GrizzlyBearEntity.this.getWorld() - .isSkyVisible(blockPos) && !((ServerWorld) GrizzlyBearEntity.this.getWorld()).isNearOccupiedPointOfInterest(blockPos) && this.targetShadedPos(); - } - } else { - return false; - } - } - public void start() { - GrizzlyBearEntity.this.setSleeping(false); - super.start(); - } - } + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { return cache; } } diff --git a/src/main/java/net/rotgruengelb/forestal/item/ForestalItems.java b/src/main/java/net/rotgruengelb/forestal/item/ForestalItems.java index 5622bbd..4135f12 100644 --- a/src/main/java/net/rotgruengelb/forestal/item/ForestalItems.java +++ b/src/main/java/net/rotgruengelb/forestal/item/ForestalItems.java @@ -17,9 +17,10 @@ public class ForestalItems { public static final Item GRIZZLY_BEAR_SPAWN_EGG = registerItem("grizzly_bear_spawn_egg", new SpawnEggItem(ForestalEntities.GRIZZLY_BEAR, 0x966240, 0x553a28, new FabricItemSettings())); + // public static final Item DEER_SPAWN_EGG = registerItem("deer_spawn_egg", new SpawnEggItem(ForestalEntities.DEER, 0x966240, 0x553a28, new FabricItemSettings())); public static final Item GRIZZLY_BEAR_HAIR = registerItem("grizzly_bear_hair", new Item(new FabricItemSettings())); public static final Item MUSIC_DISC_REVERB = registerMusicDisc("reverb", 14, ForestalSoundEvents.MUSIC_DISC_REVERB, 79); - public static final Item MUSIC_DISC_SUNRAYS = registerMusicDisc("sunrays", 15, ForestalSoundEvents.MUSIC_DISC_SUNRAYS, 240); + public static final Item MUSIC_DISC_SUNRAYS = registerMusicDisc("foolishly", 15, ForestalSoundEvents.MUSIC_DISC_FOOLISHLY, 191); private static Item registerItem(String name, Item item) { return Registry.register(Registries.ITEM, new Identifier(Forestal.MOD_ID, name), item); diff --git a/src/main/java/net/rotgruengelb/forestal/sound/ForestalSoundEvents.java b/src/main/java/net/rotgruengelb/forestal/sound/ForestalSoundEvents.java index aa900df..4b050a4 100644 --- a/src/main/java/net/rotgruengelb/forestal/sound/ForestalSoundEvents.java +++ b/src/main/java/net/rotgruengelb/forestal/sound/ForestalSoundEvents.java @@ -14,7 +14,7 @@ public class ForestalSoundEvents { public static final SoundEvent ENTITY_GRIZZLY_BEAR_HURT = registerSoundEvent("entity.forestal.grizzly_bear.hurt"); public static final SoundEvent ENTITY_GRIZZLY_BEAR_DEATH = registerSoundEvent("entity.forestal.grizzly_bear.death"); public static final SoundEvent MUSIC_DISC_REVERB = registerSoundEvent("music_disc.forestal.reverb"); - public static final SoundEvent MUSIC_DISC_SUNRAYS = registerSoundEvent("music_disc.forestal.sunrays"); + public static final SoundEvent MUSIC_DISC_FOOLISHLY = registerSoundEvent("music_disc.forestal.foolishly"); private static SoundEvent registerSoundEvent(String id) { return registerSoundEvent(new Identifier(Forestal.MOD_ID, id)); diff --git a/src/main/java/net/rotgruengelb/forestal/world/gen/ForestalEntityGeneration.java b/src/main/java/net/rotgruengelb/forestal/world/gen/ForestalEntityGeneration.java index 5e93c9f..4b52417 100644 --- a/src/main/java/net/rotgruengelb/forestal/world/gen/ForestalEntityGeneration.java +++ b/src/main/java/net/rotgruengelb/forestal/world/gen/ForestalEntityGeneration.java @@ -11,10 +11,20 @@ public class ForestalEntityGeneration { public static void addSpawns() { - BiomeModifications.addSpawn(BiomeSelectors.tag(ForestalTags.Biomes.SPAWNS_GRIZZLY_BEAR.COMMON), SpawnGroup.CREATURE, ForestalEntities.GRIZZLY_BEAR, 30, 1, 2); + addGrizzlyBearSpawn(); + // addDeerSpawn(); + } + public static void addGrizzlyBearSpawn() { + BiomeModifications.addSpawn(BiomeSelectors.tag(ForestalTags.Biomes.SPAWNS_GRIZZLY_BEAR.COMMON), SpawnGroup.CREATURE, ForestalEntities.GRIZZLY_BEAR, 30, 1, 2); BiomeModifications.addSpawn(BiomeSelectors.tag(ForestalTags.Biomes.SPAWNS_GRIZZLY_BEAR.RARE), SpawnGroup.CREATURE, ForestalEntities.GRIZZLY_BEAR, 7, 1, 1); - SpawnRestriction.register(ForestalEntities.GRIZZLY_BEAR, SpawnRestriction.Location.ON_GROUND, Heightmap.Type.MOTION_BLOCKING_NO_LEAVES, GrizzlyBearEntity::isValidGrizzlyBearSpawn); + SpawnRestriction.register(ForestalEntities.GRIZZLY_BEAR, SpawnRestriction.Location.ON_GROUND, Heightmap.Type.MOTION_BLOCKING_NO_LEAVES, GrizzlyBearEntity::isValidBearSpawn); } + + // public static void addDeerSpawn() { + // BiomeModifications.addSpawn(BiomeSelectors.tag(ForestalTags.Biomes.SPAWNS_GRIZZLY_BEAR.COMMON), SpawnGroup.CREATURE, ForestalEntities.DEER, 30, 1, 4); + // + // SpawnRestriction.register(ForestalEntities.DEER, SpawnRestriction.Location.ON_GROUND, Heightmap.Type.MOTION_BLOCKING_NO_LEAVES, DeerEntity::isValidDeerSpawn); + // } } diff --git a/src/main/resources/assets/forestal/animations/deer.animation.json b/src/main/resources/assets/forestal/animations/deer.animation.json new file mode 100644 index 0000000..a99e41a --- /dev/null +++ b/src/main/resources/assets/forestal/animations/deer.animation.json @@ -0,0 +1,111 @@ +{ + "format_version": "1.8.0", + "animations": { + "animation.deer.walk": { + "loop": true, + "animation_length": 1.5, + "bones": { + "Head": { + "rotation": { + "vector": [0, 0, "math.sin(36+query.anim_time*240)*2"] + }, + "position": { + "vector": [0, "math.sin(query.anim_time*480)*0.25", 0] + } + }, + "body": { + "rotation": { + "vector": [0, 0, 0] + }, + "position": { + "vector": [0, "math.sin(query.anim_time*480)*0.25", 0] + } + }, + "leg_1": { + "rotation": { + "vector": ["math.sin(query.anim_time*240)*-15", 0, 0] + }, + "position": { + "vector": [0, "math.max(0,math.cos(query.anim_time*240)*1)", 0] + } + }, + "leg_2": { + "rotation": { + "vector": ["math.sin(query.anim_time*240)*15", 0, 0] + }, + "position": { + "vector": [0, "math.max(0,math.cos(query.anim_time*240)*-1)", 0] + } + }, + "leg_3": { + "rotation": { + "vector": ["math.sin(query.anim_time*240)*15", 0, 0] + }, + "position": { + "vector": [0, "math.max(0,math.cos(query.anim_time*240)*-1)", 0] + } + }, + "leg_4": { + "rotation": { + "vector": ["math.sin(query.anim_time*240)*-15", 0, 0] + }, + "position": { + "vector": [0, "math.max(0,math.cos(query.anim_time*240)*1)", 0] + } + }, + "tail": { + "rotation": { + "vector": ["math.sin(query.anim_time * 480) * 2", 0, 0] + } + } + } + }, + "animation.deer.idle": { + "loop": true, + "animation_length": 2, + "bones": { + "Head": { + "rotation": { + "vector": ["Math.sin((query.anim_time + 0.1) * 180) * 1", 0, 0] + }, + "position": { + "vector": [0, "Math.sin((query.anim_time - 0.0) * 180) * 0.4", 0] + } + }, + "body": { + "position": { + "vector": [0, "Math.sin((query.anim_time - 0.0) * 180) * 0.4", 0] + } + }, + "tail": { + "rotation": { + "vector": [0, 0, "math.sin(query.anim_time * 180) * 3"] + } + } + } + }, + "animation.deer.eat": { + "loop": true, + "animation_length": 1.5, + "bones": { + "Head": { + "rotation": { + "vector": ["105+ math.sin(query.anim_time * 480) * 4", 0, 0] + }, + "position": { + "vector": [0, 0, 0] + } + }, + "body": { + "rotation": { + "vector": [10, 0, 0] + }, + "position": { + "vector": [0, 0, 1] + } + } + } + } + }, + "geckolib_format_version": 2 +} \ No newline at end of file diff --git a/src/main/resources/assets/forestal/geo/deer.geo.json b/src/main/resources/assets/forestal/geo/deer.geo.json new file mode 100644 index 0000000..0d822fa --- /dev/null +++ b/src/main/resources/assets/forestal/geo/deer.geo.json @@ -0,0 +1,90 @@ +{ + "format_version": "1.12.0", + "minecraft:geometry": [ + { + "description": { + "identifier": "geometry.unknown", + "texture_width": 64, + "texture_height": 64, + "visible_bounds_width": 3, + "visible_bounds_height": 3.5, + "visible_bounds_offset": [0, 1.25, 0] + }, + "bones": [ + { + "name": "Deer", + "pivot": [0, 9, 0] + }, + { + "name": "Head", + "parent": "Deer", + "pivot": [0.5, 20.41667, -6.16667], + "cubes": [ + {"origin": [-3, 20, -10], "size": [7, 5, 6], "uv": [31, 0]}, + {"origin": [-2, 20, -14], "size": [5, 2, 4], "uv": [44, 11]}, + {"origin": [-6, 22, -7], "size": [3, 2, 1], "uv": [44, 17]}, + {"origin": [4, 22, -7], "size": [3, 2, 1], "uv": [0, 49]}, + {"origin": [2, 25, -9], "size": [7, 7, 7], "uv": [28, 22]}, + {"origin": [-8, 25, -9], "size": [7, 7, 7], "uv": [0, 22]} + ] + }, + { + "name": "neck", + "parent": "Head", + "pivot": [0, 11, -5], + "cubes": [ + {"origin": [-2, 11, -8], "size": [5, 9, 4], "uv": [0, 36]} + ] + }, + { + "name": "body", + "parent": "Deer", + "pivot": [0, 9, 0], + "cubes": [ + {"origin": [-4, 9, -6], "size": [9, 9, 13], "uv": [0, 0]} + ] + }, + { + "name": "tail", + "parent": "body", + "pivot": [0.5, 17.5, 7], + "cubes": [ + {"origin": [-1, 16, 7], "size": [3, 5, 2], "uv": [21, 22]} + ] + }, + { + "name": "leg_1", + "parent": "Deer", + "pivot": [-1.5, 10, -3.5], + "cubes": [ + {"origin": [-3, 0, -5], "size": [3, 10, 3], "uv": [0, 0]} + ] + }, + { + "name": "leg_2", + "parent": "Deer", + "pivot": [2.5, 10, -3.5], + "cubes": [ + {"origin": [1, 0, -5], "size": [3, 10, 3], "uv": [42, 36]} + ] + }, + { + "name": "leg_3", + "parent": "Deer", + "pivot": [-1.5, 10, 6.5], + "cubes": [ + {"origin": [-3, 0, 5], "size": [3, 10, 3], "uv": [18, 36]} + ] + }, + { + "name": "leg_4", + "parent": "Deer", + "pivot": [2.5, 10, 6.5], + "cubes": [ + {"origin": [1, 0, 5], "size": [3, 10, 3], "uv": [30, 36]} + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/forestal/lang/en_us.json b/src/main/resources/assets/forestal/lang/en_us.json index 82cc10c..5545948 100644 --- a/src/main/resources/assets/forestal/lang/en_us.json +++ b/src/main/resources/assets/forestal/lang/en_us.json @@ -3,8 +3,8 @@ "entity.forestal.grizzly_bear": "Grizzly Bear", "item.forestal.grizzly_bear_spawn_egg": "Grizzly Bear Spawn Egg", "item.forestal.grizzly_bear_hair": "Grizzly Bear Hair", - "item.forestal.music_disc_sunrays": "Music Disc", - "item.forestal.music_disc_sunrays.desc": "Shaun1p - sunrays", + "item.forestal.music_disc_foolishly": "Music Disc", + "item.forestal.music_disc_foolishly.desc": "Shaun1p - foolishly", "item.forestal.music_disc_reverb": "Music Disc", "item.forestal.music_disc_reverb.desc": "Rotgruengelb - reverb", "subtitles.entity.forestal.grizzly_bear.ambient": "Grizzly Bear groans", diff --git a/src/main/resources/assets/forestal/models/item/deer_spawn_egg.json b/src/main/resources/assets/forestal/models/item/deer_spawn_egg.json new file mode 100644 index 0000000..fff64c3 --- /dev/null +++ b/src/main/resources/assets/forestal/models/item/deer_spawn_egg.json @@ -0,0 +1,3 @@ +{ + "parent": "minecraft:item/template_spawn_egg" +} \ No newline at end of file diff --git a/src/main/resources/assets/forestal/models/item/music_disc_sunrays.json b/src/main/resources/assets/forestal/models/item/music_disc_foolishly.json similarity index 58% rename from src/main/resources/assets/forestal/models/item/music_disc_sunrays.json rename to src/main/resources/assets/forestal/models/item/music_disc_foolishly.json index 1a96cbe..69ab86e 100644 --- a/src/main/resources/assets/forestal/models/item/music_disc_sunrays.json +++ b/src/main/resources/assets/forestal/models/item/music_disc_foolishly.json @@ -1,6 +1,6 @@ { "parent": "minecraft:item/template_music_disc", "textures": { - "layer0": "forestal:item/music_disc_sunrays" + "layer0": "forestal:item/music_disc_foolishly" } } \ No newline at end of file diff --git a/src/main/resources/assets/forestal/sounds.json b/src/main/resources/assets/forestal/sounds.json index 826d247..7d578dc 100644 --- a/src/main/resources/assets/forestal/sounds.json +++ b/src/main/resources/assets/forestal/sounds.json @@ -7,10 +7,10 @@ } ] }, - "music_disc.forestal.sunrays": { + "music_disc.forestal.foolishly": { "sounds": [ { - "name": "forestal:records/sunrays", + "name": "forestal:records/foolishly", "stream": true } ] diff --git a/src/main/resources/assets/forestal/sounds/records/foolishly.ogg b/src/main/resources/assets/forestal/sounds/records/foolishly.ogg new file mode 100644 index 0000000..19fd2ac Binary files /dev/null and b/src/main/resources/assets/forestal/sounds/records/foolishly.ogg differ diff --git a/src/main/resources/assets/forestal/textures/entity/deer.png b/src/main/resources/assets/forestal/textures/entity/deer.png new file mode 100644 index 0000000..e5b7c4e Binary files /dev/null and b/src/main/resources/assets/forestal/textures/entity/deer.png differ diff --git a/src/main/resources/assets/forestal/textures/item/music_disc_sunrays.png b/src/main/resources/assets/forestal/textures/item/music_disc_foolishly.png similarity index 100% rename from src/main/resources/assets/forestal/textures/item/music_disc_sunrays.png rename to src/main/resources/assets/forestal/textures/item/music_disc_foolishly.png diff --git a/src/main/resources/data/minecraft/tags/items/music_discs.json b/src/main/resources/data/minecraft/tags/items/music_discs.json index 7f90294..9f6276d 100644 --- a/src/main/resources/data/minecraft/tags/items/music_discs.json +++ b/src/main/resources/data/minecraft/tags/items/music_discs.json @@ -6,7 +6,7 @@ "required": false }, { - "id": "forestal:music_disc_sunrays", + "id": "forestal:music_disc_foolishly", "required": false } ]