Fix door stuck nudge, double door priority, shelter detection, and debug stick
This commit is contained in:
@@ -15,14 +15,16 @@ import java.util.EnumSet;
|
|||||||
public class EllieDoorInteractGoal extends Goal {
|
public class EllieDoorInteractGoal extends Goal {
|
||||||
private static final int CLOSE_DELAY = 25;
|
private static final int CLOSE_DELAY = 25;
|
||||||
private static final double CLOSE_DIST_SQ = 2.0 * 2.0;
|
private static final double CLOSE_DIST_SQ = 2.0 * 2.0;
|
||||||
private static final double WAYPOINT_REACH_DIST = 0.4;
|
private static final double STUCK_DELTA = 0.005;
|
||||||
|
|
||||||
private final EllieEntity ellie;
|
private final EllieEntity ellie;
|
||||||
private BlockPos doorPos;
|
private BlockPos doorPos;
|
||||||
private BlockPos pairedDoorPos;
|
private BlockPos pairedDoorPos;
|
||||||
private Vec3 passageCenter;
|
|
||||||
private boolean hasPassed;
|
private boolean hasPassed;
|
||||||
private int closeTimer;
|
private int closeTimer;
|
||||||
|
private Vec3 doorStuckPos;
|
||||||
|
private int doorStuckTicks;
|
||||||
|
private boolean stuckNudgeCw;
|
||||||
|
|
||||||
public EllieDoorInteractGoal(EllieEntity ellie) {
|
public EllieDoorInteractGoal(EllieEntity ellie) {
|
||||||
this.ellie = ellie;
|
this.ellie = ellie;
|
||||||
@@ -49,21 +51,13 @@ public class EllieDoorInteractGoal extends Goal {
|
|||||||
return;
|
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) {
|
if (!hasPassed) {
|
||||||
double distSq = ellie.distanceToSqr(Vec3.atCenterOf(doorPos));
|
double distSq = ellie.distanceToSqr(Vec3.atCenterOf(doorPos));
|
||||||
if (distSq > CLOSE_DIST_SQ) {
|
if (distSq > CLOSE_DIST_SQ) {
|
||||||
hasPassed = true;
|
hasPassed = true;
|
||||||
closeTimer = CLOSE_DELAY;
|
closeTimer = CLOSE_DELAY;
|
||||||
|
} else {
|
||||||
|
checkStuck();
|
||||||
}
|
}
|
||||||
} else if (--closeTimer <= 0) {
|
} else if (--closeTimer <= 0) {
|
||||||
closeDoor(doorPos);
|
closeDoor(doorPos);
|
||||||
@@ -93,11 +87,42 @@ public class EllieDoorInteractGoal extends Goal {
|
|||||||
|
|
||||||
hasPassed = false;
|
hasPassed = false;
|
||||||
closeTimer = 0;
|
closeTimer = 0;
|
||||||
passageCenter = calcPassageCenter();
|
|
||||||
ellie.getNavigation().moveTo(passageCenter.x, passageCenter.y, passageCenter.z, 0.6);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkStuck() {
|
||||||
|
Vec3 current = ellie.position();
|
||||||
|
if (doorStuckPos != null) {
|
||||||
|
if (current.distanceToSqr(doorStuckPos) < STUCK_DELTA) {
|
||||||
|
doorStuckTicks++;
|
||||||
|
if (doorStuckTicks > 40) {
|
||||||
|
nudgeDoor();
|
||||||
|
doorStuckTicks = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
doorStuckTicks = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
doorStuckPos = current;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void nudgeDoor() {
|
||||||
|
BlockState state = ellie.level().getBlockState(doorPos);
|
||||||
|
if (!(state.getBlock() instanceof DoorBlock)) return;
|
||||||
|
|
||||||
|
Direction facing = state.getValue(DoorBlock.FACING);
|
||||||
|
Direction nudgeDir = stuckNudgeCw
|
||||||
|
? facing.getClockWise()
|
||||||
|
: facing.getCounterClockWise();
|
||||||
|
stuckNudgeCw = !stuckNudgeCw;
|
||||||
|
|
||||||
|
ellie.setPos(
|
||||||
|
ellie.getX() + nudgeDir.getStepX() * 0.2,
|
||||||
|
ellie.getY(),
|
||||||
|
ellie.getZ() + nudgeDir.getStepZ() * 0.2
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private void openDoor(BlockPos pos, BlockState state) {
|
private void openDoor(BlockPos pos, BlockState state) {
|
||||||
if (state.getBlock() instanceof DoorBlock door && !state.getValue(DoorBlock.OPEN)) {
|
if (state.getBlock() instanceof DoorBlock door && !state.getValue(DoorBlock.OPEN)) {
|
||||||
door.setOpen(ellie, ellie.level(), state, pos, true);
|
door.setOpen(ellie, ellie.level(), state, pos, true);
|
||||||
@@ -115,22 +140,43 @@ public class EllieDoorInteractGoal extends Goal {
|
|||||||
Path path = ellie.getNavigation().getPath();
|
Path path = ellie.getNavigation().getPath();
|
||||||
if (path != null && !path.isDone()) {
|
if (path != null && !path.isDone()) {
|
||||||
BlockPos entityPos = ellie.blockPosition();
|
BlockPos entityPos = ellie.blockPosition();
|
||||||
for (int i = 0; i < Math.min(8, path.getNodeCount()); i++) {
|
for (int i = 0; i < Math.min(16, path.getNodeCount()); i++) {
|
||||||
Node node = path.getNode(i);
|
Node node = path.getNode(i);
|
||||||
if (node == null) continue;
|
if (node == null) continue;
|
||||||
BlockPos checkPos = new BlockPos(node.x, node.y, node.z);
|
BlockPos checkPos = new BlockPos(node.x, node.y, node.z);
|
||||||
if (checkPos.distSqr(entityPos) > 64) continue;
|
if (checkPos.distSqr(entityPos) > 64) continue;
|
||||||
if (checkForDoor(checkPos)) return checkPos;
|
BlockPos door = resolveDoor(checkPos);
|
||||||
if (checkForDoor(checkPos.above())) return checkPos.above();
|
if (door != null) return door;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BlockPos center = ellie.blockPosition();
|
BlockPos center = ellie.blockPosition();
|
||||||
for (int dx = -1; dx <= 1; dx++) {
|
BlockPos singleDoor = null;
|
||||||
for (int dz = -1; dz <= 1; dz++) {
|
for (int dx = -2; dx <= 2; dx++) {
|
||||||
BlockPos checkPos = center.offset(dx, 0, dz);
|
for (int dz = -2; dz <= 2; dz++) {
|
||||||
if (checkForDoor(checkPos)) return checkPos;
|
for (int dy = -1; dy <= 1; dy++) {
|
||||||
if (checkForDoor(checkPos.above())) return checkPos.above();
|
BlockPos checkPos = center.offset(dx, dy, dz);
|
||||||
|
if (!checkForDoor(checkPos)) continue;
|
||||||
|
BlockState state = ellie.level().getBlockState(checkPos);
|
||||||
|
if (findPairedDoor(checkPos, state) != null) {
|
||||||
|
return checkPos;
|
||||||
}
|
}
|
||||||
|
if (singleDoor == null) {
|
||||||
|
singleDoor = checkPos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return singleDoor;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BlockPos resolveDoor(BlockPos pos) {
|
||||||
|
if (checkForDoor(pos)) return pos;
|
||||||
|
if (checkForDoor(pos.above())) return pos.above();
|
||||||
|
if (checkForDoor(pos.below())) return pos.below();
|
||||||
|
for (Direction dir : Direction.Plane.HORIZONTAL) {
|
||||||
|
BlockPos adj = pos.relative(dir);
|
||||||
|
if (checkForDoor(adj)) return adj;
|
||||||
|
if (checkForDoor(adj.above())) return adj.above();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -155,19 +201,13 @@ public class EllieDoorInteractGoal extends Goal {
|
|||||||
return null;
|
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() {
|
private void clear() {
|
||||||
doorPos = null;
|
doorPos = null;
|
||||||
pairedDoorPos = null;
|
pairedDoorPos = null;
|
||||||
passageCenter = null;
|
|
||||||
hasPassed = false;
|
hasPassed = false;
|
||||||
closeTimer = 0;
|
closeTimer = 0;
|
||||||
|
doorStuckPos = null;
|
||||||
|
doorStuckTicks = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -14,9 +14,17 @@ public class EllieNodeEvaluator extends WalkNodeEvaluator {
|
|||||||
if (node != null) return node;
|
if (node != null) return node;
|
||||||
|
|
||||||
BlockPathTypes head1 = this.getCachedBlockType(this.mob, x, y + 1, z);
|
BlockPathTypes head1 = this.getCachedBlockType(this.mob, x, y + 1, z);
|
||||||
if (head1 == BlockPathTypes.BLOCKED) return null;
|
float head1Malus = this.mob.getPathfindingMalus(head1);
|
||||||
|
if (head1Malus < 0.0f) {
|
||||||
|
BlockPathTypes body = this.getCachedBlockType(this.mob, x, y, z);
|
||||||
|
BlockPathTypes below = this.getCachedBlockType(this.mob, x, y - 1, z);
|
||||||
|
if (this.mob.getPathfindingMalus(body) < 0.0f || this.mob.getPathfindingMalus(below) < 0.0f) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BlockPathTypes head2 = this.getCachedBlockType(this.mob, x, y + 2, z);
|
BlockPathTypes head2 = this.getCachedBlockType(this.mob, x, y + 2, z);
|
||||||
if (head2 != BlockPathTypes.BLOCKED) return null;
|
if (this.mob.getPathfindingMalus(head2) >= 0.0f) return null;
|
||||||
|
|
||||||
BlockPathTypes footType = this.getCachedBlockType(this.mob, x, y, z);
|
BlockPathTypes footType = this.getCachedBlockType(this.mob, x, y, z);
|
||||||
float costMalus = this.mob.getPathfindingMalus(footType);
|
float costMalus = this.mob.getPathfindingMalus(footType);
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ package me.sashegdev.fabled_hearts.ai;
|
|||||||
import me.sashegdev.fabled_hearts.entity.ellie.EllieEntity;
|
import me.sashegdev.fabled_hearts.entity.ellie.EllieEntity;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.world.entity.ai.goal.Goal;
|
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 net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
@@ -40,10 +38,11 @@ public class ShelterGoal extends Goal {
|
|||||||
@Override
|
@Override
|
||||||
public void tick() {
|
public void tick() {
|
||||||
if (shelterPos == null) return;
|
if (shelterPos == null) return;
|
||||||
if (ellie.distanceToSqr(Vec3.atCenterOf(shelterPos)) < REACH_DIST_SQR) {
|
Vec3 target = new Vec3(shelterPos.getX() + 0.5, shelterPos.getY(), shelterPos.getZ() + 0.5);
|
||||||
|
if (ellie.distanceToSqr(target) < REACH_DIST_SQR) {
|
||||||
ellie.getNavigation().stop();
|
ellie.getNavigation().stop();
|
||||||
} else if (ellie.getNavigation().isDone()) {
|
} else if (ellie.getNavigation().isDone()) {
|
||||||
ellie.getNavigation().moveTo(shelterPos.getX() + 0.5, shelterPos.getY(), shelterPos.getZ() + 0.5, 0.6);
|
ellie.getNavigation().moveTo(target.x, target.y, target.z, 0.6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,16 +58,6 @@ public class ShelterGoal extends Goal {
|
|||||||
shelterPos = null;
|
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() {
|
private BlockPos findShelter() {
|
||||||
BlockPos entityPos = ellie.blockPosition();
|
BlockPos entityPos = ellie.blockPosition();
|
||||||
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
|
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
|
||||||
@@ -77,14 +66,18 @@ public class ShelterGoal extends Goal {
|
|||||||
|
|
||||||
for (int x = -SEARCH_RADIUS; x <= SEARCH_RADIUS; x++) {
|
for (int x = -SEARCH_RADIUS; x <= SEARCH_RADIUS; x++) {
|
||||||
for (int z = -SEARCH_RADIUS; z <= SEARCH_RADIUS; z++) {
|
for (int z = -SEARCH_RADIUS; z <= SEARCH_RADIUS; z++) {
|
||||||
mutable.set(entityPos.getX() + x, entityPos.getY(), entityPos.getZ() + z);
|
for (int dy = 2; dy >= -4; dy--) {
|
||||||
int topY = ellie.level().getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, mutable).getY();
|
mutable.set(entityPos.getX() + x, entityPos.getY() + dy, entityPos.getZ() + z);
|
||||||
mutable.setY(topY);
|
BlockPos standPos = mutable.above();
|
||||||
if (hasShelter(mutable)) {
|
if (!ellie.level().isRainingAt(standPos)
|
||||||
|
&& ellie.level().getBlockState(standPos).isAir()
|
||||||
|
&& !ellie.level().getBlockState(mutable).isAir()) {
|
||||||
double dist = entityPos.distSqr(mutable);
|
double dist = entityPos.distSqr(mutable);
|
||||||
if (dist < nearestDist) {
|
if (dist < nearestDist) {
|
||||||
nearestDist = dist;
|
nearestDist = dist;
|
||||||
nearest = mutable.immutable();
|
nearest = standPos;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,11 @@ public class EllieEntity extends Animal implements GeoEntity {
|
|||||||
SynchedEntityData.defineId(EllieEntity.class, EntityDataSerializers.INT);
|
SynchedEntityData.defineId(EllieEntity.class, EntityDataSerializers.INT);
|
||||||
|
|
||||||
private static final List<String> DEBUG_ANIMS = List.of(
|
private static final List<String> DEBUG_ANIMS = List.of(
|
||||||
"idle1", "idle2", "idle3", "turn", "eat1", "fall"
|
"idle1", "idle2", "idle3", "turn", "eat1", "fall",
|
||||||
|
"sleep", "walkingsleepy", "idlesleepy",
|
||||||
|
"walkingrain", "idleconrain",
|
||||||
|
"shiftwalking", "shiftidle",
|
||||||
|
"walkingsimple", "idleins"
|
||||||
);
|
);
|
||||||
|
|
||||||
private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this);
|
private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this);
|
||||||
@@ -423,7 +427,7 @@ public class EllieEntity extends Animal implements GeoEntity {
|
|||||||
BlockPos footPos = headPos.relative(facing.getOpposite());
|
BlockPos footPos = headPos.relative(facing.getOpposite());
|
||||||
double footX = footPos.getX() + 0.5 - facing.getStepX() * 0.5;
|
double footX = footPos.getX() + 0.5 - facing.getStepX() * 0.5;
|
||||||
double footZ = footPos.getZ() + 0.5 - facing.getStepZ() * 0.5;
|
double footZ = footPos.getZ() + 0.5 - facing.getStepZ() * 0.5;
|
||||||
setPos(footX, footPos.getY() + 0.6875, footZ);
|
setPos(footX, footPos.getY() + 1.0625, footZ);
|
||||||
setSleepingPos(headPos);
|
setSleepingPos(headPos);
|
||||||
float yRot = facing.getOpposite().toYRot();
|
float yRot = facing.getOpposite().toYRot();
|
||||||
setYRot(yRot);
|
setYRot(yRot);
|
||||||
@@ -530,7 +534,7 @@ public class EllieEntity extends Animal implements GeoEntity {
|
|||||||
@Override
|
@Override
|
||||||
public InteractionResult mobInteract(Player player, InteractionHand hand) {
|
public InteractionResult mobInteract(Player player, InteractionHand hand) {
|
||||||
ItemStack stack = player.getItemInHand(hand);
|
ItemStack stack = player.getItemInHand(hand);
|
||||||
boolean holdingStick = stack.is(Items.STICK);
|
boolean holdingStick = stack.is(Items.DEBUG_STICK);
|
||||||
|
|
||||||
if (holdingStick && player.isShiftKeyDown()) {
|
if (holdingStick && player.isShiftKeyDown()) {
|
||||||
if (!level().isClientSide) {
|
if (!level().isClientSide) {
|
||||||
@@ -547,7 +551,7 @@ public class EllieEntity extends Animal implements GeoEntity {
|
|||||||
if (holdingStick) {
|
if (holdingStick) {
|
||||||
if (!level().isClientSide) {
|
if (!level().isClientSide) {
|
||||||
int current = entityData.get(DATA_DEBUG_ANIM);
|
int current = entityData.get(DATA_DEBUG_ANIM);
|
||||||
int next = (current % DEBUG_ANIMS.size()) + 1;
|
int next = (current + 1) % (DEBUG_ANIMS.size() + 1);
|
||||||
entityData.set(DATA_DEBUG_ANIM, next);
|
entityData.set(DATA_DEBUG_ANIM, next);
|
||||||
debugAnimTimer = 200;
|
debugAnimTimer = 200;
|
||||||
}
|
}
|
||||||
@@ -575,7 +579,7 @@ public class EllieEntity extends Animal implements GeoEntity {
|
|||||||
public boolean hurt(DamageSource source, float amount) {
|
public boolean hurt(DamageSource source, float amount) {
|
||||||
if (source.getEntity() instanceof Player player) {
|
if (source.getEntity() instanceof Player player) {
|
||||||
ItemStack weapon = player.getMainHandItem();
|
ItemStack weapon = player.getMainHandItem();
|
||||||
if (weapon.is(Items.STICK)) {
|
if (weapon.is(Items.DEBUG_STICK)) {
|
||||||
if (!level().isClientSide) {
|
if (!level().isClientSide) {
|
||||||
int current = entityData.get(DATA_DEBUG_ANIM);
|
int current = entityData.get(DATA_DEBUG_ANIM);
|
||||||
if (current > 0) {
|
if (current > 0) {
|
||||||
|
|||||||
@@ -13899,53 +13899,97 @@
|
|||||||
"bones": {
|
"bones": {
|
||||||
"root": {
|
"root": {
|
||||||
"rotation": {
|
"rotation": {
|
||||||
"vector": [0, 0, 0]
|
"vector": [90, 0, -180]
|
||||||
},
|
},
|
||||||
"position": {
|
"position": {
|
||||||
"vector": [0, 0, 0]
|
"vector": [0, 9.1, 9]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"torso": {
|
"torso": {
|
||||||
"rotation": {
|
"rotation": {
|
||||||
"0.0833": { "vector": [0, 0, -5] },
|
"0.0833": {
|
||||||
"1.0833": { "vector": [2, 0, -5] },
|
"vector": [0, 0, -5]
|
||||||
"1.3333": { "vector": [2.25, 0, -5] },
|
},
|
||||||
"2.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": {
|
"position": {
|
||||||
"0.0": { "vector": [0, -0.4, 0] },
|
"0.0": {
|
||||||
"1.0": { "vector": [0, -0.3, 0] },
|
"vector": [0, -0.4, 0]
|
||||||
"1.25": { "vector": [0, -0.3, 0] },
|
},
|
||||||
"2.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": {
|
"head": {
|
||||||
"rotation": {
|
"rotation": {
|
||||||
"0.0": { "vector": [0, 0, -5] },
|
"0.0": {
|
||||||
"0.1667": { "vector": [0, 0, -5] },
|
"vector": [0, 0, -5]
|
||||||
"1.1667": { "vector": [-3, 0, -5] },
|
},
|
||||||
"1.4167": { "vector": [-3, 0, -5] },
|
"0.1667": {
|
||||||
"2.1667": { "vector": [0, 0, -5] }
|
"vector": [0, 0, -5]
|
||||||
|
},
|
||||||
|
"1.1667": {
|
||||||
|
"vector": [-3, 0, -5]
|
||||||
|
},
|
||||||
|
"1.4167": {
|
||||||
|
"vector": [-3, 0, -5]
|
||||||
|
},
|
||||||
|
"2.1667": {
|
||||||
|
"vector": [0, 0, -5]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"righteye": {
|
"righteye": {
|
||||||
"position": { "vector": [0, 0, 1] }
|
"position": {
|
||||||
|
"vector": [0, 0, 1]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"frown": {
|
"frown": {
|
||||||
"position": { "vector": [0, 0, 1] }
|
"position": {
|
||||||
|
"vector": [0, 0, 1]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"rightarm": {
|
"rightarm": {
|
||||||
"rotation": {
|
"rotation": {
|
||||||
"0.0": { "vector": [0, 0, -10] },
|
"0.0": {
|
||||||
"0.2083": { "vector": [0, 0, -10] },
|
"vector": [0, 0, -10]
|
||||||
"1.2083": { "vector": [2, 0, -10] },
|
},
|
||||||
"1.4583": { "vector": [3, 0, -10] },
|
"0.2083": {
|
||||||
"2.2083": { "vector": [0, 0, -10] }
|
"vector": [0, 0, -10]
|
||||||
|
},
|
||||||
|
"1.2083": {
|
||||||
|
"vector": [2, 0, -10]
|
||||||
|
},
|
||||||
|
"1.4583": {
|
||||||
|
"vector": [3, 0, -10]
|
||||||
|
},
|
||||||
|
"2.2083": {
|
||||||
|
"vector": [0, 0, -10]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rightleg": {
|
"rightleg": {
|
||||||
"rotation": { "vector": [0, 0, 25] },
|
"rotation": {
|
||||||
"position": { "vector": [0, 0.7, 0] }
|
"vector": [0, 0, 25]
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"vector": [0, 0.7, 0]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"openmouth]2": {
|
"openmouth]2": {
|
||||||
"position": {
|
"position": {
|
||||||
@@ -13985,19 +14029,19 @@
|
|||||||
"leftarm": {
|
"leftarm": {
|
||||||
"rotation": {
|
"rotation": {
|
||||||
"0.0": {
|
"0.0": {
|
||||||
"vector": [0, -82.5, -80]
|
"vector": [-17.1045, 0.5398, 22.7077]
|
||||||
},
|
},
|
||||||
"0.2083": {
|
"0.2083": {
|
||||||
"vector": [0, -82.5, -80]
|
"vector": [-17.1045, 0.5398, 22.7077]
|
||||||
},
|
},
|
||||||
"1.2083": {
|
"1.2083": {
|
||||||
"vector": [18.3312, -82.0966, -98.4951]
|
"vector": [-14.6045, 0.5398, 22.7077]
|
||||||
},
|
},
|
||||||
"1.4583": {
|
"1.4583": {
|
||||||
"vector": [24.8777, -81.7278, -105.1071]
|
"vector": [-14.6045, 0.5398, 22.7077]
|
||||||
},
|
},
|
||||||
"2.2083": {
|
"2.2083": {
|
||||||
"vector": [0, -82.5, -80]
|
"vector": [-17.1045, 0.5398, 22.7077]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"position": {
|
"position": {
|
||||||
@@ -14007,6 +14051,12 @@
|
|||||||
"0.2083": {
|
"0.2083": {
|
||||||
"vector": [-1, 0, 0]
|
"vector": [-1, 0, 0]
|
||||||
},
|
},
|
||||||
|
"1.2083": {
|
||||||
|
"vector": [-1, 0, 0]
|
||||||
|
},
|
||||||
|
"1.4583": {
|
||||||
|
"vector": [-1, 0, 0]
|
||||||
|
},
|
||||||
"2.2083": {
|
"2.2083": {
|
||||||
"vector": [-1, 0, 0]
|
"vector": [-1, 0, 0]
|
||||||
}
|
}
|
||||||
@@ -14014,17 +14064,31 @@
|
|||||||
},
|
},
|
||||||
"loverleftarm": {
|
"loverleftarm": {
|
||||||
"rotation": {
|
"rotation": {
|
||||||
"vector": [0, 0, 12.5]
|
"0.0": {
|
||||||
|
"vector": [0, 0, 85]
|
||||||
|
},
|
||||||
|
"0.3333": {
|
||||||
|
"vector": [0, 0, 85]
|
||||||
|
},
|
||||||
|
"1.3333": {
|
||||||
|
"vector": [0, 0, 87.5]
|
||||||
|
},
|
||||||
|
"1.5833": {
|
||||||
|
"vector": [0, 0, 87.5]
|
||||||
|
},
|
||||||
|
"2.25": {
|
||||||
|
"vector": [0, 0, 85]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"leftleg": {
|
"leftleg": {
|
||||||
"rotation": {
|
"rotation": {
|
||||||
"vector": [-30, 0, 0]
|
"vector": [-15, 0, 0]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"loverleg_L": {
|
"loverleg_L": {
|
||||||
"rotation": {
|
"rotation": {
|
||||||
"vector": [70, 0, 0]
|
"vector": [47.5, 0, 0]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"closed_L": {
|
"closed_L": {
|
||||||
@@ -14036,6 +14100,14 @@
|
|||||||
"position": {
|
"position": {
|
||||||
"vector": [0, 0, 1]
|
"vector": [0, 0, 1]
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"clothleg_lower_L": {
|
||||||
|
"rotation": {
|
||||||
|
"vector": [42.5, 0, 0]
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"vector": [0, -0.5, -0.3]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user