another kid update
This commit is contained in:
@@ -6,7 +6,7 @@ minecraft_version=1.20.1
|
|||||||
yarn_mappings=1.20.1+build.10
|
yarn_mappings=1.20.1+build.10
|
||||||
loader_version=0.18.3
|
loader_version=0.18.3
|
||||||
# Mod Properties
|
# Mod Properties
|
||||||
mod_version=26.2.23.1
|
mod_version=26.2.24
|
||||||
maven_group=dev.tggamesyt
|
maven_group=dev.tggamesyt
|
||||||
archives_base_name=szar
|
archives_base_name=szar
|
||||||
# Dependencies
|
# Dependencies
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
package dev.tggamesyt.szar;
|
package dev.tggamesyt.szar;
|
||||||
|
|
||||||
import net.minecraft.block.Blocks;
|
import net.minecraft.block.Blocks;
|
||||||
|
import net.minecraft.entity.EntityDimensions;
|
||||||
|
import net.minecraft.entity.EntityPose;
|
||||||
import net.minecraft.entity.EntityType;
|
import net.minecraft.entity.EntityType;
|
||||||
|
import net.minecraft.entity.LivingEntity;
|
||||||
import net.minecraft.entity.ai.goal.*;
|
import net.minecraft.entity.ai.goal.*;
|
||||||
import net.minecraft.entity.attribute.DefaultAttributeContainer;
|
import net.minecraft.entity.attribute.DefaultAttributeContainer;
|
||||||
import net.minecraft.entity.attribute.EntityAttributes;
|
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.entity.player.PlayerEntity;
|
||||||
import net.minecraft.nbt.NbtCompound;
|
import net.minecraft.nbt.NbtCompound;
|
||||||
import net.minecraft.server.world.ServerWorld;
|
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.BlockPos;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@@ -27,9 +34,11 @@ public class KidEntity extends PathAwareEntity {
|
|||||||
DataTracker.registerData(KidEntity.class, TrackedDataHandlerRegistry.OPTIONAL_UUID);
|
DataTracker.registerData(KidEntity.class, TrackedDataHandlerRegistry.OPTIONAL_UUID);
|
||||||
private static final TrackedData<Optional<UUID>> PARENT_B =
|
private static final TrackedData<Optional<UUID>> PARENT_B =
|
||||||
DataTracker.registerData(KidEntity.class, TrackedDataHandlerRegistry.OPTIONAL_UUID);
|
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
|
public static final int MAX_AGE = 360000; // 30 days * 10h
|
||||||
|
private BlockPos stayPos;
|
||||||
|
private BlockPos lastSeenParentPos;
|
||||||
public KidEntity(EntityType<KidEntity> type, World world) {
|
public KidEntity(EntityType<KidEntity> type, World world) {
|
||||||
super(type, world);
|
super(type, world);
|
||||||
}
|
}
|
||||||
@@ -40,6 +49,7 @@ public class KidEntity extends PathAwareEntity {
|
|||||||
this.dataTracker.startTracking(AGE, 0);
|
this.dataTracker.startTracking(AGE, 0);
|
||||||
this.dataTracker.startTracking(PARENT_A, Optional.empty());
|
this.dataTracker.startTracking(PARENT_A, Optional.empty());
|
||||||
this.dataTracker.startTracking(PARENT_B, Optional.empty());
|
this.dataTracker.startTracking(PARENT_B, Optional.empty());
|
||||||
|
this.dataTracker.startTracking(STAYING, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getAgeFraction() {
|
public float getAgeFraction() {
|
||||||
@@ -49,12 +59,8 @@ public class KidEntity extends PathAwareEntity {
|
|||||||
@Override
|
@Override
|
||||||
protected void initGoals() {
|
protected void initGoals() {
|
||||||
this.goalSelector.add(0, new SwimGoal(this));
|
this.goalSelector.add(0, new SwimGoal(this));
|
||||||
this.goalSelector.add(1, new FleeEntityGoal<>(this, PlayerEntity.class, 6F, 1.2, 1.5));
|
this.goalSelector.add(1, new KidParentBrainGoal(this, 1.3));
|
||||||
this.goalSelector.add(2, new WanderAroundFarGoal(this, 1.0));
|
this.goalSelector.add(2, new LookAroundGoal(this));
|
||||||
this.goalSelector.add(3, new LookAroundGoal(this));
|
|
||||||
//this.goalSelector.add(4, new KidGoToBedGoal(this, 1.0));
|
|
||||||
|
|
||||||
this.targetSelector.add(1, new RevengeGoal(this));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -65,6 +71,9 @@ public class KidEntity extends PathAwareEntity {
|
|||||||
int age = dataTracker.get(AGE);
|
int age = dataTracker.get(AGE);
|
||||||
age++;
|
age++;
|
||||||
dataTracker.set(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
|
// Remove brutal killing; just let the kid “grow up” visually
|
||||||
if (age > MAX_AGE) {
|
if (age > MAX_AGE) {
|
||||||
@@ -114,6 +123,38 @@ public class KidEntity extends PathAwareEntity {
|
|||||||
this.dataTracker.set(PARENT_B, Optional.ofNullable(b));
|
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
|
@Override
|
||||||
public void writeCustomDataToNbt(NbtCompound nbt) {
|
public void writeCustomDataToNbt(NbtCompound nbt) {
|
||||||
super.writeCustomDataToNbt(nbt);
|
super.writeCustomDataToNbt(nbt);
|
||||||
@@ -139,4 +180,179 @@ public class KidEntity extends PathAwareEntity {
|
|||||||
|
|
||||||
dataTracker.set(AGE, nbt.getInt("Age"));
|
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;
|
package dev.tggamesyt.szar;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
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.api.ModInitializer;
|
||||||
import net.fabricmc.fabric.api.biome.v1.BiomeModifications;
|
import net.fabricmc.fabric.api.biome.v1.BiomeModifications;
|
||||||
import net.fabricmc.fabric.api.biome.v1.BiomeSelectors;
|
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.ServerLifecycleEvents;
|
||||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||||
import net.fabricmc.fabric.api.event.player.AttackEntityCallback;
|
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.BiomeTags;
|
||||||
import net.minecraft.registry.tag.BlockTags;
|
import net.minecraft.registry.tag.BlockTags;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.command.ServerCommandSource;
|
||||||
import net.minecraft.server.network.ServerPlayerEntity;
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
import net.minecraft.server.world.ServerWorld;
|
import net.minecraft.server.world.ServerWorld;
|
||||||
import net.minecraft.sound.SoundCategory;
|
import net.minecraft.sound.SoundCategory;
|
||||||
@@ -64,11 +68,13 @@ import net.minecraft.world.gen.structure.StructureType;
|
|||||||
import net.minecraft.world.poi.PointOfInterestType;
|
import net.minecraft.world.poi.PointOfInterestType;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.jetbrains.annotations.UnknownNullability;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.regex.Pattern;
|
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.USERS;
|
||||||
import static dev.tggamesyt.szar.ServerCosmetics.sync;
|
import static dev.tggamesyt.szar.ServerCosmetics.sync;
|
||||||
|
|
||||||
@@ -157,7 +163,7 @@ public class Szar implements ModInitializer {
|
|||||||
new Identifier(MOD_ID, "kid"),
|
new Identifier(MOD_ID, "kid"),
|
||||||
FabricEntityTypeBuilder.create(SpawnGroup.CREATURE,
|
FabricEntityTypeBuilder.create(SpawnGroup.CREATURE,
|
||||||
KidEntity::new) // ✅ matches EntityType<KidEntity>
|
KidEntity::new) // ✅ matches EntityType<KidEntity>
|
||||||
.dimensions(EntityDimensions.fixed(0.6F, 1.8F))
|
.dimensions(EntityDimensions.changing(0.6F, 1.8F))
|
||||||
.build()
|
.build()
|
||||||
);
|
);
|
||||||
public static final EntityType<EpsteinEntity> EpsteinEntityType =
|
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 =
|
public static final StructurePieceType TNT_OBELISK_PIECE =
|
||||||
Registry.register(
|
Registry.register(
|
||||||
|
|||||||
Reference in New Issue
Block a user