From c19c9931bb26646137c47a6df34e7ea9dbc9a4a4 Mon Sep 17 00:00:00 2001 From: TGdoesCode Date: Fri, 27 Feb 2026 13:52:05 +0100 Subject: [PATCH] ah --- gradle.properties | 2 +- .../dev/tggamesyt/szar/IslamTerrorist.java | 198 +++++++++++++++++- .../dev/tggamesyt/szar/ObeliskCoreBlock.java | 20 +- .../szar/ObeliskCoreBlockEntity.java | 31 +++ src/main/java/dev/tggamesyt/szar/Szar.java | 62 +++++- 5 files changed, 305 insertions(+), 8 deletions(-) create mode 100644 src/main/java/dev/tggamesyt/szar/ObeliskCoreBlockEntity.java diff --git a/gradle.properties b/gradle.properties index e52c3bb..ab0b16e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ minecraft_version=1.20.1 yarn_mappings=1.20.1+build.10 loader_version=0.18.3 # Mod Properties -mod_version=26.2.26.1 +mod_version=26.2.27 maven_group=dev.tggamesyt archives_base_name=szar # Dependencies diff --git a/src/main/java/dev/tggamesyt/szar/IslamTerrorist.java b/src/main/java/dev/tggamesyt/szar/IslamTerrorist.java index fafbd08..2ec00fd 100644 --- a/src/main/java/dev/tggamesyt/szar/IslamTerrorist.java +++ b/src/main/java/dev/tggamesyt/szar/IslamTerrorist.java @@ -1,9 +1,7 @@ package dev.tggamesyt.szar; -import net.minecraft.entity.EntityType; -import net.minecraft.entity.EquipmentSlot; -import net.minecraft.entity.ItemEntity; -import net.minecraft.entity.TntEntity; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.entity.*; import net.minecraft.entity.ai.TargetPredicate; import net.minecraft.entity.ai.goal.Goal; import net.minecraft.entity.ai.goal.LookAroundGoal; @@ -15,13 +13,24 @@ import net.minecraft.entity.mob.MobEntity; import net.minecraft.entity.mob.PathAwareEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; +import net.minecraft.world.LocalDifficulty; +import net.minecraft.world.ServerWorldAccess; import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; import java.util.*; public class IslamTerrorist extends PathAwareEntity implements Arrestable{ - + private BlockPos targetCoreBlock = null; // the core block this mob is attacking + private Vec3d taxiDirection; + private Vec3d currentDirection = null; // direction plane is moving + private BlockPos taxiTarget; + private int flyStraightTicks = 0; + private int planeTaxiTicks = 0; public static boolean arrestable = false; private int BlowUpCooldown = 0; private int panicTicks = 0; @@ -56,6 +65,108 @@ public class IslamTerrorist extends PathAwareEntity implements Arrestable{ super.tick(); if (BlowUpCooldown > 0) BlowUpCooldown--; + + Entity vehicle = this.getVehicle(); + if (!(vehicle instanceof PlaneEntity plane) || targetCoreBlock == null) return; + + Vec3d vel = plane.getVelocity(); + + // ------------------------- + // TAXI PHASE: ground, random direction + // ------------------------- + if (planeTaxiTicks > 0) { + planeTaxiTicks--; + + if (taxiTarget != null) { + Vec3d toTarget = Vec3d.ofCenter(taxiTarget).subtract(plane.getPos()); + if (toTarget.length() > 0.5) { + Vec3d desired = toTarget.normalize().multiply(0.4); + plane.setVelocity(vel.lerp(desired, 0.1)); + } + } + + // small lift near end + if (planeTaxiTicks < 20) { + plane.setVelocity(plane.getVelocity().x, 0.08, plane.getVelocity().z); + } + + // Face movement + Vec3d look = plane.getVelocity().normalize(); + if (look.length() > 0) { + plane.setYaw((float) Math.toDegrees(Math.atan2(-look.x, look.z))); + plane.setPitch((float) -Math.toDegrees(Math.asin(look.y))); + } + + return; + } + + // ------------------------- + // FLY STRAIGHT PHASE + // ------------------------- + if (flyStraightTicks > 0) { + flyStraightTicks--; + + plane.setVelocity(currentDirection.x * 1.4, 0.25, currentDirection.z * 1.4); + + Vec3d look = plane.getVelocity().normalize(); + if (look.length() > 0) { + plane.setYaw((float) Math.toDegrees(Math.atan2(-look.x, look.z))); + plane.setPitch((float) -Math.toDegrees(Math.asin(look.y))); + } + + return; + } + + // ------------------------- + // HOMING PHASE + // ------------------------- + Vec3d target = Vec3d.ofCenter(targetCoreBlock); + Vec3d toTarget = target.subtract(plane.getPos()); + Vec3d desired = toTarget.normalize().multiply(1.8); + + // Add small upward lift if below target + if (plane.getY() < target.y - 10) { + desired = desired.add(0, 0.2, 0); + } + + // Smooth turning toward target + currentDirection = currentDirection.lerp(desired.normalize(), 0.03).normalize(); + + plane.setVelocity(currentDirection.multiply(1.8)); + + // Face movement + Vec3d look = plane.getVelocity().normalize(); + if (look.length() > 0) { + plane.setYaw((float) Math.toDegrees(Math.atan2(-look.x, look.z))); + plane.setPitch((float) -Math.toDegrees(Math.asin(look.y))); + } + + // ------------------------- + // IMPACT + // ------------------------- + if (!getWorld().isClient && + (plane.horizontalCollision || plane.verticalCollision)) { + + getWorld().createExplosion( + plane, + plane.getX(), + plane.getY(), + plane.getZ(), + 7.0f, + World.ExplosionSourceType.TNT + ); + + plane.discard(); + this.discard(); + + BlockEntity be = getWorld().getBlockEntity(targetCoreBlock); + if (be instanceof ObeliskCoreBlockEntity core) { + core.setHasPlaneMob(false); + core.markDirty(); + } + + targetCoreBlock = null; + } } // ================= VISIBILITY ================= @@ -96,6 +207,19 @@ public class IslamTerrorist extends PathAwareEntity implements Arrestable{ this.velocityDirty = true; } + @Override + public void onDeath(DamageSource source) { + super.onDeath(source); + + if (targetCoreBlock == null) return; + + BlockEntity be = getWorld().getBlockEntity(targetCoreBlock); + if (be instanceof ObeliskCoreBlockEntity core) { + core.setHasPlaneMob(false); + core.markDirty(); + } + } + // ================= DAMAGE ================= @@ -119,6 +243,70 @@ public class IslamTerrorist extends PathAwareEntity implements Arrestable{ } } + @Override + public EntityData initialize( + ServerWorldAccess worldAccess, + LocalDifficulty difficulty, + SpawnReason spawnReason, + @Nullable EntityData entityData, + @Nullable NbtCompound entityNbt + ) { + EntityData data = super.initialize(worldAccess, difficulty, spawnReason, entityData, entityNbt); + + if (!(worldAccess instanceof ServerWorld world)) return data; + + BlockPos corePos = findNearbyCoreBlock(this.getBlockPos(), 100); + if (corePos == null) return data; + + BlockEntity be = world.getBlockEntity(corePos); + if (!(be instanceof ObeliskCoreBlockEntity core)) return data; + + if (!core.hasPlaneMob() && world.random.nextInt(100) == 0) { + + PlaneEntity plane = new PlaneEntity(Szar.PLANE_ENTITY_TYPE, world); + plane.refreshPositionAndAngles(getX(), getY(), getZ(), getYaw(), getPitch()); + + world.spawnEntity(plane); + this.startRiding(plane, true); + + core.setHasPlaneMob(true); + core.markDirty(); + + this.targetCoreBlock = corePos; + + // Taxi + straight flight setup + this.planeTaxiTicks = 60; // 3 seconds ground taxi + this.flyStraightTicks = 40; // 2 seconds straight flight before homing + + // Random horizontal direction + float randomYaw = world.random.nextFloat() * 360f; + this.currentDirection = Vec3d.fromPolar(0, randomYaw).normalize(); + + // Taxi target 20 blocks ahead in random direction + this.taxiTarget = this.getBlockPos().add( + (int)(currentDirection.x * 20), + 0, + (int)(currentDirection.z * 20) + ); + } + + return data; + } + + private BlockPos findNearbyCoreBlock(BlockPos pos, int radius) { + for (int dx = -radius; dx <= radius; dx++) { + for (int dy = -radius; dy <= radius; dy++) { + for (int dz = -radius; dz <= radius; dz++) { + BlockPos check = pos.add(dx, dy, dz); + if (getWorld().getBlockState(check).getBlock() == Szar.OBELISK_CORE) { + return check; + } + } + } + } + return null; + } + // 🔴 Flee from only specific victim, hide behind others private static class FleeSpecificPlayerGoal extends Goal { private final IslamTerrorist mob; diff --git a/src/main/java/dev/tggamesyt/szar/ObeliskCoreBlock.java b/src/main/java/dev/tggamesyt/szar/ObeliskCoreBlock.java index b9851e3..664ef57 100644 --- a/src/main/java/dev/tggamesyt/szar/ObeliskCoreBlock.java +++ b/src/main/java/dev/tggamesyt/szar/ObeliskCoreBlock.java @@ -1,17 +1,28 @@ package dev.tggamesyt.szar; import net.minecraft.block.Block; +import net.minecraft.block.BlockEntityProvider; +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.world.ServerWorld; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraft.world.explosion.Explosion; +import org.jetbrains.annotations.Nullable; -public class ObeliskCoreBlock extends Block { +public class ObeliskCoreBlock extends Block implements BlockEntityProvider { public ObeliskCoreBlock(Settings settings) { super(settings); } + @Nullable + @Override + public ObeliskCoreBlockEntity createBlockEntity(BlockPos pos, BlockState state) { + return new ObeliskCoreBlockEntity(pos, state); + } + @Override public void onDestroyedByExplosion(World world, BlockPos pos, Explosion explosion) { super.onDestroyedByExplosion(world, pos, explosion); @@ -19,5 +30,12 @@ public class ObeliskCoreBlock extends Block { if (!(world instanceof ServerWorld serverWorld)) return; TwoTowersUtil.grantNearbyAdvancement(serverWorld, pos, 100); + + BlockEntity be = world.getBlockEntity(pos); + if (be instanceof ObeliskCoreBlockEntity core) { + core.setHasPlaneMob(false); // reset in case a plane was active + core.markDirty(); + } } } + diff --git a/src/main/java/dev/tggamesyt/szar/ObeliskCoreBlockEntity.java b/src/main/java/dev/tggamesyt/szar/ObeliskCoreBlockEntity.java new file mode 100644 index 0000000..e043155 --- /dev/null +++ b/src/main/java/dev/tggamesyt/szar/ObeliskCoreBlockEntity.java @@ -0,0 +1,31 @@ +package dev.tggamesyt.szar; + +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.util.math.BlockPos; + +public class ObeliskCoreBlockEntity extends BlockEntity { + + private boolean hasPlaneMob = false; + + public ObeliskCoreBlockEntity(BlockPos pos, BlockState state) { + super(Szar.OBELISK_CORE_ENTITY, pos, state); + } + + // NBT serialization + @Override + public void writeNbt(NbtCompound nbt) { + super.writeNbt(nbt); + nbt.putBoolean("hasPlaneMob", hasPlaneMob); + } + + @Override + public void readNbt(NbtCompound nbt) { + super.readNbt(nbt); + hasPlaneMob = nbt.getBoolean("hasPlaneMob"); + } + + public boolean hasPlaneMob() { return hasPlaneMob; } + public void setHasPlaneMob(boolean value) { hasPlaneMob = value; } +} diff --git a/src/main/java/dev/tggamesyt/szar/Szar.java b/src/main/java/dev/tggamesyt/szar/Szar.java index d761e49..26190c4 100644 --- a/src/main/java/dev/tggamesyt/szar/Szar.java +++ b/src/main/java/dev/tggamesyt/szar/Szar.java @@ -17,12 +17,15 @@ import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; +import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder; import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry; import net.fabricmc.fabric.api.object.builder.v1.entity.FabricEntityTypeBuilder; import net.fabricmc.fabric.api.object.builder.v1.trade.TradeOfferHelper; import net.fabricmc.fabric.api.object.builder.v1.world.poi.PointOfInterestHelper; import net.minecraft.advancement.Advancement; import net.minecraft.block.*; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.block.entity.BlockEntityType; import net.minecraft.entity.*; import net.minecraft.entity.damage.DamageType; import net.minecraft.entity.data.DataTracker; @@ -649,6 +652,26 @@ public class Szar implements ModInitializer { return count; }) ); + dispatcher.register( + LiteralArgumentBuilder.literal("getnearestobeliskcore") + .requires(context -> context.hasPermissionLevel(2)) + .executes(context -> { + ServerCommandSource source = context.getSource(); + ServerWorld world = source.getWorld(); + + assert source.getEntity() != null; + ObeliskCoreBlockEntity nearest = findNearestObelisk(world, source.getEntity().getBlockPos(), 100); + if (nearest != null) { + boolean hasPlane = nearest.hasPlaneMob(); + + source.sendMessage(Text.literal( + "HasPlane: " + hasPlane + )); + return 1; + } + return 0; + }) + ); }); Registry.register( Registries.ITEM, @@ -656,6 +679,36 @@ public class Szar implements ModInitializer { new BlockItem(OBELISK_CORE, new Item.Settings()) ); } + public static ObeliskCoreBlockEntity findNearestObelisk(ServerWorld world, BlockPos center, int radius) { + ObeliskCoreBlockEntity closest = null; + double closestDistance = Double.MAX_VALUE; + + BlockPos.Mutable mutable = new BlockPos.Mutable(); + + for (int x = -radius; x <= radius; x++) { + for (int y = -radius; y <= radius; y++) { + for (int z = -radius; z <= radius; z++) { + + mutable.set(center.getX() + x, + center.getY() + y, + center.getZ() + z); + + BlockEntity be = world.getBlockEntity(mutable); + + if (be instanceof ObeliskCoreBlockEntity obelisk) { + double distance = center.getSquaredDistance(mutable); + + if (distance < closestDistance) { + closestDistance = distance; + closest = obelisk; + } + } + } + } + } + + return closest; + } public static final Item CNDM = Registry.register( Registries.ITEM, new Identifier(MOD_ID, "cndm"), @@ -691,8 +744,15 @@ public class Szar implements ModInitializer { .copy(Blocks.DIRT) // soft block .strength(0.5f, 1.0f) // very easy to break, low blast resistance ) - ); + public static final BlockEntityType OBELISK_CORE_ENTITY = Registry.register( + Registries.BLOCK_ENTITY_TYPE, + new Identifier(MOD_ID, "obelisk_core"), + FabricBlockEntityTypeBuilder.create( + ObeliskCoreBlockEntity::new, + OBELISK_CORE // block(s) this BE is linked to + ).build(null) + );