ну типо фиксы всякие
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
--- a/net/minecraft/client/renderer/entity/LivingEntityRenderer.java
|
||||
+++ b/net/minecraft/client/renderer/entity/LivingEntityRenderer.java
|
||||
@@ -49,14 +_,17 @@
|
||||
}
|
||||
|
||||
public void m_7392_(T p_115308_, float p_115309_, float p_115310_, PoseStack p_115311_, MultiBufferSource p_115312_, int p_115313_) {
|
||||
+ if (net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.client.event.RenderLivingEvent.Pre<T, M>(p_115308_, this, p_115310_, p_115311_, p_115312_, p_115313_))) return;
|
||||
p_115311_.m_85836_();
|
||||
this.f_115290_.f_102608_ = this.m_115342_(p_115308_, p_115310_);
|
||||
- this.f_115290_.f_102609_ = p_115308_.m_20159_();
|
||||
+
|
||||
+ boolean shouldSit = p_115308_.m_20159_() && (p_115308_.m_20202_() != null && p_115308_.m_20202_().shouldRiderSit());
|
||||
+ this.f_115290_.f_102609_ = shouldSit;
|
||||
this.f_115290_.f_102610_ = p_115308_.m_6162_();
|
||||
float f = Mth.m_14189_(p_115310_, p_115308_.f_20884_, p_115308_.f_20883_);
|
||||
float f1 = Mth.m_14189_(p_115310_, p_115308_.f_20886_, p_115308_.f_20885_);
|
||||
float f2 = f1 - f;
|
||||
- if (p_115308_.m_20159_() && p_115308_.m_20202_() instanceof LivingEntity) {
|
||||
+ if (shouldSit && p_115308_.m_20202_() instanceof LivingEntity) {
|
||||
LivingEntity livingentity = (LivingEntity)p_115308_.m_20202_();
|
||||
f = Mth.m_14189_(p_115310_, livingentity.f_20884_, livingentity.f_20883_);
|
||||
f2 = f1 - f;
|
||||
@@ -98,7 +_,7 @@
|
||||
p_115311_.m_252880_(0.0F, -1.501F, 0.0F);
|
||||
float f8 = 0.0F;
|
||||
float f5 = 0.0F;
|
||||
- if (!p_115308_.m_20159_() && p_115308_.m_6084_()) {
|
||||
+ if (!shouldSit && p_115308_.m_6084_()) {
|
||||
f8 = p_115308_.f_267362_.m_267711_(p_115310_);
|
||||
f5 = p_115308_.f_267362_.m_267590_(p_115310_);
|
||||
if (p_115308_.m_6162_()) {
|
||||
@@ -131,6 +_,7 @@
|
||||
|
||||
p_115311_.m_85849_();
|
||||
super.m_7392_(p_115308_, p_115309_, p_115310_, p_115311_, p_115312_, p_115313_);
|
||||
+ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.client.event.RenderLivingEvent.Post<T, M>(p_115308_, this, p_115310_, p_115311_, p_115312_, p_115313_));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -0,0 +1,177 @@
|
||||
package me.sashegdev.fabled_hearts.ai;
|
||||
|
||||
import me.sashegdev.fabled_hearts.entity.ellie.EllieEntity;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.entity.ai.goal.Goal;
|
||||
import net.minecraft.world.level.block.DoorBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.pathfinder.Node;
|
||||
import net.minecraft.world.level.pathfinder.Path;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
public class EllieDoorInteractGoal extends Goal {
|
||||
private static final int CLOSE_DELAY = 25;
|
||||
private static final double CLOSE_DIST_SQ = 2.0 * 2.0;
|
||||
private static final double WAYPOINT_REACH_DIST = 0.4;
|
||||
|
||||
private final EllieEntity ellie;
|
||||
private BlockPos doorPos;
|
||||
private BlockPos pairedDoorPos;
|
||||
private Vec3 passageCenter;
|
||||
private boolean hasPassed;
|
||||
private int closeTimer;
|
||||
|
||||
public EllieDoorInteractGoal(EllieEntity ellie) {
|
||||
this.ellie = ellie;
|
||||
this.setFlags(EnumSet.noneOf(Flag.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUse() {
|
||||
if (ellie.tickCount < 20) return false;
|
||||
return !ellie.isSleeping();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requiresUpdateEveryTick() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
if (doorPos != null) {
|
||||
BlockState state = ellie.level().getBlockState(doorPos);
|
||||
if (!(state.getBlock() instanceof DoorBlock)) {
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
|
||||
if (passageCenter != null) {
|
||||
boolean reached = ellie.distanceToSqr(passageCenter) < WAYPOINT_REACH_DIST * WAYPOINT_REACH_DIST
|
||||
|| ellie.getNavigation().isDone();
|
||||
if (reached) {
|
||||
passageCenter = null;
|
||||
} else {
|
||||
ellie.getNavigation().moveTo(passageCenter.x, passageCenter.y, passageCenter.z, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasPassed) {
|
||||
double distSq = ellie.distanceToSqr(Vec3.atCenterOf(doorPos));
|
||||
if (distSq > CLOSE_DIST_SQ) {
|
||||
hasPassed = true;
|
||||
closeTimer = CLOSE_DELAY;
|
||||
}
|
||||
} else if (--closeTimer <= 0) {
|
||||
closeDoor(doorPos);
|
||||
if (pairedDoorPos != null) {
|
||||
closeDoor(pairedDoorPos);
|
||||
}
|
||||
clear();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
BlockPos door = findDoor();
|
||||
if (door != null) {
|
||||
BlockState state = ellie.level().getBlockState(door);
|
||||
openDoor(door, state);
|
||||
|
||||
doorPos = door;
|
||||
pairedDoorPos = findPairedDoor(door, state);
|
||||
if (pairedDoorPos != null) {
|
||||
BlockState pairedState = ellie.level().getBlockState(pairedDoorPos);
|
||||
if (pairedState.getBlock() instanceof DoorBlock) {
|
||||
if (!pairedState.getValue(DoorBlock.OPEN)) {
|
||||
openDoor(pairedDoorPos, pairedState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hasPassed = false;
|
||||
closeTimer = 0;
|
||||
passageCenter = calcPassageCenter();
|
||||
ellie.getNavigation().moveTo(passageCenter.x, passageCenter.y, passageCenter.z, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
private void openDoor(BlockPos pos, BlockState state) {
|
||||
if (state.getBlock() instanceof DoorBlock door && !state.getValue(DoorBlock.OPEN)) {
|
||||
door.setOpen(ellie, ellie.level(), state, pos, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void closeDoor(BlockPos pos) {
|
||||
BlockState state = ellie.level().getBlockState(pos);
|
||||
if (state.getBlock() instanceof DoorBlock door && state.getValue(DoorBlock.OPEN)) {
|
||||
door.setOpen(null, ellie.level(), state, pos, false);
|
||||
}
|
||||
}
|
||||
|
||||
private BlockPos findDoor() {
|
||||
Path path = ellie.getNavigation().getPath();
|
||||
if (path != null && !path.isDone()) {
|
||||
BlockPos entityPos = ellie.blockPosition();
|
||||
for (int i = 0; i < Math.min(8, path.getNodeCount()); i++) {
|
||||
Node node = path.getNode(i);
|
||||
if (node == null) continue;
|
||||
BlockPos checkPos = new BlockPos(node.x, node.y, node.z);
|
||||
if (checkPos.distSqr(entityPos) > 64) continue;
|
||||
if (checkForDoor(checkPos)) return checkPos;
|
||||
if (checkForDoor(checkPos.above())) return checkPos.above();
|
||||
}
|
||||
}
|
||||
BlockPos center = ellie.blockPosition();
|
||||
for (int dx = -1; dx <= 1; dx++) {
|
||||
for (int dz = -1; dz <= 1; dz++) {
|
||||
BlockPos checkPos = center.offset(dx, 0, dz);
|
||||
if (checkForDoor(checkPos)) return checkPos;
|
||||
if (checkForDoor(checkPos.above())) return checkPos.above();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean checkForDoor(BlockPos pos) {
|
||||
BlockState state = ellie.level().getBlockState(pos);
|
||||
return state.getBlock() instanceof DoorBlock && !state.getValue(DoorBlock.OPEN);
|
||||
}
|
||||
|
||||
private BlockPos findPairedDoor(BlockPos pos, BlockState state) {
|
||||
Direction facing = state.getValue(DoorBlock.FACING);
|
||||
for (Direction adj : Direction.Plane.HORIZONTAL) {
|
||||
BlockPos adjPos = pos.relative(adj);
|
||||
BlockState adjState = ellie.level().getBlockState(adjPos);
|
||||
if (adjState.getBlock() instanceof DoorBlock) {
|
||||
Direction adjFacing = adjState.getValue(DoorBlock.FACING);
|
||||
if (adjFacing == facing.getOpposite()) {
|
||||
return adjPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Vec3 calcPassageCenter() {
|
||||
if (pairedDoorPos != null) {
|
||||
return Vec3.atCenterOf(doorPos).add(Vec3.atCenterOf(pairedDoorPos)).scale(0.5);
|
||||
}
|
||||
return Vec3.atCenterOf(doorPos);
|
||||
}
|
||||
|
||||
private void clear() {
|
||||
doorPos = null;
|
||||
pairedDoorPos = null;
|
||||
passageCenter = null;
|
||||
hasPassed = false;
|
||||
closeTimer = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
clear();
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,33 @@
|
||||
package me.sashegdev.fabled_hearts.ai;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.Mob;
|
||||
import net.minecraft.world.entity.ai.navigation.GroundPathNavigation;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.pathfinder.BlockPathTypes;
|
||||
import net.minecraft.world.level.pathfinder.PathFinder;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public class ElliePathNavigation extends GroundPathNavigation {
|
||||
|
||||
private Vec3 lastDest;
|
||||
private double lastSpeed;
|
||||
private BlockPos lastStuckCheck;
|
||||
private int stuckTicks;
|
||||
private int repathTimer;
|
||||
|
||||
private static final int REPATH_INTERVAL = 60;
|
||||
private static final int STUCK_THRESHOLD = 40;
|
||||
private static final int CROUCH_STUCK_THRESHOLD = 120;
|
||||
private static final double PROGRESS_MIN_SQ = 0.2 * 0.2;
|
||||
|
||||
public ElliePathNavigation(Mob mob, Level level) {
|
||||
super(mob, level);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PathFinder createPathFinder(int maxVisitedNodes) {
|
||||
mob.setPathfindingMalus(BlockPathTypes.DOOR_WOOD_CLOSED, 2.0F);
|
||||
mob.setPathfindingMalus(BlockPathTypes.DOOR_WOOD_CLOSED, 0.0F);
|
||||
mob.setPathfindingMalus(BlockPathTypes.DOOR_IRON_CLOSED, 5.0F);
|
||||
mob.setPathfindingMalus(BlockPathTypes.DANGER_FIRE, -1.0F);
|
||||
mob.setPathfindingMalus(BlockPathTypes.DAMAGE_FIRE, -1.0F);
|
||||
@@ -29,4 +42,65 @@ public class ElliePathNavigation extends GroundPathNavigation {
|
||||
this.nodeEvaluator = evaluator;
|
||||
return new PathFinder(evaluator, maxVisitedNodes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
if (isInProgress() && lastDest != null) {
|
||||
BlockPos currentPos = mob.blockPosition();
|
||||
|
||||
boolean crouching = mob.getPose() == net.minecraft.world.entity.Pose.CROUCHING;
|
||||
|
||||
if (lastStuckCheck != null) {
|
||||
double movedSq = currentPos.distSqr(lastStuckCheck);
|
||||
if (movedSq < PROGRESS_MIN_SQ) {
|
||||
stuckTicks++;
|
||||
} else {
|
||||
stuckTicks = 0;
|
||||
}
|
||||
}
|
||||
lastStuckCheck = currentPos;
|
||||
|
||||
int threshold = crouching ? CROUCH_STUCK_THRESHOLD : STUCK_THRESHOLD;
|
||||
if (stuckTicks > threshold) {
|
||||
moveTo(lastDest.x, lastDest.y, lastDest.z, lastSpeed);
|
||||
stuckTicks = 0;
|
||||
repathTimer = 0;
|
||||
}
|
||||
|
||||
if (!crouching && repathTimer++ > REPATH_INTERVAL) {
|
||||
moveTo(lastDest.x, lastDest.y, lastDest.z, lastSpeed);
|
||||
repathTimer = 0;
|
||||
}
|
||||
} else if (isDone() && lastDest != null) {
|
||||
if (mob.distanceToSqr(lastDest) > 4.0) {
|
||||
if (repathTimer++ > REPATH_INTERVAL) {
|
||||
moveTo(lastDest.x, lastDest.y, lastDest.z, lastSpeed);
|
||||
repathTimer = 0;
|
||||
}
|
||||
} else {
|
||||
lastDest = null;
|
||||
}
|
||||
}
|
||||
|
||||
super.tick();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean moveTo(double x, double y, double z, double speed) {
|
||||
lastDest = new Vec3(x, y, z);
|
||||
lastSpeed = speed;
|
||||
stuckTicks = 0;
|
||||
repathTimer = 0;
|
||||
lastStuckCheck = mob.blockPosition();
|
||||
return super.moveTo(x, y, z, speed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
super.stop();
|
||||
lastDest = null;
|
||||
stuckTicks = 0;
|
||||
repathTimer = 0;
|
||||
lastStuckCheck = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,7 @@ import me.sashegdev.fabled_hearts.entity.ellie.EllieEntity;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.ai.goal.Goal;
|
||||
import net.minecraft.world.level.block.BedBlock;
|
||||
import net.minecraft.world.level.block.DoorBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.pathfinder.Node;
|
||||
import net.minecraft.world.level.pathfinder.Path;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import java.util.EnumSet;
|
||||
@@ -62,8 +59,6 @@ public class EllieSleepGoal extends Goal {
|
||||
return;
|
||||
}
|
||||
|
||||
tryOpenDoor();
|
||||
|
||||
double distSqr = ellie.distanceToSqr(Vec3.atCenterOf(bedPos));
|
||||
|
||||
if (distSqr < REACH_DIST_SQR) {
|
||||
@@ -87,35 +82,6 @@ public class EllieSleepGoal extends Goal {
|
||||
}
|
||||
}
|
||||
|
||||
private void tryOpenDoor() {
|
||||
Path path = ellie.getNavigation().getPath();
|
||||
BlockPos entityPos = ellie.blockPosition();
|
||||
if (path != null) {
|
||||
for (int i = 0; i < Math.min(4, path.getNodeCount()); i++) {
|
||||
Node node = path.getNode(i);
|
||||
BlockPos checkPos = new BlockPos(node.x, node.y, node.z);
|
||||
if (checkPos.distSqr(entityPos) > 9) break;
|
||||
BlockState state = ellie.level().getBlockState(checkPos);
|
||||
if (state.getBlock() instanceof DoorBlock) {
|
||||
if (!state.getValue(DoorBlock.OPEN)) {
|
||||
ellie.level().setBlock(checkPos, state.setValue(DoorBlock.OPEN, true), 3);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 3; i++) {
|
||||
BlockPos checkPos = entityPos.relative(ellie.getDirection(), i);
|
||||
BlockState state = ellie.level().getBlockState(checkPos);
|
||||
if (state.getBlock() instanceof DoorBlock) {
|
||||
if (!state.getValue(DoorBlock.OPEN)) {
|
||||
ellie.level().setBlock(checkPos, state.setValue(DoorBlock.OPEN, true), 3);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
if (ellie.isSleeping()) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package me.sashegdev.fabled_hearts.ai;
|
||||
|
||||
import me.sashegdev.fabled_hearts.entity.ellie.EllieEntity;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.ai.goal.Goal;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
@@ -27,8 +28,20 @@ public class FollowPlayerGoal extends Goal {
|
||||
|
||||
@Override
|
||||
public boolean canUse() {
|
||||
if (ellie.tickCount < 20) return false;
|
||||
if (ellie.isSleeping()) return false;
|
||||
if (ellie.hurtTime > 0) return false;
|
||||
|
||||
int followId = ellie.getFollowTargetId();
|
||||
if (followId > 0) {
|
||||
Entity e = ellie.level().getEntity(followId);
|
||||
if (e instanceof Player p && p.isAlive()) {
|
||||
target = p;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
float rel = ellie.getRelationshipPoints();
|
||||
if (rel < 50) return false;
|
||||
|
||||
@@ -51,15 +64,19 @@ public class FollowPlayerGoal extends Goal {
|
||||
if (target == null) return;
|
||||
|
||||
double distSqr = ellie.distanceToSqr(target);
|
||||
float rel = ellie.getRelationshipPoints();
|
||||
|
||||
double minDist, maxDist;
|
||||
if (rel >= 100) {
|
||||
minDist = 1.5; maxDist = 3.0;
|
||||
} else if (rel >= 75) {
|
||||
minDist = 3.0; maxDist = 6.0;
|
||||
if (ellie.getFollowTargetId() == target.getId()) {
|
||||
minDist = 2.0; maxDist = 4.0;
|
||||
} else {
|
||||
minDist = 6.0; maxDist = 10.0;
|
||||
float rel = ellie.getRelationshipPoints();
|
||||
if (rel >= 100) {
|
||||
minDist = 1.5; maxDist = 3.0;
|
||||
} else if (rel >= 75) {
|
||||
minDist = 3.0; maxDist = 6.0;
|
||||
} else {
|
||||
minDist = 6.0; maxDist = 10.0;
|
||||
}
|
||||
}
|
||||
|
||||
if (distSqr > maxDist * maxDist) {
|
||||
@@ -124,6 +141,9 @@ public class FollowPlayerGoal extends Goal {
|
||||
if (target == null || !target.isAlive()) return false;
|
||||
if (ellie.isSleeping()) return false;
|
||||
if (ellie.hurtTime > 0) return false;
|
||||
if (ellie.getFollowTargetId() == target.getId()) {
|
||||
return ellie.isFollowingPlayer();
|
||||
}
|
||||
double distSqr = ellie.distanceToSqr(target);
|
||||
return distSqr <= FOLLOW_RANGE_SQR;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
package me.sashegdev.fabled_hearts.ai;
|
||||
|
||||
import me.sashegdev.fabled_hearts.entity.ellie.EllieEntity;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.ai.goal.Goal;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
public class ShelterGoal extends Goal {
|
||||
private final EllieEntity ellie;
|
||||
private BlockPos shelterPos;
|
||||
private static final int SEARCH_RADIUS = 12;
|
||||
private static final double REACH_DIST_SQR = 1.5 * 1.5;
|
||||
|
||||
public ShelterGoal(EllieEntity ellie) {
|
||||
this.ellie = ellie;
|
||||
this.setFlags(EnumSet.of(Flag.MOVE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUse() {
|
||||
if (ellie.tickCount < 20) return false;
|
||||
if (ellie.isSleeping()) return false;
|
||||
if (!ellie.level().isRaining() && !ellie.level().isThundering()) return false;
|
||||
if (!ellie.isInRain()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
shelterPos = findShelter();
|
||||
if (shelterPos != null) {
|
||||
ellie.getNavigation().moveTo(shelterPos.getX() + 0.5, shelterPos.getY(), shelterPos.getZ() + 0.5, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
if (shelterPos == null) return;
|
||||
if (ellie.distanceToSqr(Vec3.atCenterOf(shelterPos)) < REACH_DIST_SQR) {
|
||||
ellie.getNavigation().stop();
|
||||
} else if (ellie.getNavigation().isDone()) {
|
||||
ellie.getNavigation().moveTo(shelterPos.getX() + 0.5, shelterPos.getY(), shelterPos.getZ() + 0.5, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canContinueToUse() {
|
||||
if (shelterPos == null) return false;
|
||||
if (ellie.isSleeping()) return false;
|
||||
return ellie.level().isRaining() || ellie.level().isThundering();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
shelterPos = null;
|
||||
}
|
||||
|
||||
private boolean hasShelter(BlockPos pos) {
|
||||
Level level = ellie.level();
|
||||
for (int y = 1; y <= 3; y++) {
|
||||
if (level.getBlockState(pos.above(y)).blocksMotion()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private BlockPos findShelter() {
|
||||
BlockPos entityPos = ellie.blockPosition();
|
||||
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
|
||||
BlockPos nearest = null;
|
||||
double nearestDist = Double.MAX_VALUE;
|
||||
|
||||
for (int x = -SEARCH_RADIUS; x <= SEARCH_RADIUS; x++) {
|
||||
for (int z = -SEARCH_RADIUS; z <= SEARCH_RADIUS; z++) {
|
||||
mutable.set(entityPos.getX() + x, entityPos.getY(), entityPos.getZ() + z);
|
||||
int topY = ellie.level().getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, mutable).getY();
|
||||
mutable.setY(topY);
|
||||
if (hasShelter(mutable)) {
|
||||
double dist = entityPos.distSqr(mutable);
|
||||
if (dist < nearestDist) {
|
||||
nearestDist = dist;
|
||||
nearest = mutable.immutable();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nearest;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
package me.sashegdev.fabled_hearts.entity.ellie;
|
||||
|
||||
import me.sashegdev.fabled_hearts.ai.BasicAI;
|
||||
import me.sashegdev.fabled_hearts.ai.EllieDoorInteractGoal;
|
||||
import me.sashegdev.fabled_hearts.ai.ElliePathNavigation;
|
||||
import me.sashegdev.fabled_hearts.ai.EllieSleepGoal;
|
||||
import me.sashegdev.fabled_hearts.ai.IdleAnimationGoal;
|
||||
import me.sashegdev.fabled_hearts.ai.ShelterGoal;
|
||||
import me.sashegdev.fabled_hearts.network.ModNetworking;
|
||||
import me.sashegdev.fabled_hearts.network.OpenDialogPacket;
|
||||
import net.minecraft.core.BlockPos;
|
||||
@@ -16,7 +18,10 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
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.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
||||
import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
@@ -26,13 +31,11 @@ import net.minecraft.world.entity.animal.Animal;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.BedBlock;
|
||||
import net.minecraft.world.level.block.DoorBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.BedPart;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.pathfinder.Node;
|
||||
import net.minecraft.world.level.pathfinder.Path;
|
||||
import net.minecraft.world.level.pathfinder.BlockPathTypes;
|
||||
import net.minecraftforge.network.PacketDistributor;
|
||||
import me.sashegdev.fabled_hearts.network.DebugSyncPacket;
|
||||
import me.sashegdev.fabled_hearts.network.ModNetworking;
|
||||
@@ -66,16 +69,27 @@ public class EllieEntity extends Animal implements GeoEntity {
|
||||
SynchedEntityData.defineId(EllieEntity.class, EntityDataSerializers.BOOLEAN);
|
||||
private static final EntityDataAccessor<String> DATA_DEBUG_BRAIN =
|
||||
SynchedEntityData.defineId(EllieEntity.class, EntityDataSerializers.STRING);
|
||||
private static final EntityDataAccessor<Integer> DATA_TURNING_TIMER =
|
||||
SynchedEntityData.defineId(EllieEntity.class, EntityDataSerializers.INT);
|
||||
private static final EntityDataAccessor<Integer> DATA_DEBUG_ANIM =
|
||||
SynchedEntityData.defineId(EllieEntity.class, EntityDataSerializers.INT);
|
||||
private static final EntityDataAccessor<Integer> DATA_FOLLOW_TARGET =
|
||||
SynchedEntityData.defineId(EllieEntity.class, EntityDataSerializers.INT);
|
||||
|
||||
private static final List<String> DEBUG_ANIMS = List.of(
|
||||
"idle1", "idle2", "idle3", "turn", "eat1", "fall"
|
||||
);
|
||||
|
||||
private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this);
|
||||
|
||||
private int ticksWithoutSleep;
|
||||
private float relationshipPoints;
|
||||
private float prevYRot;
|
||||
private float yawDeltaAccumulator;
|
||||
private BlockPos bedPos;
|
||||
private double lastX, lastZ;
|
||||
private BlockPos lastOpenedDoor;
|
||||
private int doorCloseTimer;
|
||||
private int crouchTimer;
|
||||
private int debugAnimTimer;
|
||||
private boolean needsSleepRestore;
|
||||
|
||||
public EllieEntity(EntityType<? extends Animal> type, Level level) {
|
||||
@@ -84,6 +98,7 @@ public class EllieEntity extends Animal implements GeoEntity {
|
||||
this.setPersistenceRequired();
|
||||
lastX = getX();
|
||||
lastZ = getZ();
|
||||
prevYRot = getYRot();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -111,20 +126,33 @@ public class EllieEntity extends Animal implements GeoEntity {
|
||||
this.entityData.define(DATA_MOVING, false);
|
||||
this.entityData.define(DATA_DEBUG, false);
|
||||
this.entityData.define(DATA_DEBUG_BRAIN, "");
|
||||
this.entityData.define(DATA_TURNING_TIMER, 0);
|
||||
this.entityData.define(DATA_DEBUG_ANIM, 0);
|
||||
this.entityData.define(DATA_FOLLOW_TARGET, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerGoals() {
|
||||
BasicAI.addBasicGoals(this, this.goalSelector, 2);
|
||||
BasicAI.addBasicGoals(this, this.goalSelector, 4);
|
||||
this.goalSelector.addGoal(1, new EllieSleepGoal(this, 30));
|
||||
this.goalSelector.addGoal(1, new EllieDoorInteractGoal(this));
|
||||
this.goalSelector.addGoal(1, new IdleAnimationGoal(this));
|
||||
this.goalSelector.addGoal(2, new ShelterGoal(this));
|
||||
this.goalSelector.addGoal(3, new me.sashegdev.fabled_hearts.ai.FollowPlayerGoal(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void aiStep() {
|
||||
if (!level().isClientSide && !entityData.get(DATA_SLEEPING)) {
|
||||
boolean aheadLow = checkLowCeiling();
|
||||
if (aheadLow) {
|
||||
crouchTimer = Math.max(crouchTimer, 20);
|
||||
if (onGround()) {
|
||||
setPose(Pose.CROUCHING);
|
||||
}
|
||||
}
|
||||
}
|
||||
super.aiStep();
|
||||
tickDoors();
|
||||
if (!level().isClientSide) {
|
||||
tickServer();
|
||||
lastX = getX();
|
||||
@@ -132,28 +160,6 @@ public class EllieEntity extends Animal implements GeoEntity {
|
||||
}
|
||||
}
|
||||
|
||||
private void tickDoors() {
|
||||
if (lastOpenedDoor != null) {
|
||||
BlockState state = level().getBlockState(lastOpenedDoor);
|
||||
if (state.getBlock() instanceof DoorBlock && state.getValue(DoorBlock.OPEN)) {
|
||||
double dist = distanceToSqr(lastOpenedDoor.getX() + 0.5, lastOpenedDoor.getY(), lastOpenedDoor.getZ() + 0.5);
|
||||
if (dist > 0.5 * 0.5) {
|
||||
doorCloseTimer++;
|
||||
if (doorCloseTimer > 10) {
|
||||
level().setBlock(lastOpenedDoor, state.setValue(DoorBlock.OPEN, false), 3);
|
||||
lastOpenedDoor = null;
|
||||
doorCloseTimer = 0;
|
||||
}
|
||||
} else {
|
||||
doorCloseTimer = 0;
|
||||
}
|
||||
} else {
|
||||
lastOpenedDoor = null;
|
||||
doorCloseTimer = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isMoving() {
|
||||
boolean navBusy = navigation.isInProgress() && !navigation.isDone();
|
||||
boolean hasVelocity = getDeltaMovement().horizontalDistanceSqr() > 0.001;
|
||||
@@ -166,6 +172,13 @@ public class EllieEntity extends Animal implements GeoEntity {
|
||||
needsSleepRestore = false;
|
||||
}
|
||||
|
||||
if (entityData.get(DATA_SLEEPING) && bedPos != null) {
|
||||
BlockState bedState = level().getBlockState(bedPos);
|
||||
if (!(bedState.getBlock() instanceof BedBlock)) {
|
||||
wakeUp();
|
||||
}
|
||||
}
|
||||
|
||||
boolean isNight = level().isNight();
|
||||
boolean raining = level().isRainingAt(blockPosition());
|
||||
boolean lowCeiling = checkLowCeiling();
|
||||
@@ -185,10 +198,6 @@ public class EllieEntity extends Animal implements GeoEntity {
|
||||
entityData.set(DATA_FALL_TICKS, 0);
|
||||
}
|
||||
|
||||
if (!sleeping && moving && tickCount % 10 == 0) {
|
||||
openDoorInFront();
|
||||
}
|
||||
|
||||
boolean wasCrouching = getPose() == Pose.CROUCHING;
|
||||
|
||||
if (lowCeiling) {
|
||||
@@ -234,6 +243,38 @@ public class EllieEntity extends Animal implements GeoEntity {
|
||||
} else {
|
||||
ticksWithoutSleep = Math.max(0, ticksWithoutSleep - 10);
|
||||
}
|
||||
|
||||
int turnTimer = entityData.get(DATA_TURNING_TIMER);
|
||||
if (turnTimer > 0) {
|
||||
entityData.set(DATA_TURNING_TIMER, turnTimer - 1);
|
||||
if (turnTimer == 1) yawDeltaAccumulator = 0;
|
||||
} else if (!sleeping && !falling) {
|
||||
float yawDelta = Math.abs(getYRot() - prevYRot);
|
||||
yawDeltaAccumulator += yawDelta;
|
||||
if (yawDeltaAccumulator > 30 && !moving) {
|
||||
entityData.set(DATA_TURNING_TIMER, 17);
|
||||
yawDeltaAccumulator = 0;
|
||||
}
|
||||
}
|
||||
prevYRot = getYRot();
|
||||
|
||||
if (tickCount > 20) {
|
||||
int debugAnim = entityData.get(DATA_DEBUG_ANIM);
|
||||
if (debugAnim > 0) {
|
||||
debugAnimTimer--;
|
||||
if (debugAnimTimer <= 0) {
|
||||
entityData.set(DATA_DEBUG_ANIM, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int followTarget = entityData.get(DATA_FOLLOW_TARGET);
|
||||
if (followTarget > 0) {
|
||||
Entity target = level().getEntity(followTarget);
|
||||
if (!(target instanceof Player) || !target.isAlive() || target.distanceToSqr(this) > 64 * 64) {
|
||||
entityData.set(DATA_FOLLOW_TARGET, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateDebugBrainString() {
|
||||
@@ -251,6 +292,7 @@ public class EllieEntity extends Animal implements GeoEntity {
|
||||
sb.append("LowCeil:").append(entityData.get(DATA_UNDER_LOW_CEILING)).append("|");
|
||||
sb.append("Rel:").append(String.format("%.0f", relationshipPoints)).append("|");
|
||||
sb.append("CrouchT:").append(crouchTimer).append("|");
|
||||
sb.append("TurnT:").append(entityData.get(DATA_TURNING_TIMER)).append("|");
|
||||
if (navigation.isInProgress() && !navigation.isDone()) {
|
||||
sb.append("NavTo:").append(navigation.getTargetPos());
|
||||
} else {
|
||||
@@ -283,9 +325,7 @@ public class EllieEntity extends Animal implements GeoEntity {
|
||||
if (isSpaceLow(pos)) return true;
|
||||
if (isMoving() && navigation.isInProgress()) {
|
||||
Direction dir = getDirection();
|
||||
for (int i = 1; i <= 2; i++) {
|
||||
if (isSpaceLow(pos.relative(dir, i))) return true;
|
||||
}
|
||||
if (isSpaceLow(pos.relative(dir, 1))) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -301,20 +341,30 @@ public class EllieEntity extends Animal implements GeoEntity {
|
||||
|
||||
@Override
|
||||
public EntityDimensions getDimensions(Pose pose) {
|
||||
if (pose == Pose.SLEEPING) return EntityDimensions.fixed(0.6f, 0.6f);
|
||||
if (pose == Pose.SLEEPING) return EntityDimensions.fixed(0.15f, 0.15f);
|
||||
if (pose == Pose.CROUCHING) return EntityDimensions.fixed(0.6f, 1.0f);
|
||||
return super.getDimensions(pose);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getEyeHeight(Pose pose) {
|
||||
if (pose == Pose.STANDING && getPose() == Pose.SLEEPING) return 0.1f;
|
||||
return super.getEyeHeight(pose);
|
||||
}
|
||||
|
||||
public boolean occupyBed(BlockPos pos) {
|
||||
BlockState state = level().getBlockState(pos);
|
||||
if (state.getBlock() instanceof BedBlock) {
|
||||
if (state.getValue(BedBlock.OCCUPIED)) return false;
|
||||
Direction facing = state.getValue(BedBlock.FACING);
|
||||
BlockPos foot = state.getValue(BedBlock.PART) == BedPart.HEAD
|
||||
? pos.relative(state.getValue(BedBlock.FACING).getOpposite())
|
||||
? pos.relative(facing.getOpposite())
|
||||
: pos;
|
||||
level().setBlock(foot, state.setValue(BedBlock.OCCUPIED, true), 3);
|
||||
BlockPos head = foot.relative(state.getValue(BedBlock.FACING));
|
||||
BlockState footState = level().getBlockState(foot);
|
||||
if (footState.getBlock() instanceof BedBlock) {
|
||||
level().setBlock(foot, footState.setValue(BedBlock.OCCUPIED, true), 3);
|
||||
}
|
||||
BlockPos head = foot.relative(facing);
|
||||
BlockState headState = level().getBlockState(head);
|
||||
if (headState.getBlock() instanceof BedBlock) {
|
||||
level().setBlock(head, headState.setValue(BedBlock.OCCUPIED, true), 3);
|
||||
@@ -370,7 +420,11 @@ public class EllieEntity extends Animal implements GeoEntity {
|
||||
: pos.relative(facing);
|
||||
|
||||
setPose(Pose.SLEEPING);
|
||||
setPos(headPos.getX() + 0.5, headPos.getY() + 0.5625, headPos.getZ() + 0.5);
|
||||
BlockPos footPos = headPos.relative(facing.getOpposite());
|
||||
double footX = footPos.getX() + 0.5 - facing.getStepX() * 0.5;
|
||||
double footZ = footPos.getZ() + 0.5 - facing.getStepZ() * 0.5;
|
||||
setPos(footX, footPos.getY() + 0.6875, footZ);
|
||||
setSleepingPos(headPos);
|
||||
float yRot = facing.getOpposite().toYRot();
|
||||
setYRot(yRot);
|
||||
yRotO = yRot;
|
||||
@@ -387,45 +441,17 @@ public class EllieEntity extends Animal implements GeoEntity {
|
||||
setDeltaMovement(getDeltaMovement().add(0, 0.15, 0));
|
||||
}
|
||||
|
||||
public void openDoorInFront() {
|
||||
Path path = navigation.getPath();
|
||||
BlockPos entityPos = blockPosition();
|
||||
if (path != null) {
|
||||
for (int i = 0; i < Math.min(4, path.getNodeCount()); i++) {
|
||||
Node node = path.getNode(i);
|
||||
BlockPos checkPos = new BlockPos(node.x, node.y, node.z);
|
||||
if (checkPos.distSqr(entityPos) > 9) break;
|
||||
BlockState state = level().getBlockState(checkPos);
|
||||
if (state.getBlock() instanceof DoorBlock) {
|
||||
if (!state.getValue(DoorBlock.OPEN)) {
|
||||
level().setBlock(checkPos, state.setValue(DoorBlock.OPEN, true), 3);
|
||||
lastOpenedDoor = checkPos;
|
||||
doorCloseTimer = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 3; i++) {
|
||||
BlockPos checkPos = entityPos.relative(getDirection(), 2 + i);
|
||||
BlockState state = level().getBlockState(checkPos);
|
||||
if (state.getBlock() instanceof DoorBlock) {
|
||||
if (!state.getValue(DoorBlock.OPEN)) {
|
||||
level().setBlock(checkPos, state.setValue(DoorBlock.OPEN, true), 3);
|
||||
lastOpenedDoor = checkPos;
|
||||
doorCloseTimer = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
|
||||
controllers.add(new AnimationController<>(this, "main", 4, this::animationHandler));
|
||||
}
|
||||
|
||||
private <E extends GeoEntity> PlayState animationHandler(AnimationState<E> state) {
|
||||
int debugAnim = entityData.get(DATA_DEBUG_ANIM);
|
||||
if (debugAnim > 0 && debugAnim <= DEBUG_ANIMS.size()) {
|
||||
return state.setAndContinue(RawAnimation.begin().thenPlay(DEBUG_ANIMS.get(debugAnim - 1)));
|
||||
}
|
||||
|
||||
int idleAnim = entityData.get(DATA_IDLE_ANIM);
|
||||
if (idleAnim > 0) {
|
||||
String animName = switch (idleAnim) {
|
||||
@@ -466,6 +492,10 @@ public class EllieEntity extends Animal implements GeoEntity {
|
||||
if (fallTicks > 5) return RawAnimation.begin().thenPlay("fall");
|
||||
if (eating) return RawAnimation.begin().thenPlay("eat1");
|
||||
|
||||
if (entityData.get(DATA_TURNING_TIMER) > 0) {
|
||||
return RawAnimation.begin().thenPlay("turn").thenLoop(resolveTurnLoopName());
|
||||
}
|
||||
|
||||
if (tired) return moving
|
||||
? RawAnimation.begin().thenLoop("walkingsleepy")
|
||||
: RawAnimation.begin().thenLoop("idlesleepy");
|
||||
@@ -479,6 +509,19 @@ public class EllieEntity extends Animal implements GeoEntity {
|
||||
return RawAnimation.begin().thenLoop("idleins");
|
||||
}
|
||||
|
||||
private String resolveTurnLoopName() {
|
||||
boolean tired = entityData.get(DATA_TIRED);
|
||||
boolean inRain = entityData.get(DATA_IN_RAIN);
|
||||
boolean lowCeiling = entityData.get(DATA_UNDER_LOW_CEILING);
|
||||
boolean moving = entityData.get(DATA_MOVING);
|
||||
|
||||
if (tired) return moving ? "walkingsleepy" : "idlesleepy";
|
||||
if (inRain) return moving ? "walkingrain" : "idleconrain";
|
||||
if (lowCeiling) return moving ? "shiftwalking" : "shiftidle";
|
||||
if (moving) return "walkingsimple";
|
||||
return "idleins";
|
||||
}
|
||||
|
||||
@Override
|
||||
public AgeableMob getBreedOffspring(ServerLevel level, AgeableMob other) {
|
||||
return null;
|
||||
@@ -486,6 +529,31 @@ public class EllieEntity extends Animal implements GeoEntity {
|
||||
|
||||
@Override
|
||||
public InteractionResult mobInteract(Player player, InteractionHand hand) {
|
||||
ItemStack stack = player.getItemInHand(hand);
|
||||
boolean holdingStick = stack.is(Items.STICK);
|
||||
|
||||
if (holdingStick && player.isShiftKeyDown()) {
|
||||
if (!level().isClientSide) {
|
||||
int current = entityData.get(DATA_FOLLOW_TARGET);
|
||||
if (current == player.getId()) {
|
||||
entityData.set(DATA_FOLLOW_TARGET, 0);
|
||||
} else {
|
||||
entityData.set(DATA_FOLLOW_TARGET, player.getId());
|
||||
}
|
||||
}
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
if (holdingStick) {
|
||||
if (!level().isClientSide) {
|
||||
int current = entityData.get(DATA_DEBUG_ANIM);
|
||||
int next = (current % DEBUG_ANIMS.size()) + 1;
|
||||
entityData.set(DATA_DEBUG_ANIM, next);
|
||||
debugAnimTimer = 200;
|
||||
}
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
if (player.isShiftKeyDown()) return InteractionResult.PASS;
|
||||
|
||||
if (entityData.get(DATA_SLEEPING)) {
|
||||
@@ -503,6 +571,24 @@ public class EllieEntity extends Animal implements GeoEntity {
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hurt(DamageSource source, float amount) {
|
||||
if (source.getEntity() instanceof Player player) {
|
||||
ItemStack weapon = player.getMainHandItem();
|
||||
if (weapon.is(Items.STICK)) {
|
||||
if (!level().isClientSide) {
|
||||
int current = entityData.get(DATA_DEBUG_ANIM);
|
||||
if (current > 0) {
|
||||
entityData.set(DATA_DEBUG_ANIM, current);
|
||||
debugAnimTimer = 200;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return super.hurt(source, amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAdditionalSaveData(CompoundTag tag) {
|
||||
super.addAdditionalSaveData(tag);
|
||||
@@ -541,4 +627,7 @@ public class EllieEntity extends Animal implements GeoEntity {
|
||||
this.relationshipPoints = Math.min(100, Math.max(0, this.relationshipPoints + amount));
|
||||
}
|
||||
public int getTicksWithoutSleep() { return ticksWithoutSleep; }
|
||||
public int getFollowTargetId() { return entityData.get(DATA_FOLLOW_TARGET); }
|
||||
public boolean isFollowingPlayer() { return entityData.get(DATA_FOLLOW_TARGET) > 0; }
|
||||
public int getDebugAnim() { return entityData.get(DATA_DEBUG_ANIM); }
|
||||
}
|
||||
|
||||
@@ -2,13 +2,18 @@ package me.sashegdev.fabled_hearts.entity.ellie;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import com.mojang.math.Axis;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.Font;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.Pose;
|
||||
import net.minecraft.world.level.block.BedBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.joml.Matrix4f;
|
||||
import software.bernie.geckolib.renderer.GeoEntityRenderer;
|
||||
@@ -19,6 +24,31 @@ public class EllieRenderer extends GeoEntityRenderer<EllieEntity> {
|
||||
this.shadowRadius = 0.5f;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyRotations(EllieEntity entity, PoseStack poseStack, float tick, float yRot, float partialTick) {
|
||||
if (entity.getPose() == Pose.SLEEPING) {
|
||||
BlockPos bedPos = entity.getBedPos();
|
||||
if (bedPos != null) {
|
||||
BlockState state = entity.level().getBlockState(bedPos);
|
||||
if (state.getBlock() instanceof BedBlock) {
|
||||
Direction facing = state.getValue(BedBlock.FACING);
|
||||
float angle = switch (facing) {
|
||||
case SOUTH -> 90;
|
||||
case WEST -> 0;
|
||||
case NORTH -> 270;
|
||||
case EAST -> 180;
|
||||
default -> 180;
|
||||
};
|
||||
poseStack.mulPose(Axis.YP.rotationDegrees(angle));
|
||||
poseStack.mulPose(Axis.ZP.rotationDegrees(90));
|
||||
poseStack.mulPose(Axis.YP.rotationDegrees(270));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
super.applyRotations(entity, poseStack, tick, yRot, partialTick);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderType getRenderType(EllieEntity animatable, ResourceLocation texture,
|
||||
@Nullable MultiBufferSource bufferSource, float partialTick) {
|
||||
@@ -64,6 +94,7 @@ public class EllieRenderer extends GeoEntityRenderer<EllieEntity> {
|
||||
else if (line.startsWith("Rel:")) color = 0xFF69B4;
|
||||
else if (line.startsWith("CrouchT:")) color = 0xAAAAAA;
|
||||
else if (line.startsWith("NavTo:")) color = 0x55FFAA;
|
||||
else if (line.startsWith("TurnT:")) color = 0xFFAAFF;
|
||||
|
||||
int width = font.width(line);
|
||||
int x = -width / 2;
|
||||
|
||||
@@ -13899,97 +13899,53 @@
|
||||
"bones": {
|
||||
"root": {
|
||||
"rotation": {
|
||||
"vector": [90, 0, -180]
|
||||
"vector": [0, 0, 0]
|
||||
},
|
||||
"position": {
|
||||
"vector": [0, 9.1, 9]
|
||||
"vector": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
"torso": {
|
||||
"rotation": {
|
||||
"0.0833": {
|
||||
"vector": [0, 0, -5]
|
||||
},
|
||||
"1.0833": {
|
||||
"vector": [2, 0, -5]
|
||||
},
|
||||
"1.3333": {
|
||||
"vector": [2.25, 0, -5]
|
||||
},
|
||||
"2.0833": {
|
||||
"vector": [0, 0, -5]
|
||||
}
|
||||
"0.0833": { "vector": [0, 0, -5] },
|
||||
"1.0833": { "vector": [2, 0, -5] },
|
||||
"1.3333": { "vector": [2.25, 0, -5] },
|
||||
"2.0833": { "vector": [0, 0, -5] }
|
||||
},
|
||||
"position": {
|
||||
"0.0": {
|
||||
"vector": [0, -0.4, 0]
|
||||
},
|
||||
"1.0": {
|
||||
"vector": [0, -0.3, 0]
|
||||
},
|
||||
"1.25": {
|
||||
"vector": [0, -0.3, 0]
|
||||
},
|
||||
"2.0": {
|
||||
"vector": [0, -0.4, 0]
|
||||
}
|
||||
"0.0": { "vector": [0, -0.4, 0] },
|
||||
"1.0": { "vector": [0, -0.3, 0] },
|
||||
"1.25": { "vector": [0, -0.3, 0] },
|
||||
"2.0": { "vector": [0, -0.4, 0] }
|
||||
}
|
||||
},
|
||||
"head": {
|
||||
"rotation": {
|
||||
"0.0": {
|
||||
"vector": [0, 0, -5]
|
||||
},
|
||||
"0.1667": {
|
||||
"vector": [0, 0, -5]
|
||||
},
|
||||
"1.1667": {
|
||||
"vector": [-3, 0, -5]
|
||||
},
|
||||
"1.4167": {
|
||||
"vector": [-3, 0, -5]
|
||||
},
|
||||
"2.1667": {
|
||||
"vector": [0, 0, -5]
|
||||
}
|
||||
"0.0": { "vector": [0, 0, -5] },
|
||||
"0.1667": { "vector": [0, 0, -5] },
|
||||
"1.1667": { "vector": [-3, 0, -5] },
|
||||
"1.4167": { "vector": [-3, 0, -5] },
|
||||
"2.1667": { "vector": [0, 0, -5] }
|
||||
}
|
||||
},
|
||||
"righteye": {
|
||||
"position": {
|
||||
"vector": [0, 0, 1]
|
||||
}
|
||||
"position": { "vector": [0, 0, 1] }
|
||||
},
|
||||
"frown": {
|
||||
"position": {
|
||||
"vector": [0, 0, 1]
|
||||
}
|
||||
"position": { "vector": [0, 0, 1] }
|
||||
},
|
||||
"rightarm": {
|
||||
"rotation": {
|
||||
"0.0": {
|
||||
"vector": [0, 0, -10]
|
||||
},
|
||||
"0.2083": {
|
||||
"vector": [0, 0, -10]
|
||||
},
|
||||
"1.2083": {
|
||||
"vector": [2, 0, -10]
|
||||
},
|
||||
"1.4583": {
|
||||
"vector": [3, 0, -10]
|
||||
},
|
||||
"2.2083": {
|
||||
"vector": [0, 0, -10]
|
||||
}
|
||||
"0.0": { "vector": [0, 0, -10] },
|
||||
"0.2083": { "vector": [0, 0, -10] },
|
||||
"1.2083": { "vector": [2, 0, -10] },
|
||||
"1.4583": { "vector": [3, 0, -10] },
|
||||
"2.2083": { "vector": [0, 0, -10] }
|
||||
}
|
||||
},
|
||||
"rightleg": {
|
||||
"rotation": {
|
||||
"vector": [0, 0, 25]
|
||||
},
|
||||
"position": {
|
||||
"vector": [0, 0.7, 0]
|
||||
}
|
||||
"rotation": { "vector": [0, 0, 25] },
|
||||
"position": { "vector": [0, 0.7, 0] }
|
||||
},
|
||||
"openmouth]2": {
|
||||
"position": {
|
||||
|
||||
Reference in New Issue
Block a user