another kid update
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
package dev.tggamesyt.szar;
|
||||
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.entity.EntityDimensions;
|
||||
import net.minecraft.entity.EntityPose;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.ai.goal.*;
|
||||
import net.minecraft.entity.attribute.DefaultAttributeContainer;
|
||||
import net.minecraft.entity.attribute.EntityAttributes;
|
||||
@@ -13,7 +16,11 @@ import net.minecraft.entity.passive.VillagerEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import java.util.Optional;
|
||||
@@ -27,9 +34,11 @@ public class KidEntity extends PathAwareEntity {
|
||||
DataTracker.registerData(KidEntity.class, TrackedDataHandlerRegistry.OPTIONAL_UUID);
|
||||
private static final TrackedData<Optional<UUID>> PARENT_B =
|
||||
DataTracker.registerData(KidEntity.class, TrackedDataHandlerRegistry.OPTIONAL_UUID);
|
||||
|
||||
private static final TrackedData<Boolean> STAYING =
|
||||
DataTracker.registerData(KidEntity.class, TrackedDataHandlerRegistry.BOOLEAN);
|
||||
public static final int MAX_AGE = 360000; // 30 days * 10h
|
||||
|
||||
private BlockPos stayPos;
|
||||
private BlockPos lastSeenParentPos;
|
||||
public KidEntity(EntityType<KidEntity> type, World world) {
|
||||
super(type, world);
|
||||
}
|
||||
@@ -40,6 +49,7 @@ public class KidEntity extends PathAwareEntity {
|
||||
this.dataTracker.startTracking(AGE, 0);
|
||||
this.dataTracker.startTracking(PARENT_A, Optional.empty());
|
||||
this.dataTracker.startTracking(PARENT_B, Optional.empty());
|
||||
this.dataTracker.startTracking(STAYING, false);
|
||||
}
|
||||
|
||||
public float getAgeFraction() {
|
||||
@@ -49,12 +59,8 @@ public class KidEntity extends PathAwareEntity {
|
||||
@Override
|
||||
protected void initGoals() {
|
||||
this.goalSelector.add(0, new SwimGoal(this));
|
||||
this.goalSelector.add(1, new FleeEntityGoal<>(this, PlayerEntity.class, 6F, 1.2, 1.5));
|
||||
this.goalSelector.add(2, new WanderAroundFarGoal(this, 1.0));
|
||||
this.goalSelector.add(3, new LookAroundGoal(this));
|
||||
//this.goalSelector.add(4, new KidGoToBedGoal(this, 1.0));
|
||||
|
||||
this.targetSelector.add(1, new RevengeGoal(this));
|
||||
this.goalSelector.add(1, new KidParentBrainGoal(this, 1.3));
|
||||
this.goalSelector.add(2, new LookAroundGoal(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -65,6 +71,9 @@ public class KidEntity extends PathAwareEntity {
|
||||
int age = dataTracker.get(AGE);
|
||||
age++;
|
||||
dataTracker.set(AGE, age);
|
||||
EntityPose current = this.getPose();
|
||||
this.setPose(EntityPose.SITTING);
|
||||
this.setPose(current);
|
||||
|
||||
// Remove brutal killing; just let the kid “grow up” visually
|
||||
if (age > MAX_AGE) {
|
||||
@@ -114,6 +123,38 @@ public class KidEntity extends PathAwareEntity {
|
||||
this.dataTracker.set(PARENT_B, Optional.ofNullable(b));
|
||||
}
|
||||
|
||||
public PlayerEntity getNearbyParent() {
|
||||
if (this.getWorld().isClient) return null;
|
||||
|
||||
ServerWorld world = (ServerWorld) this.getWorld();
|
||||
|
||||
UUID a = getParentA();
|
||||
UUID b = getParentB();
|
||||
|
||||
PlayerEntity parentA = a != null ? world.getPlayerByUuid(a) : null;
|
||||
PlayerEntity parentB = b != null ? world.getPlayerByUuid(b) : null;
|
||||
|
||||
PlayerEntity closest = null;
|
||||
double closestDist = Double.MAX_VALUE;
|
||||
|
||||
for (PlayerEntity p : new PlayerEntity[]{parentA, parentB}) {
|
||||
if (p != null && p.isAlive() && !p.isSpectator()) {
|
||||
double dist = this.squaredDistanceTo(p);
|
||||
if (dist < closestDist) {
|
||||
closest = p;
|
||||
closestDist = dist;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Render distance check (32 blocks = 1024 sq)
|
||||
if (closest != null && closestDist <= 1024) {
|
||||
return closest;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeCustomDataToNbt(NbtCompound nbt) {
|
||||
super.writeCustomDataToNbt(nbt);
|
||||
@@ -139,4 +180,179 @@ public class KidEntity extends PathAwareEntity {
|
||||
|
||||
dataTracker.set(AGE, nbt.getInt("Age"));
|
||||
}
|
||||
@Override
|
||||
public ActionResult interactMob(PlayerEntity player, Hand hand) {
|
||||
if (!this.getWorld().isClient && hand == Hand.MAIN_HAND) {
|
||||
boolean staying = this.dataTracker.get(STAYING);
|
||||
|
||||
if (!staying) {
|
||||
player.sendMessage(Text.literal("Kid will now say here."));
|
||||
this.dataTracker.set(STAYING, true);
|
||||
this.stayPos = this.getBlockPos();
|
||||
} else {
|
||||
player.sendMessage(Text.literal("Kid will now follow parents."));
|
||||
this.dataTracker.set(STAYING, false);
|
||||
}
|
||||
}
|
||||
|
||||
return ActionResult.success(this.getWorld().isClient);
|
||||
}
|
||||
@Override
|
||||
public EntityDimensions getDimensions(EntityPose pose) {
|
||||
float ageFraction = getAgeFraction();
|
||||
float bodyScale = 0.3f + (1.0f - 0.3f) * ageFraction;
|
||||
|
||||
EntityDimensions base = super.getDimensions(pose);
|
||||
|
||||
return EntityDimensions.changing(
|
||||
base.width * bodyScale,
|
||||
base.height * bodyScale
|
||||
);
|
||||
}
|
||||
static class KidParentBrainGoal extends Goal {
|
||||
|
||||
private final KidEntity kid;
|
||||
private final double speed;
|
||||
|
||||
public KidParentBrainGoal(KidEntity kid, double speed) {
|
||||
this.kid = kid;
|
||||
this.speed = speed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canStart() {
|
||||
return true; // Always active brain
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
|
||||
if (kid.dataTracker.get(KidEntity.STAYING)) {
|
||||
handleStayMode();
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerEntity parent = kid.getNearbyParent();
|
||||
|
||||
if (parent != null) {
|
||||
kid.lastSeenParentPos = parent.getBlockPos();
|
||||
|
||||
double dist = kid.squaredDistanceTo(parent);
|
||||
|
||||
if (dist > 120) {
|
||||
// RUN to parent
|
||||
kid.getNavigation().startMovingTo(parent, speed * 1.5);
|
||||
} else if (dist < 36) { // 6 blocks
|
||||
kid.getNavigation().stop();
|
||||
} else {
|
||||
// Wander casually near parent
|
||||
if (kid.getNavigation().isIdle() && kid.getRandom().nextInt(80) == 0) {
|
||||
wanderNear(parent.getBlockPos(), 6);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// No visible parent → panic mode
|
||||
handlePanic();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleStayMode() {
|
||||
if (kid.stayPos == null) return;
|
||||
|
||||
if (kid.getNavigation().isIdle() && kid.getRandom().nextInt(60) == 0) {
|
||||
wanderNear(kid.stayPos, 5);
|
||||
}
|
||||
}
|
||||
|
||||
private void handlePanic() {
|
||||
|
||||
if (kid.lastSeenParentPos == null) return;
|
||||
|
||||
ServerWorld world = (ServerWorld) kid.getWorld();
|
||||
|
||||
double dist = kid.squaredDistanceTo(
|
||||
kid.lastSeenParentPos.getX(),
|
||||
kid.lastSeenParentPos.getY(),
|
||||
kid.lastSeenParentPos.getZ()
|
||||
);
|
||||
|
||||
// ===== MOVEMENT =====
|
||||
|
||||
// If far from last seen location, run there fast
|
||||
if (dist > 16) { // 4 blocks
|
||||
kid.getNavigation().startMovingTo(
|
||||
kid.lastSeenParentPos.getX(),
|
||||
kid.lastSeenParentPos.getY(),
|
||||
kid.lastSeenParentPos.getZ(),
|
||||
speed * 1.2
|
||||
);
|
||||
}
|
||||
// Once there → panic wander in 5 block radius
|
||||
else if (kid.getNavigation().isIdle() && kid.getRandom().nextInt(20) == 0) {
|
||||
|
||||
double panicX = kid.lastSeenParentPos.getX() + kid.getRandom().nextInt(11) - 5;
|
||||
double panicZ = kid.lastSeenParentPos.getZ() + kid.getRandom().nextInt(11) - 5;
|
||||
|
||||
kid.getNavigation().startMovingTo(panicX,
|
||||
kid.lastSeenParentPos.getY(),
|
||||
panicZ,
|
||||
speed);
|
||||
}
|
||||
|
||||
// ===== CRYING PARTICLES =====
|
||||
|
||||
if (kid.getRandom().nextInt(2) == 0) {
|
||||
|
||||
// Proper head height (accounts for body scaling)
|
||||
double headY = kid.getY() + kid.getStandingEyeHeight();
|
||||
|
||||
// Face direction
|
||||
float yawRad = (float) Math.toRadians(kid.getYaw());
|
||||
|
||||
// Offset to simulate left/right eyes
|
||||
double eyeOffsetX = Math.cos(yawRad) * 0.15;
|
||||
double eyeOffsetZ = Math.sin(yawRad) * 0.15;
|
||||
|
||||
// Left eye
|
||||
spawnTear(world,
|
||||
kid.getX() - eyeOffsetZ,
|
||||
headY,
|
||||
kid.getZ() + eyeOffsetX);
|
||||
|
||||
// Right eye
|
||||
spawnTear(world,
|
||||
kid.getX() + eyeOffsetZ,
|
||||
headY,
|
||||
kid.getZ() - eyeOffsetX);
|
||||
}
|
||||
}
|
||||
private void spawnTear(ServerWorld world, double x, double y, double z) {
|
||||
|
||||
// Downward falling motion
|
||||
double velX = (kid.getRandom().nextDouble() - 0.5) * 0.02;
|
||||
double velY = -0.12 - kid.getRandom().nextDouble() * 0.05;
|
||||
double velZ = (kid.getRandom().nextDouble() - 0.5) * 0.02;
|
||||
|
||||
world.spawnParticles(
|
||||
net.minecraft.particle.ParticleTypes.FALLING_WATER,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
1,
|
||||
velX,
|
||||
velY,
|
||||
velZ,
|
||||
0.0
|
||||
);
|
||||
}
|
||||
|
||||
private void wanderNear(BlockPos center, int radius) {
|
||||
double x = center.getX() + kid.getRandom().nextInt(radius * 2) - radius;
|
||||
double z = center.getZ() + kid.getRandom().nextInt(radius * 2) - radius;
|
||||
double y = center.getY();
|
||||
|
||||
kid.getNavigation().startMovingTo(x, y, z, 1.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,12 @@
|
||||
package dev.tggamesyt.szar;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.biome.v1.BiomeModifications;
|
||||
import net.fabricmc.fabric.api.biome.v1.BiomeSelectors;
|
||||
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||
import net.fabricmc.fabric.api.event.player.AttackEntityCallback;
|
||||
@@ -36,6 +39,7 @@ import net.minecraft.registry.entry.RegistryEntry;
|
||||
import net.minecraft.registry.tag.BiomeTags;
|
||||
import net.minecraft.registry.tag.BlockTags;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.sound.SoundCategory;
|
||||
@@ -64,11 +68,13 @@ import net.minecraft.world.gen.structure.StructureType;
|
||||
import net.minecraft.world.poi.PointOfInterestType;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.mojang.brigadier.builder.LiteralArgumentBuilder.literal;
|
||||
import static dev.tggamesyt.szar.ServerCosmetics.USERS;
|
||||
import static dev.tggamesyt.szar.ServerCosmetics.sync;
|
||||
|
||||
@@ -157,7 +163,7 @@ public class Szar implements ModInitializer {
|
||||
new Identifier(MOD_ID, "kid"),
|
||||
FabricEntityTypeBuilder.create(SpawnGroup.CREATURE,
|
||||
KidEntity::new) // ✅ matches EntityType<KidEntity>
|
||||
.dimensions(EntityDimensions.fixed(0.6F, 1.8F))
|
||||
.dimensions(EntityDimensions.changing(0.6F, 1.8F))
|
||||
.build()
|
||||
);
|
||||
public static final EntityType<EpsteinEntity> EpsteinEntityType =
|
||||
@@ -622,6 +628,23 @@ public class Szar implements ModInitializer {
|
||||
}
|
||||
}
|
||||
});
|
||||
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
|
||||
dispatcher.register(
|
||||
LiteralArgumentBuilder.<ServerCommandSource>literal("ny")
|
||||
.requires(context -> context.hasPermissionLevel(2))
|
||||
.executes(context -> {
|
||||
ServerCommandSource source = context.getSource();
|
||||
ServerWorld world = source.getWorld();
|
||||
|
||||
// Kill all KidEntity instances
|
||||
int count = world.getEntitiesByType(NyanEntityType, e -> true).size();
|
||||
world.getEntitiesByType(NyanEntityType, e -> true).forEach(e -> e.kill());
|
||||
|
||||
source.sendMessage(Text.literal("Killed " + count + " nyan cats."));
|
||||
return count;
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
public static final StructurePieceType TNT_OBELISK_PIECE =
|
||||
Registry.register(
|
||||
|
||||
Reference in New Issue
Block a user