another kid update

This commit is contained in:
2026-02-24 15:20:19 +01:00
parent 680cddfc14
commit 915db8d815
3 changed files with 249 additions and 10 deletions

View File

@@ -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);
}
}
}

View File

@@ -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(