time dilation and contraction effects, various fixes

This commit is contained in:
craisinlord committed 2026-09-09 09:37:55 -05:00
1 parent 68eba61022
commit 89d41dd7e1
192 files changed
+2962 -1981

No files matched your search

@@ -550,6 +550,7 @@ public final class AntarchySettings {
private static double queenManticoreSummonRange = 24.0D;
private static double queenBeamDamage = 45.0D;
private static double queenBeamRange = 100.0D;
private static double queenBeamMinimumRange = 22.0D;
private static int queenBeamDurationTicks = 30;
private static int queenBeamWindupTicks = 20;
private static int queenBeamTravelTicks = 12;
@@ -559,6 +560,7 @@ public final class AntarchySettings {
private static int queenBeamTerrainCap = 192;
private static double kingBeamDamage = 50.0D;
private static double kingBeamRange = 100.0D;
private static double kingBeamMinimumRange = 32.0D;
private static int kingBeamDurationTicks = 30;
private static int kingBeamWindupTicks = 20;
private static int kingBeamTravelTicks = 12;
@@ -567,6 +569,11 @@ public final class AntarchySettings {
private static double kingBeamTerrainRadius = 5.0D;
private static int kingBeamTerrainCap = 192;
private static int royalDecreeCooldownTicks = 1200;
private static int kingRoyalMusterCooldownTicks = 500;
private static int kingRoyalMusterWindupTicks = 30;
private static int kingRoyalMusterDurationTicks = 600;
private static double kingRoyalMusterRadius = 32.0D;
private static int kingRoyalMusterCap = 12;
private static double jerryInfantHealth = 20.0D;
private static double jerryInfantAttackDamage = 2.0D;
private static double jerryMatureHealth = 40.0D;
@@ -2887,6 +2894,8 @@ public final class AntarchySettings {
public static void setQueenBeamDamage(double v) { queenBeamDamage = v; }
public static double queenBeamRange() { return queenBeamRange; }
public static void setQueenBeamRange(double v) { queenBeamRange = v; }
public static double queenBeamMinimumRange() { return queenBeamMinimumRange; }
public static void setQueenBeamMinimumRange(double v) { queenBeamMinimumRange = v; }
public static int queenBeamDurationTicks() { return queenBeamDurationTicks; }
public static void setQueenBeamDurationTicks(int v) { queenBeamDurationTicks = v; }
public static int queenBeamWindupTicks() { return queenBeamWindupTicks; }
@@ -2905,6 +2914,8 @@ public final class AntarchySettings {
public static void setKingBeamDamage(double v) { kingBeamDamage = v; }
public static double kingBeamRange() { return kingBeamRange; }
public static void setKingBeamRange(double v) { kingBeamRange = v; }
public static double kingBeamMinimumRange() { return kingBeamMinimumRange; }
public static void setKingBeamMinimumRange(double v) { kingBeamMinimumRange = v; }
public static int kingBeamDurationTicks() { return kingBeamDurationTicks; }
public static void setKingBeamDurationTicks(int v) { kingBeamDurationTicks = v; }
public static int kingBeamWindupTicks() { return kingBeamWindupTicks; }
@@ -2921,6 +2932,16 @@ public final class AntarchySettings {
public static void setKingBeamTerrainCap(int v) { kingBeamTerrainCap = v; }
public static int royalDecreeCooldownTicks() { return royalDecreeCooldownTicks; }
public static void setRoyalDecreeCooldownTicks(int v) { royalDecreeCooldownTicks = v; }
public static int kingRoyalMusterCooldownTicks() { return kingRoyalMusterCooldownTicks; }
public static void setKingRoyalMusterCooldownTicks(int v) { kingRoyalMusterCooldownTicks = v; }
public static int kingRoyalMusterWindupTicks() { return kingRoyalMusterWindupTicks; }
public static void setKingRoyalMusterWindupTicks(int v) { kingRoyalMusterWindupTicks = v; }
public static int kingRoyalMusterDurationTicks() { return kingRoyalMusterDurationTicks; }
public static void setKingRoyalMusterDurationTicks(int v) { kingRoyalMusterDurationTicks = v; }
public static double kingRoyalMusterRadius() { return kingRoyalMusterRadius; }
public static void setKingRoyalMusterRadius(double v) { kingRoyalMusterRadius = v; }
public static int kingRoyalMusterCap() { return kingRoyalMusterCap; }
public static void setKingRoyalMusterCap(int v) { kingRoyalMusterCap = v; }
public static double jerryInfantHealth() { return jerryInfantHealth; }
public static void setJerryInfantHealth(double v) { jerryInfantHealth = v; }
public static double jerryInfantAttackDamage() { return jerryInfantAttackDamage; }
@@ -206,6 +206,8 @@ public final class AntarchyObjects {
@SuppressWarnings("unchecked")
public static Supplier<MenuType<com.craisinlord.antarchy.content.menu.DorrieInventoryMenu>> DORRIE_INVENTORY_MENU = (Supplier<MenuType<com.craisinlord.antarchy.content.menu.DorrieInventoryMenu>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<MenuType<com.craisinlord.antarchy.content.menu.RoyalJudgmentMenu>> ROYAL_JUDGMENT_MENU = (Supplier<MenuType<com.craisinlord.antarchy.content.menu.RoyalJudgmentMenu>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<net.minecraft.world.item.Item> CHEEP_ITEM = (Supplier<net.minecraft.world.item.Item>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> DUPLICATOR_LOG = (Supplier<Block>) UNBOUND;
@@ -893,6 +895,10 @@ public final class AntarchyObjects {
DORRIE_INVENTORY_MENU = supplier;
}
public static void setRoyalJudgmentMenu(Supplier<MenuType<com.craisinlord.antarchy.content.menu.RoyalJudgmentMenu>> supplier) {
ROYAL_JUDGMENT_MENU = supplier;
}
public static void setAmericanComponent(Supplier<net.minecraft.core.component.DataComponentType<net.minecraft.util.Unit>> supplier) {
AMERICAN_COMPONENT = supplier;
}
@@ -1,5 +1,6 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.entity.WormEntity;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
@@ -18,9 +19,9 @@ import net.minecraft.world.phys.shapes.VoxelShape;
public class MucusBlock extends GlowLichenBlock {
public static final MapCodec<MucusBlock> CODEC = simpleCodec(MucusBlock::new);
private static final VoxelShape DOWN_COLLISION_SHAPE = Shapes.box(0.0D, 0.0D, 0.0D, 1.0D, 0.0625D, 1.0D);
private static final double SLIDE_ACCELERATION = 0.025D;
private static final double SLIDE_MAX_SPEED = 0.6D;
private static final double SLIDE_MIN_SPEED = 0.02D;
private static final double SLIDE_ACCELERATION = 0.045D;
private static final double SLIDE_MAX_SPEED = 1.2D;
private static final double SLIDE_MIN_SPEED = 0.01D;
public MucusBlock(BlockBehaviour.Properties properties) {
super(properties);
@@ -37,9 +38,12 @@ public class MucusBlock extends GlowLichenBlock {
}
@Override
public void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) {
super.entityInside(state, level, pos, entity);
if (level.isClientSide || !state.getValue(MultifaceBlock.getFaceProperty(Direction.DOWN))) {
public void stepOn(Level level, BlockPos pos, BlockState state, Entity entity) {
super.stepOn(level, pos, state, entity);
if (level.isClientSide
|| entity instanceof WormEntity
|| entity.isShiftKeyDown()
|| !state.getValue(MultifaceBlock.getFaceProperty(Direction.DOWN))) {
return;
}
@@ -10,7 +10,6 @@ import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.util.Mth;
public final class ClientTimeDilationTicker {
@@ -32,12 +31,6 @@ public final class ClientTimeDilationTicker {
ANIMATION_CLOCKS.clear();
com.craisinlord.antarchy.content.time.TimeDilationApi.clearSyncedClientRates();
}
// Entity rates come from the server. Field snapshots are used only for local effects.
for (Player player : level.players()) {
if (player.isDeadOrDying() || rateAt(player.getX(), player.getY(), player.getZ()) >= TimeDilationMath.NORMAL_RATE) {
com.craisinlord.antarchy.content.time.TimeDilationApi.clearRate(player);
}
}
}
public static float dilateAnimationTime(Entity entity, float vanillaTime) {
@@ -2,10 +2,25 @@ package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.royal.RoyalBossEntity;
import com.craisinlord.antarchy.content.entity.royal.RoyalHead;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.Mth;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
import software.bernie.geckolib.animation.AnimationState;
import software.bernie.geckolib.cache.object.GeoBone;
import software.bernie.geckolib.model.GeoModel;
public class RoyalBossModel extends GeoModel<RoyalBossEntity> {
private static final String[] BEAM_ANCHORS = {
"beam_anchor_left", "beam_anchor_center", "beam_anchor_right"
};
private static final String[][] AIM_CHAINS = {
{"L_neck", "L_neck2", "L_neck3"},
{"neck", "neck3", "neck4"},
{"R_neck", "R_neck2", "R_neck3"}
};
@Override
public ResourceLocation getModelResource(RoyalBossEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/" + animatable.geoNameForRender() + ".geo.json");
@@ -21,4 +36,53 @@ public class RoyalBossModel extends GeoModel<RoyalBossEntity> {
public ResourceLocation getAnimationResource(RoyalBossEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/" + animatable.geoNameForRender() + ".animation.json");
}
@Override
public void setCustomAnimations(RoyalBossEntity animatable, long instanceId,
AnimationState<RoyalBossEntity> animationState) {
super.setCustomAnimations(animatable, instanceId, animationState);
for (String anchor : BEAM_ANCHORS) {
this.getBone(anchor).ifPresent(bone -> bone.setTrackingMatrices(true));
}
RoyalHead.Slot slot = animatable.getRoyalBeamHeadSlot();
Vec3 beamEnd = animatable.getRoyalBeamEndPosition();
if (!animatable.isFiringRoyalBeam() || slot == null || beamEnd == null) {
return;
}
float partialTick = animationState.getPartialTick();
Vec3 origin = animatable.getRoyalBeamShootFrom(partialTick);
Vec3 direction = beamEnd.subtract(origin);
double horizontal = Math.sqrt(direction.x * direction.x + direction.z * direction.z);
if (direction.lengthSqr() < 1.0E-6D || horizontal < 1.0E-4D) {
return;
}
float desiredYaw = (float) (Mth.atan2(-direction.x, direction.z) * Mth.RAD_TO_DEG);
float bodyYaw = Mth.rotLerp(partialTick, animatable.yRotO, animatable.getYRot());
float relativeYaw = Mth.clamp(Mth.wrapDegrees(desiredYaw - bodyYaw), -55.0F, 55.0F) * Mth.DEG_TO_RAD;
float pitch = Mth.clamp((float) -Mth.atan2(direction.y, horizontal) * Mth.RAD_TO_DEG,
-45.0F, 45.0F) * Mth.DEG_TO_RAD;
String[] chain = AIM_CHAINS[slot.ordinal()];
float yawPerBone = relativeYaw / chain.length;
float pitchPerBone = pitch / chain.length;
for (String boneName : chain) {
this.getBone(boneName).ifPresent(bone -> {
bone.setRotY(bone.getRotY() + yawPerBone);
bone.setRotX(bone.getRotX() + pitchPerBone);
});
}
}
@Nullable
public Vec3 getTrackedBeamAnchor(RoyalHead.Slot slot) {
GeoBone bone = this.getBone(BEAM_ANCHORS[slot.ordinal()]).orElse(null);
if (bone == null || !bone.isTrackingMatrices()) {
return null;
}
org.joml.Vector3d position = bone.getWorldPosition();
return new Vec3(position.x, position.y, position.z);
}
}
@@ -3,6 +3,7 @@ package com.craisinlord.antarchy.content.client.renderer;
import com.craisinlord.antarchy.content.client.model.RoyalBossModel;
import com.craisinlord.antarchy.content.entity.royal.RoyalBossEntity;
import com.craisinlord.antarchy.content.entity.royal.KingEntity;
import com.craisinlord.antarchy.content.entity.royal.RoyalHead;
import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamElement;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
@@ -58,8 +59,8 @@ public class RoyalBossRenderer extends GeoEntityRenderer<RoyalBossEntity> {
this.shadowRadius = 8.0F * RoyalBossEntity.MODEL_RENDER_SCALE;
}
private static final float BEAM_OUTER_RADIUS = 1.10F;
private static final float BEAM_INNER_RADIUS = 0.52F;
private static final float BEAM_OUTER_RADIUS = 0.55F;
private static final float BEAM_INNER_RADIUS = 0.32F;
private static final float BEAM_TILE_BLOCKS = 3.0F;
private static final float BEAM_SCROLL_SPEED = 0.32F;
@@ -74,7 +75,12 @@ public class RoyalBossRenderer extends GeoEntityRenderer<RoyalBossEntity> {
double x = Mth.lerp(partialTick, entity.xo, entity.getX());
double y = Mth.lerp(partialTick, entity.yo, entity.getY());
double z = Mth.lerp(partialTick, entity.zo, entity.getZ());
Vec3 start = entity.getRoyalBeamShootFrom(partialTick).subtract(x, y, z);
RoyalHead.Slot beamHead = entity.getRoyalBeamHeadSlot();
Vec3 trackedAnchor = beamHead == null
? null
: ((RoyalBossModel) this.getGeoModel()).getTrackedBeamAnchor(beamHead);
Vec3 start = (trackedAnchor != null ? trackedAnchor : entity.getRoyalBeamShootFrom(partialTick))
.subtract(x, y, z);
Vec3 finish = end.subtract(x, y, z);
Vec3 axis = finish.subtract(start);
double length = axis.length();
@@ -13,7 +13,6 @@ import org.joml.Matrix4f;
public class WindVortexRenderer extends EntityRenderer<WindVortexEntity> {
private static final int RINGS = 11;
private static final int SQUARES_PER_SIDE = 3;
private static final float BASE_RADIUS = 0.35F;
public WindVortexRenderer(EntityRendererProvider.Context context) {
@@ -44,11 +43,11 @@ public class WindVortexRenderer extends EntityRenderer<WindVortexEntity> {
float ringSpin = spinDirection * age * (0.13F + progress * 0.045F) + ring * 0.47F;
float alpha = alphaMultiplier;
float halfSide = radius * 0.92F;
float tileSize = Math.max(0.035F, radius * 0.12F);
float lineThickness = 0.055F + progress * 0.018F;
int red = push ? 70 : 64;
int green = push ? 220 : 255;
int blue = push ? 255 : 56;
drawSquareRing(consumer, pose, basis, halfSide, axisDistance, tileSize, ringSpin,
drawSquareRing(consumer, pose, basis, halfSide, axisDistance, lineThickness, ringSpin,
alpha, red, green, blue);
}
@@ -56,47 +55,24 @@ public class WindVortexRenderer extends EntityRenderer<WindVortexEntity> {
}
private static void drawSquareRing(VertexConsumer consumer, Matrix4f pose, WindVortexEntity.Basis basis,
float halfSide, float axisDistance, float tileSize, float rotation, float alpha,
float halfSide, float axisDistance, float lineThickness, float rotation, float alpha,
int red, int green, int blue) {
for (int side = 0; side < 4; side++) {
for (int tile = 0; tile < SQUARES_PER_SIDE; tile++) {
float start = -halfSide + (tile + 0.18F) * (2.0F * halfSide / SQUARES_PER_SIDE);
float end = -halfSide + (tile + 0.82F) * (2.0F * halfSide / SQUARES_PER_SIDE);
float sideAngle = rotation + side * (Mth.TWO_PI / 4.0F);
addSquareTile(consumer, pose, basis, halfSide, axisDistance, tileSize,
sideAngle, start, end, alpha, red, green, blue);
}
float sideAngle = rotation + side * (Mth.TWO_PI / 4.0F);
addSquareSide(consumer, pose, basis, halfSide, axisDistance, lineThickness,
sideAngle, alpha, red, green, blue);
}
}
private static void addSquareTile(VertexConsumer consumer, Matrix4f pose, WindVortexEntity.Basis basis,
float halfSide, float axisDistance, float tileSize, float sideAngle, float start, float end,
private static void addSquareSide(VertexConsumer consumer, Matrix4f pose, WindVortexEntity.Basis basis,
float halfSide, float axisDistance, float lineThickness, float sideAngle,
float alpha, int red, int green, int blue) {
org.joml.Vector3f center = squarePoint(basis, halfSide, axisDistance, sideAngle, (start + end) * 0.5F);
org.joml.Vector3f tangent = new org.joml.Vector3f(
(float) (-basis.sideA.x * Mth.sin(sideAngle) + basis.sideB.x * Mth.cos(sideAngle)),
(float) (-basis.sideA.y * Mth.sin(sideAngle) + basis.sideB.y * Mth.cos(sideAngle)),
(float) (-basis.sideA.z * Mth.sin(sideAngle) + basis.sideB.z * Mth.cos(sideAngle)));
org.joml.Vector3f start = squarePoint(basis, halfSide, axisDistance, sideAngle, -halfSide);
org.joml.Vector3f end = squarePoint(basis, halfSide, axisDistance, sideAngle, halfSide);
org.joml.Vector3f axisOffset = new org.joml.Vector3f(
(float) basis.axis.x, (float) basis.axis.y, (float) basis.axis.z).mul(tileSize * 0.5F);
tangent.mul(tileSize * 0.5F);
(float) basis.axis.x, (float) basis.axis.y, (float) basis.axis.z).mul(lineThickness);
int a = Mth.clamp((int) (alpha * 255.0F), 0, 255);
addVertex(consumer, pose, center.x - tangent.x - axisOffset.x, center.y - tangent.y - axisOffset.y,
center.z - tangent.z - axisOffset.z, red, green, blue, a);
addVertex(consumer, pose, center.x + tangent.x - axisOffset.x, center.y + tangent.y - axisOffset.y,
center.z + tangent.z - axisOffset.z, red, green, blue, a);
addVertex(consumer, pose, center.x + tangent.x + axisOffset.x, center.y + tangent.y + axisOffset.y,
center.z + tangent.z + axisOffset.z, red, green, blue, a);
addVertex(consumer, pose, center.x - tangent.x + axisOffset.x, center.y - tangent.y + axisOffset.y,
center.z - tangent.z + axisOffset.z, red, green, blue, a);
addVertex(consumer, pose, center.x - tangent.x + axisOffset.x, center.y - tangent.y + axisOffset.y,
center.z - tangent.z + axisOffset.z, red, green, blue, a);
addVertex(consumer, pose, center.x + tangent.x + axisOffset.x, center.y + tangent.y + axisOffset.y,
center.z + tangent.z + axisOffset.z, red, green, blue, a);
addVertex(consumer, pose, center.x + tangent.x - axisOffset.x, center.y + tangent.y - axisOffset.y,
center.z + tangent.z - axisOffset.z, red, green, blue, a);
addVertex(consumer, pose, center.x - tangent.x - axisOffset.x, center.y - tangent.y - axisOffset.y,
center.z - tangent.z - axisOffset.z, red, green, blue, a);
addQuad(consumer, pose, start, end, axisOffset, red, green, blue, a);
}
private static org.joml.Vector3f squarePoint(WindVortexEntity.Basis basis, float halfSide,
@@ -595,7 +595,7 @@ public final class CreativeTabContents {
"dread", "long_dread", "inversion", "long_inversion", "stinky", "long_stinky",
"paralysis", "long_paralysis", "haste", "strong_haste", "shrinking",
"strong_shrinking", "extreme_shrinking", "growing", "strong_growing", "extreme_growing",
"command", "long_command", "time_dilation", "long_time_dilation"
"command", "long_command", "time_dilation", "long_time_dilation", "time_contraction", "long_time_contraction"
);
private static final Map<String, Integer> ORDER_INDEX = createOrderIndex();
@@ -1,11 +1,11 @@
package com.craisinlord.antarchy.content.effect;
import java.util.UUID;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.player.Player;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.ai.attributes.Attributes;
public final class CommandedBehavior {
private CommandedBehavior() {
@@ -20,23 +20,39 @@ public final class CommandedBehavior {
clear(mob);
return;
}
ServerPlayer commander = mob.level().getServer().getPlayerList().getPlayer(commanderUuid);
Entity commander = mob.level() instanceof ServerLevel level ? level.getEntity(commanderUuid) : null;
if (commander == null || commander.level() != mob.level() || !RoyalEffectEligibility.canApplyCommanded(mob)) {
mob.removeEffect(RoyalEffectHooks.commandedHolder());
clear(mob);
return;
}
if (mob.tickCount % 10 == 0) {
LivingEntity commandedCandidate = findCommanderTarget(mob, commander);
if (commandedCandidate != null) {
mob.setTarget(commandedCandidate);
access.antarchy$setCommandedTargetOwned(true);
}
}
LivingEntity target = mob.getTarget();
if (target != null && isProtectedAlly(mob, target)) {
mob.setTarget(null);
target = null;
}
if (target != null) {
tryPassiveCommandedAttack(mob, target);
}
if (mob.tickCount % 10 != 0 || target != null) {
return;
}
LivingEntity candidate = commander.getLastHurtByMob();
LivingEntity candidate = commander instanceof Mob commanderMob ? commanderMob.getTarget() : null;
if (!isValidTarget(mob, commander, candidate)) {
candidate = commander.getLastHurtMob();
candidate = commander instanceof net.minecraft.world.entity.player.Player player ? player.getLastHurtByMob() : null;
}
if (!isValidTarget(mob, commander, candidate)) {
candidate = mob.getLastHurtByMob();
}
if (!isValidTarget(mob, commander, candidate)) {
candidate = commander instanceof net.minecraft.world.entity.player.Player player ? player.getLastHurtMob() : null;
}
if (!isValidTarget(mob, commander, candidate)) {
candidate = mob.getLastHurtByMob();
@@ -72,18 +88,59 @@ public final class CommandedBehavior {
if (entity instanceof LivingEntity living && living.isAlliedTo(mob)) {
return true;
}
if (mob.level().getServer() != null
&& mob.level().getServer().getPlayerList().getPlayer(commanderUuid) instanceof Player commander
&& entity instanceof LivingEntity living) {
return living.isAlliedTo(commander);
if (entity instanceof LivingEntity living && commanderEntity(mob) instanceof LivingEntity livingCommander) {
return living.isAlliedTo(livingCommander);
}
return false;
}
private static boolean isValidTarget(Mob mob, ServerPlayer commander, LivingEntity target) {
private static boolean isValidTarget(Mob mob, Entity commander, LivingEntity target) {
return target != null && target.isAlive() && target != mob && target != commander
&& !isProtectedAlly(mob, target) && !target.isAlliedTo(commander)
&& mob.canAttack(target);
&& !isProtectedAlly(mob, target) && !target.isAlliedTo(commander);
}
private static LivingEntity findCommanderTarget(Mob mob, Entity commander) {
LivingEntity target = commander instanceof Mob commanderMob ? commanderMob.getTarget() : null;
if (isValidTarget(mob, commander, target)) {
return target;
}
if (commander instanceof net.minecraft.world.entity.player.Player player) {
target = player.getLastHurtMob();
if (isValidTarget(mob, commander, target)) {
return target;
}
target = player.getLastHurtByMob();
if (isValidTarget(mob, commander, target)) {
return target;
}
}
return mob.level().getEntitiesOfClass(Mob.class, mob.getBoundingBox().inflate(32.0D),
other -> other != mob && other != commander && commander.equals(other.getTarget())
&& isValidTarget(mob, commander, other)).stream()
.min((a, b) -> Double.compare(mob.distanceToSqr(a), mob.distanceToSqr(b)))
.orElse(null);
}
private static void tryPassiveCommandedAttack(Mob mob, LivingEntity target) {
if (mob.getAttribute(Attributes.ATTACK_DAMAGE) != null
&& mob.getAttributeValue(Attributes.ATTACK_DAMAGE) > 0.0D) {
return;
}
mob.getNavigation().moveTo(target, 1.0D);
if (mob.tickCount % 20 != 0 || mob.distanceToSqr(target) > 4.0D) {
return;
}
if (target.hurt(mob.damageSources().mobAttack(mob), 1.0F)) {
mob.swing(net.minecraft.world.InteractionHand.MAIN_HAND);
}
}
private static Entity commanderEntity(Mob mob) {
if (!(mob instanceof CommandedEntityAccess access) || mob.level().getServer() == null) {
return null;
}
UUID uuid = access.antarchy$getCommanderUuid();
return uuid == null || !(mob.level() instanceof ServerLevel level) ? null : level.getEntity(uuid);
}
public static void clear(Mob mob) {
@@ -6,6 +6,7 @@ import net.minecraft.world.entity.LivingEntity;
public final class DilatedMobEffect extends MobEffect {
public static final double RATE = 0.35D;
public static final double STRONG_RATE = 0.2D;
public DilatedMobEffect() {
super(MobEffectCategory.HARMFUL, 0x6C4AB6);
@@ -20,4 +21,8 @@ public final class DilatedMobEffect extends MobEffect {
public boolean shouldApplyEffectTickThisTick(int duration, int amplifier) {
return true;
}
public static double rateForAmplifier(int amplifier) {
return amplifier > 0 ? STRONG_RATE : RATE;
}
}
@@ -8,6 +8,7 @@ import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.player.Player;
import com.craisinlord.antarchy.content.entity.royal.RoyalBossEntity;
public final class RoyalEffectEligibility {
private RoyalEffectEligibility() {
@@ -21,6 +22,10 @@ public final class RoyalEffectEligibility {
return RoyalEffectHooks.dilatedHolder() != null && instance.is(RoyalEffectHooks.dilatedHolder());
}
public static boolean isContracted(MobEffectInstance instance) {
return RoyalEffectHooks.contractedHolder() != null && instance.is(RoyalEffectHooks.contractedHolder());
}
public static boolean canApplyCommanded(LivingEntity entity) {
return entity instanceof Mob mob
&& !(entity instanceof Player)
@@ -52,6 +57,6 @@ public final class RoyalEffectEligibility {
}
public static boolean canUseCommandSource(Entity source) {
return source instanceof Player;
return source instanceof Player || source instanceof RoyalBossEntity;
}
}
@@ -13,6 +13,8 @@ public final class RoyalEffectHooks {
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "commanded"));
private static final ResourceKey<MobEffect> DILATED_KEY = ResourceKey.create(Registries.MOB_EFFECT,
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "dilated"));
private static final ResourceKey<MobEffect> CONTRACTED_KEY = ResourceKey.create(Registries.MOB_EFFECT,
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "contracted"));
private RoyalEffectHooks() {
}
@@ -24,4 +26,8 @@ public final class RoyalEffectHooks {
public static Holder<MobEffect> dilatedHolder() {
return BuiltInRegistries.MOB_EFFECT.getHolder(DILATED_KEY).orElse(null);
}
public static Holder<MobEffect> contractedHolder() {
return BuiltInRegistries.MOB_EFFECT.getHolder(CONTRACTED_KEY).orElse(null);
}
}
@@ -24,12 +24,16 @@ import net.minecraft.world.level.block.RailBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.RailShape;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
public class DiamondMinecartEntity extends Minecart {
private static final long INPUT_TIMEOUT_TICKS = 5L;
private static final long COLLISION_COOLDOWN_TICKS = 10L;
private static final EntityDataAccessor<Float> SYNCED_SPEED =
SynchedEntityData.defineId(DiamondMinecartEntity.class, EntityDataSerializers.FLOAT);
private static final EntityDataAccessor<Integer> SYNCED_FACING =
@@ -41,6 +45,7 @@ public class DiamondMinecartEntity extends Minecart {
private Direction facingDir = Direction.SOUTH;
private BlockPos lastBlockPos = null;
private boolean railWarningCooldown = false;
private final Map<Integer, Long> collisionCooldowns = new HashMap<>();
private final Item dropItem;
@@ -134,6 +139,7 @@ public class DiamondMinecartEntity extends Minecart {
this.inputFlags = 0;
this.lastInputGameTime = Long.MIN_VALUE;
this.currentSpeed = 0.0F;
this.collisionCooldowns.clear();
this.entityData.set(SYNCED_SPEED, 0.0F);
this.setDeltaMovement(0.0D, this.getDeltaMovement().y, 0.0D);
return;
@@ -146,6 +152,11 @@ public class DiamondMinecartEntity extends Minecart {
Player rider = this.getRidingPlayer();
boolean hasRider = rider != null;
if (!hasRider) {
this.inputFlags = 0;
this.lastInputGameTime = Long.MIN_VALUE;
}
if (this.lastBlockPos == null) {
if (rider != null) {
this.facingDir = getLookFacing(rider, Direction.SOUTH);
@@ -212,10 +223,10 @@ public class DiamondMinecartEntity extends Minecart {
private void onEnteredNewBlock(BlockPos currentPos, @Nullable Player rider) {
Direction previousFacing = this.facingDir;
if (rider != null && (this.inputFlags & 0x01) != 0) {
Direction lookedFacing = getLookFacing(rider, this.facingDir);
if (lookedFacing != this.facingDir.getOpposite()) {
this.facingDir = lookedFacing;
if (rider != null) {
Direction steeredFacing = getSteeredFacing(rider, this.facingDir);
if (steeredFacing != this.facingDir.getOpposite()) {
this.facingDir = steeredFacing;
}
}
@@ -380,7 +391,10 @@ public class DiamondMinecartEntity extends Minecart {
}
private boolean canPlaceRailAt(BlockPos pos, BlockState existing) {
if (!isWithinRailBuildHeight(pos) || !this.level().getBlockState(pos.below()).isSolid()) {
if (!isWithinRailBuildHeight(pos)
|| !this.level().hasChunkAt(pos)
|| !this.level().getWorldBorder().isWithinBounds(pos)
|| !this.level().getBlockState(pos.below()).isSolid()) {
return false;
}
return BaseRailBlock.isRail(existing) || existing.isAir() || existing.canBeReplaced();
@@ -390,16 +404,44 @@ public class DiamondMinecartEntity extends Minecart {
double maxDamage = AntarchySettings.diamondMinecartMaxMobDamage();
double maxSpeed = AntarchySettings.diamondMinecartMaxSpeed();
float damage = maxSpeed <= 0.0D ? 0.0F : (float) (maxDamage * (this.currentSpeed / maxSpeed));
if (damage <= 0.0F) {
return;
}
long gameTime = this.level().getGameTime();
this.collisionCooldowns.entrySet().removeIf(entry -> entry.getValue() <= gameTime);
Vec3 horizontalVelocity = new Vec3(this.getDeltaMovement().x, 0.0D, this.getDeltaMovement().z);
double velocityLength = horizontalVelocity.length();
if (velocityLength < 1.0E-4D) {
return;
}
Vec3 movementDirection = horizontalVelocity.scale(1.0D / velocityLength);
DamageSource source = this.level().damageSources().generic();
AABB hitBox = this.getBoundingBox().inflate(0.2D, 0.0D, 0.2D);
List<LivingEntity> nearby = this.level().getEntitiesOfClass(LivingEntity.class, hitBox,
entity -> !(entity instanceof Player player && this.hasPassenger(player)));
entity -> !(entity instanceof Player player && this.hasPassenger(player))
&& !entity.isInvulnerable());
for (LivingEntity mob : nearby) {
mob.hurt(source, damage);
if (this.collisionCooldowns.containsKey(mob.getId())) {
continue;
}
double dx = mob.getX() - this.getX();
double dz = mob.getZ() - this.getZ();
double distance = Math.sqrt(dx * dx + dz * dz);
if (distance > 1.0E-4D) {
Vec3 toMob = new Vec3(dx / distance, 0.0D, dz / distance);
if (movementDirection.dot(toMob) < -0.2D) {
continue;
}
}
if (!mob.hurt(source, damage)) {
continue;
}
this.collisionCooldowns.put(mob.getId(), gameTime + COLLISION_COOLDOWN_TICKS);
double len = Math.sqrt(dx * dx + dz * dz);
if (len > 0.001D) {
mob.setDeltaMovement(mob.getDeltaMovement().add(
@@ -426,6 +468,18 @@ public class DiamondMinecartEntity extends Minecart {
return direction.getAxis() == Direction.Axis.Y ? fallback : direction;
}
private Direction getSteeredFacing(Player rider, Direction fallback) {
boolean left = (this.inputFlags & 0x04) != 0;
boolean right = (this.inputFlags & 0x08) != 0;
if (left != right) {
return left ? fallback.getCounterClockWise() : fallback.getClockWise();
}
if ((this.inputFlags & 0x01) != 0) {
return getLookFacing(rider, fallback);
}
return fallback;
}
private static int facingDirectionIndex(Direction dir) {
return switch (dir) {
case NORTH -> 0;
@@ -25,6 +25,7 @@ import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.MoverType;
import net.minecraft.world.entity.PathfinderMob;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.player.Player;
@@ -66,6 +67,11 @@ public class HoverboardEntity extends PathfinderMob implements GeoEntity {
this.setPersistenceRequired();
}
@Override
public boolean canBeAffected(MobEffectInstance effectInstance) {
return false;
}
public static AttributeSupplier.Builder createAttributes() {
return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 6.0D);
}
@@ -1,14 +1,23 @@
package com.craisinlord.antarchy.content.entity;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.AntarchySoundEvents;
import java.util.Optional;
import net.minecraft.core.Direction;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.util.RandomSource;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.MobSpawnType;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.ai.goal.FloatGoal;
@@ -21,6 +30,11 @@ import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
import net.minecraft.world.entity.monster.Monster;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.ServerLevelAccessor;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.MultifaceBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.core.BlockPos;
import net.minecraft.world.phys.Vec3;
@@ -34,6 +48,14 @@ import software.bernie.geckolib.animation.RawAnimation;
import software.bernie.geckolib.util.GeckoLibUtil;
public class WormEntity extends Monster implements GeoEntity {
private static final ResourceKey<Biome> WORMY_CAVES = ResourceKey.create(
Registries.BIOME,
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "wormy_caves")
);
private static final ResourceLocation LOAM_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "loam");
private static final ResourceLocation MUCUS_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "mucus");
private static final int MUCUS_TRAIL_INTERVAL = 6;
private static final double MUCUS_TRAIL_MIN_DISTANCE_SQR = 0.36D;
private static final EntityDataAccessor<Integer> ANIMATION_STATE = SynchedEntityData.defineId(WormEntity.class, EntityDataSerializers.INT);
private static final int ANIM_INGROUND = 0;
private static final int ANIM_CRAWL = 1;
@@ -43,6 +65,8 @@ public class WormEntity extends Monster implements GeoEntity {
private static final RawAnimation ATTACK_ANIM = RawAnimation.begin().thenPlay("attack");
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
private int attackAnimationTicks;
private int mucusTrailCooldown;
private Vec3 lastMucusTrailPosition;
public WormEntity(EntityType<? extends WormEntity> entityType, Level level) {
super(entityType, level);
@@ -58,6 +82,23 @@ public class WormEntity extends Monster implements GeoEntity {
.add(Attributes.KNOCKBACK_RESISTANCE, 0.45D);
}
public static boolean canSpawn(EntityType<WormEntity> entityType, ServerLevelAccessor level, MobSpawnType spawnReason, BlockPos pos, RandomSource random) {
if ((spawnReason == MobSpawnType.NATURAL || spawnReason == MobSpawnType.CHUNK_GENERATION)
&& !level.getBiome(pos).is(WORMY_CAVES)) {
return false;
}
Optional<Block> loam = BuiltInRegistries.BLOCK.getOptional(LOAM_ID);
BlockState floor = level.getBlockState(pos.below());
if (!floor.is(Blocks.MUD) && (loam.isEmpty() || !floor.is(loam.get()))) {
return false;
}
return level.getBlockState(pos.above()).getCollisionShape(level, pos.above()).isEmpty()
&& level.getBlockState(pos.above(2)).getCollisionShape(level, pos.above(2)).isEmpty()
&& Monster.checkMonsterSpawnRules(entityType, level, spawnReason, pos, random);
}
@Override
protected void defineSynchedData(SynchedEntityData.Builder builder) {
super.defineSynchedData(builder);
@@ -112,12 +153,96 @@ public class WormEntity extends Monster implements GeoEntity {
if (this.level().isClientSide) {
return;
}
this.tickMucusTrail();
if (this.attackAnimationTicks > 0) {
this.attackAnimationTicks--;
}
this.updateAnimationState();
}
private void tickMucusTrail() {
if (this.mucusTrailCooldown > 0) {
this.mucusTrailCooldown--;
}
Vec3 velocity = this.getDeltaMovement();
if (this.mucusTrailCooldown > 0
|| !this.isAlive()
|| !this.onGround()
|| this.isInWaterOrBubble()
|| this.isPassenger()
|| velocity.horizontalDistanceSqr() < 0.0025D) {
return;
}
Vec3 currentPosition = this.position();
if (this.lastMucusTrailPosition != null
&& this.lastMucusTrailPosition.distanceToSqr(currentPosition) < MUCUS_TRAIL_MIN_DISTANCE_SQR) {
return;
}
this.lastMucusTrailPosition = currentPosition;
this.mucusTrailCooldown = MUCUS_TRAIL_INTERVAL;
Vec3 horizontalDirection = new Vec3(velocity.x, 0.0D, velocity.z).normalize();
BlockPos trailPos = BlockPos.containing(
this.getX() - horizontalDirection.x * 0.45D,
this.getBoundingBox().minY + 0.01D,
this.getZ() - horizontalDirection.z * 0.45D
);
boolean placed = this.placeFloorMucus(trailPos);
if (placed && this.random.nextFloat() < 0.35F) {
Vec3 side = new Vec3(-horizontalDirection.z, 0.0D, horizontalDirection.x);
double sideOffset = this.random.nextBoolean() ? 0.55D : -0.55D;
this.placeFloorMucus(BlockPos.containing(
trailPos.getX() + 0.5D + side.x * sideOffset,
trailPos.getY(),
trailPos.getZ() + 0.5D + side.z * sideOffset
));
}
}
private boolean placeFloorMucus(BlockPos pos) {
Optional<Block> mucus = BuiltInRegistries.BLOCK.getOptional(MUCUS_ID);
if (mucus.isEmpty() || !(mucus.get() instanceof MultifaceBlock mucusBlock)) {
return false;
}
BlockState existing = this.level().getBlockState(pos);
var floorFace = MultifaceBlock.getFaceProperty(Direction.DOWN);
if (existing.is(mucusBlock)) {
if (existing.getValue(floorFace)) {
return true;
}
BlockState merged = existing.setValue(floorFace, true);
if (merged.canSurvive(this.level(), pos)) {
this.level().setBlock(pos, merged, Block.UPDATE_ALL);
return true;
}
return false;
}
if (!existing.isAir()) {
return false;
}
BlockPos supportPos = pos.below();
BlockState support = this.level().getBlockState(supportPos);
if (!support.isFaceSturdy(this.level(), supportPos, Direction.UP)) {
return false;
}
BlockState mucusState = mucusBlock.defaultBlockState().setValue(floorFace, true);
if (!mucusState.canSurvive(this.level(), pos)) {
return false;
}
this.level().setBlock(pos, mucusState, Block.UPDATE_ALL);
return true;
}
private void updateAnimationState() {
if (this.attackAnimationTicks > 0) {
this.entityData.set(ANIMATION_STATE, ANIM_ATTACK);
@@ -3,6 +3,8 @@ package com.craisinlord.antarchy.content.entity.royal;
import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.AntarchySoundEvents;
import com.craisinlord.antarchy.content.effect.RoyalEffectEligibility;
import com.craisinlord.antarchy.content.effect.RoyalEffectHooks;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
@@ -20,10 +22,19 @@ import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LightningBolt;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.MobCategory;
import net.minecraft.world.entity.monster.Enemy;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.Pose;
import net.minecraft.world.entity.projectile.AbstractArrow;
import net.minecraft.world.entity.projectile.Arrow;
import net.minecraft.commands.arguments.EntityAnchorArgument;
import net.minecraft.world.entity.projectile.Projectile;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.item.ArmorItem;
import net.minecraft.world.item.ArmorMaterials;
import net.minecraft.world.item.ItemStack;
@@ -36,6 +47,8 @@ import org.jetbrains.annotations.Nullable;
import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamSettings;
import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamTerrainMode;
import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamElement;
import com.craisinlord.antarchy.content.menu.RoyalJudgmentMenu;
import com.craisinlord.antarchy.content.menu.RoyalJudgmentState;
import com.craisinlord.antarchy.content.entity.royal.decree.CloseQuartersDecree;
import com.craisinlord.antarchy.content.entity.royal.decree.ComeNoCloserDecree;
import com.craisinlord.antarchy.content.entity.royal.decree.DoNotRunDecree;
@@ -85,6 +98,21 @@ public class KingEntity extends RoyalBossEntity {
private int iceballCooldownTicks = 120;
private int iceSpikeCooldownTicks = 160;
private boolean decreeRetreatPressure;
@Nullable
private ServerPlayer exileTarget;
private int exileTicks;
@Nullable
private ServerPlayer titheTarget;
private int titheTicks;
@Nullable
private ServerPlayer targetShotPlayer;
@Nullable
private ServerPlayer targetShotVictim;
private int targetShotTicks;
@Nullable
private ServerPlayer sealedTarget;
private int sealedTicks;
private long sealUntil;
private final Map<UUID, Long> judgmentCooldowns = new HashMap<>();
private final Map<UUID, Long> lastPlayerDamageTime = new HashMap<>();
private final Map<UUID, Integer> iceBuildup = new HashMap<>();
@@ -178,6 +206,11 @@ public class KingEntity extends RoyalBossEntity {
return RoyalBeamTerrainMode.BUILD_ICE;
}
@Override
protected double royalBeamMinimumRange() {
return AntarchySettings.kingBeamMinimumRange();
}
@Override
protected RoyalBeamTerrainMode royalBeamTerrainMode(@Nullable RoyalHead head) {
return head != null && head.slot() == RoyalHead.Slot.RIGHT ? RoyalBeamTerrainMode.BUILD_ICE : RoyalBeamTerrainMode.NONE;
@@ -298,6 +331,7 @@ public class KingEntity extends RoyalBossEntity {
if (this.level().isClientSide) {
return;
}
this.tickRoyalPunishment();
if (this.iceBuildup.size() > 16) {
this.iceBuildup.clear();
}
@@ -328,6 +362,262 @@ public class KingEntity extends RoyalBossEntity {
}
}
private void tickRoyalPunishment() {
if (this.exileTarget == null && this.titheTarget == null && this.targetShotPlayer == null && this.sealedTarget == null) {
return;
}
if (this.exileTarget != null) {
this.tickRoyalExile();
}
if (this.titheTarget != null) {
this.tickRoyalTithe();
}
if (this.targetShotPlayer != null) {
this.tickRoyalTargetShot();
}
if (this.sealedTarget != null) {
this.tickRoyalSeal();
}
}
private void tickRoyalExile() {
if (this.exileTicks-- <= 0 || !this.exileTarget.isAlive() || this.exileTarget.level() != this.level()
|| this.isDeadOrDying()) {
this.clearExile();
return;
}
this.exileTarget.lookAt(EntityAnchorArgument.Anchor.EYES, this.getEyePosition());
this.exileTarget.setPose(Pose.CROUCHING);
this.exileTarget.setShiftKeyDown(true);
if (this.exileTicks == 1) {
Vec3 away = this.exileTarget.position().subtract(this.position()).multiply(1.0D, 0.0D, 1.0D);
if (away.lengthSqr() < 1.0E-4D) {
away = this.getLookAngle().multiply(-1.0D, 0.0D, -1.0D);
}
away = away.normalize();
this.exileTarget.setDeltaMovement(away.x * 2.6D, 1.35D, away.z * 2.6D);
this.exileTarget.hasImpulse = true;
this.triggerAnim("body_action", "wing_gust");
this.playRoyalSound(AntarchySoundEvents.KING_WING_FLAP.get(), 0.82F);
}
}
private void tickRoyalTithe() {
if (!this.titheTarget.isAlive() || this.titheTarget.level() != this.level()
|| this.isDeadOrDying() || !(this.titheTarget.containerMenu instanceof RoyalJudgmentMenu)) {
this.clearTithe();
return;
}
if (--this.titheTicks <= 0) {
for (int slot = 0; slot < this.titheTarget.getInventory().getContainerSize(); slot++) {
ItemStack stack = this.titheTarget.getInventory().getItem(slot);
if (stack.isEmpty() || !isRoyalTitheItem(stack)) continue;
ItemStack thrown = stack.split(1);
this.titheTarget.getInventory().setChanged();
this.titheTarget.drop(thrown, true);
this.clearTithe();
return;
}
this.clearTithe();
}
}
private void tickRoyalTargetShot() {
if (!this.targetShotPlayer.isAlive() || this.targetShotVictim == null || !this.targetShotVictim.isAlive()
|| this.targetShotPlayer.level() != this.level() || this.isDeadOrDying()
|| !(this.targetShotPlayer.containerMenu instanceof RoyalJudgmentMenu)) {
this.clearTargetShot();
return;
}
this.targetShotPlayer.lookAt(EntityAnchorArgument.Anchor.EYES, this.targetShotVictim.getEyePosition());
if (--this.targetShotTicks <= 0) {
ItemStack ranged = findRoyalRangedItem(this.targetShotPlayer);
if (!ranged.isEmpty()) {
Arrow arrow = new Arrow((ServerLevel) this.level(), this.targetShotPlayer, ItemStack.EMPTY, ItemStack.EMPTY);
arrow.setPos(this.targetShotPlayer.getX(), this.targetShotPlayer.getEyeY() - 0.1D, this.targetShotPlayer.getZ());
Vec3 direction = this.targetShotVictim.getEyePosition().subtract(arrow.position()).normalize();
arrow.setDeltaMovement(direction.scale(3.0D));
arrow.setBaseDamage(2.0D);
((ServerLevel) this.level()).addFreshEntity(arrow);
this.targetShotPlayer.displayClientMessage(Component.literal("The King takes your shot."), true);
}
this.clearTargetShot();
}
}
private void tickRoyalSeal() {
if (!this.sealedTarget.isAlive() || this.sealedTarget.level() != this.level() || this.isDeadOrDying()
|| !(this.sealedTarget.containerMenu instanceof RoyalJudgmentMenu) || --this.sealedTicks <= 0) {
this.clearSeal();
}
}
private void clearExile() {
if (this.exileTarget != null && this.exileTarget.isAlive()) {
this.exileTarget.setShiftKeyDown(false);
this.exileTarget.setPose(Pose.STANDING);
}
this.exileTarget = null;
this.exileTicks = 0;
}
private void clearTithe() {
if (this.titheTarget != null && this.titheTarget.containerMenu instanceof RoyalJudgmentMenu) {
this.titheTarget.closeContainer();
}
this.titheTarget = null;
this.titheTicks = 0;
}
private void clearTargetShot() {
if (this.targetShotPlayer != null && this.targetShotPlayer.containerMenu instanceof RoyalJudgmentMenu) {
this.targetShotPlayer.closeContainer();
}
this.targetShotPlayer = null;
this.targetShotVictim = null;
this.targetShotTicks = 0;
}
private void clearSeal() {
if (this.sealedTarget != null) {
RoyalJudgmentState.clear(this.sealedTarget.getUUID());
if (this.sealedTarget.containerMenu instanceof RoyalJudgmentMenu) {
this.sealedTarget.closeContainer();
}
}
this.sealedTarget = null;
this.sealedTicks = 0;
}
private void startTithe(ServerPlayer target) {
this.clearTithe();
this.titheTarget = target;
this.titheTicks = 20;
target.openMenu(new MenuProvider() {
@Override
public Component getDisplayName() {
return Component.translatable("menu.antarchy.royal_judgment");
}
@Override
public AbstractContainerMenu createMenu(int containerId, net.minecraft.world.entity.player.Inventory inventory,
Player player) {
return new RoyalJudgmentMenu(containerId, inventory);
}
});
}
private void startTargetShot(ServerPlayer target, ServerPlayer victim) {
this.clearTargetShot();
this.targetShotPlayer = target;
this.targetShotVictim = victim;
this.targetShotTicks = 20;
target.openMenu(new MenuProvider() {
@Override
public Component getDisplayName() {
return Component.translatable("menu.antarchy.royal_judgment");
}
@Override
public AbstractContainerMenu createMenu(int containerId, net.minecraft.world.entity.player.Inventory inventory,
Player player) {
return new RoyalJudgmentMenu(containerId, inventory);
}
});
}
private void startSeal(ServerPlayer target) {
this.clearSeal();
java.util.Set<Integer> slots = new java.util.HashSet<>();
for (int slot = 9; slot < 18; slot++) slots.add(slot);
RoyalJudgmentState.seal(target.getUUID(), slots);
this.sealedTarget = target;
this.sealedTicks = 100;
target.openMenu(new MenuProvider() {
@Override
public Component getDisplayName() {
return Component.translatable("menu.antarchy.royal_judgment");
}
@Override
public AbstractContainerMenu createMenu(int containerId, net.minecraft.world.entity.player.Inventory inventory,
Player player) {
return new RoyalJudgmentMenu(containerId, inventory);
}
});
}
public boolean debugActivateDecree(String id, ServerPlayer target) {
for (RoyalDecree decree : DECREES) {
String decreeId = decree.translationKey().substring(decree.translationKey().lastIndexOf('.') + 1);
if (decreeId.equalsIgnoreCase(id.replace('-', '_'))) {
this.endDecree(this.getTarget());
this.activeDecree = decree;
this.activeDecreeTicks = 300;
this.decreeCooldownTicks = 0;
this.sendDecreeTitle(target);
return true;
}
}
return false;
}
public boolean debugTriggerPunishment(RoyalPunishmentType type, ServerPlayer target) {
if (!(this.level() instanceof ServerLevel level) || !target.isAlive() || target.level() != level) {
return false;
}
switch (type) {
case ROYAL_EXILE -> {
this.clearExile();
this.exileTarget = target;
this.exileTicks = 25;
return true;
}
case ROYAL_TITHE -> {
this.startTithe(target);
return true;
}
case KINGS_TARGET -> {
ServerPlayer victim = level.players().stream()
.filter(candidate -> candidate != target && candidate.isAlive() && candidate.distanceToSqr(target) <= 4096.0D)
.min((left, right) -> Double.compare(left.distanceToSqr(target), right.distanceToSqr(target)))
.orElse(null);
if (victim == null) return false;
ItemStack ranged = findRoyalRangedItem(target);
if (ranged.isEmpty()) return false;
target.displayClientMessage(Component.literal("The King chooses your target."), true);
this.startTargetShot(target, victim);
return true;
}
case KINGS_SEAL -> {
this.sealUntil = level.getGameTime() + 100L;
target.displayClientMessage(Component.literal("The King seals your inventory."), true);
level.sendParticles(ParticleTypes.ENCHANT, target.getX(), target.getY() + 1.0D, target.getZ(),
30, 0.6D, 1.0D, 0.6D, 0.1D);
this.startSeal(target);
return true;
}
}
return false;
}
private static boolean isRoyalTitheItem(ItemStack stack) {
return stack.is(net.minecraft.world.item.Items.ARROW)
|| stack.is(net.minecraft.world.item.Items.BREAD)
|| stack.is(net.minecraft.world.item.Items.COBBLESTONE)
|| stack.is(net.minecraft.world.item.Items.POTION);
}
private static ItemStack findRoyalRangedItem(ServerPlayer player) {
for (ItemStack stack : player.getInventory().items) {
if (stack.getItem() instanceof net.minecraft.world.item.BowItem
|| stack.getItem() instanceof net.minecraft.world.item.CrossbowItem) {
return stack;
}
}
return ItemStack.EMPTY;
}
private void trackBehavior(LivingEntity target) {
double distance = target.distanceTo(this);
this.bumpBehavior(Behavior.AIRBORNE, !target.onGround() && !target.isPassenger() ? 1 : -1);
@@ -389,6 +679,27 @@ public class KingEntity extends RoyalBossEntity {
KingEntity.this.performWingGust(level, target);
}
})) {
} else if (this.attackScheduler.ready("royal_muster", RoyalAttackLane.BODY)
&& !this.findRoyalMusterTargets(level).isEmpty()
&& (forceFar || this.random.nextInt(4) == 0)
&& this.beginRoyalAttack("royal_muster", RoyalAttackLane.BODY,
AntarchySettings.kingRoyalMusterCooldownTicks(),
AntarchySettings.kingRoyalMusterWindupTicks(), 1, 20,
new com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackScheduler.Action() {
@Override public void onStart() {
KingEntity.this.triggerAnim("body_action", "minion_spawn");
KingEntity.this.playRoyalSound(AntarchySoundEvents.KING_DECREE_CAST.get(), 0.72F);
level.sendParticles(ParticleTypes.ENCHANT,
KingEntity.this.getX(), KingEntity.this.getY() + 2.0D, KingEntity.this.getZ(),
36, 5.0D, 2.0D, 5.0D, 0.12D);
}
@Override public void onActive(int elapsedTicks) {
KingEntity.this.performRoyalMuster(level);
}
@Override public void onComplete() {
KingEntity.this.playRoyalSound(AntarchySoundEvents.KING_ROAR.get(), 0.62F);
}
})) {
}
}
@@ -403,6 +714,37 @@ public class KingEntity extends RoyalBossEntity {
this.tickKingElementalProjectiles(level, target);
}
private List<Mob> findRoyalMusterTargets(ServerLevel level) {
double radius = AntarchySettings.kingRoyalMusterRadius();
return level.getEntitiesOfClass(Mob.class, this.getBoundingBox().inflate(radius), mob ->
mob.isAlive() && mob != this
&& (mob.getType().getCategory() == MobCategory.MONSTER || mob instanceof Enemy)
&& !(mob instanceof RoyalBossEntity)
&& RoyalEffectEligibility.canApplyCommanded(mob));
}
private void performRoyalMuster(ServerLevel level) {
var commanded = RoyalEffectHooks.commandedHolder();
if (commanded == null) {
return;
}
int applied = 0;
for (Mob mob : this.findRoyalMusterTargets(level)) {
if (applied >= AntarchySettings.kingRoyalMusterCap()) {
break;
}
if (mob.addEffect(new MobEffectInstance(commanded, AntarchySettings.kingRoyalMusterDurationTicks()), this)) {
applied++;
level.sendParticles(ParticleTypes.HAPPY_VILLAGER,
mob.getX(), mob.getY() + mob.getBbHeight() + 0.3D, mob.getZ(),
5, 0.3D, 0.2D, 0.3D, 0.02D);
}
}
if (applied > 0) {
this.playRoyalSound(AntarchySoundEvents.KING_DECREE_CAST.get(), 0.95F);
}
}
private void tickKingElementalProjectiles(ServerLevel level, LivingEntity target) {
if (this.fireballCooldownTicks > 0) this.fireballCooldownTicks--;
if (this.iceballCooldownTicks > 0) this.iceballCooldownTicks--;
@@ -549,13 +891,7 @@ public class KingEntity extends RoyalBossEntity {
this.decreeRetreatPressure = false;
this.playRoyalSound(AntarchySoundEvents.KING_DECREE_CAST.get(), 0.9F + this.random.nextFloat() * 0.15F);
this.playRoyalSound(AntarchySoundEvents.KING_ROAR.get(), 0.8F + this.random.nextFloat() * 0.12F);
if (target instanceof ServerPlayer player) {
player.connection.send(new ClientboundSetTitlesAnimationPacket(5, 300, 10));
player.connection.send(new ClientboundSetTitleTextPacket(Component.translatable(this.activeDecree.translationKey())
.withStyle(style -> style.withColor(ChatFormatting.GOLD).withBold(true))));
player.connection.send(new ClientboundSetSubtitleTextPacket(Component.translatable(this.activeDecree.instructionKey())
.withStyle(style -> style.withColor(ChatFormatting.WHITE))));
}
if (target instanceof ServerPlayer player) this.sendDecreeTitle(player);
}
int countdown = this.activeDecree.countdownTicks(target);
if (countdown > 0 && countdown <= 100 && this.tickCount % 20 == 0) {
@@ -589,6 +925,15 @@ public class KingEntity extends RoyalBossEntity {
return DECREES.get(this.random.nextInt(DECREES.size()));
}
private void sendDecreeTitle(ServerPlayer player) {
if (this.activeDecree == null) return;
player.connection.send(new ClientboundSetTitlesAnimationPacket(5, 300, 10));
player.connection.send(new ClientboundSetTitleTextPacket(Component.translatable(this.activeDecree.translationKey())
.withStyle(style -> style.withColor(ChatFormatting.GOLD).withBold(true))));
player.connection.send(new ClientboundSetSubtitleTextPacket(Component.translatable(this.activeDecree.instructionKey())
.withStyle(style -> style.withColor(ChatFormatting.WHITE))));
}
private void endDecree(@Nullable LivingEntity target) {
if (target instanceof ServerPlayer player) {
player.connection.send(new ClientboundClearTitlesPacket(false));
@@ -615,7 +960,11 @@ public class KingEntity extends RoyalBossEntity {
if (this.activeDecree == null || target == null || !target.isAlive()) {
return;
}
this.invokeJudgment(target);
if (target instanceof ServerPlayer player) {
this.debugTriggerPunishment(RoyalPunishmentType.ROYAL_EXILE, player);
} else {
this.invokeJudgment(target);
}
this.endDecree(target);
}
@@ -37,6 +37,7 @@ public class RoyalBlackHoleEntity extends Entity implements GeoEntity {
private static final String OWNER_KEY = "OwnerUuid";
private static final String AGE_KEY = "Age";
private static final String ACTIVE_KEY = "ActiveTicks";
private static final String ASSAILANT_KEY = "AssailantVariant";
private static final double DEFAULT_RADIUS = 14.0D;
private static final int DEFAULT_ACTIVE_TICKS = 120;
@@ -46,6 +47,7 @@ public class RoyalBlackHoleEntity extends Entity implements GeoEntity {
private UUID ownerId;
private int age;
private int activeTicks = DEFAULT_ACTIVE_TICKS;
private boolean assailantVariant;
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
public RoyalBlackHoleEntity(EntityType<? extends RoyalBlackHoleEntity> entityType, Level level) {
@@ -67,6 +69,12 @@ public class RoyalBlackHoleEntity extends Entity implements GeoEntity {
return create(level, center, AntarchySettings.queenBlackHoleRadius(), AntarchySettings.queenBlackHoleActiveTicks(), ownerId);
}
public static RoyalBlackHoleEntity createAssailant(ServerLevel level, Vec3 center, @Nullable UUID ownerId) {
RoyalBlackHoleEntity hole = create(level, center, AntarchySettings.queenBlackHoleRadius(), AntarchySettings.queenBlackHoleActiveTicks(), ownerId);
hole.assailantVariant = true;
return hole;
}
@Override
protected void defineSynchedData(SynchedEntityData.Builder builder) {
builder.define(RADIUS, (float) DEFAULT_RADIUS);
@@ -94,9 +102,12 @@ public class RoyalBlackHoleEntity extends Entity implements GeoEntity {
}
this.age++;
if (!this.isCollapsing()) {
if (this.assailantVariant) {
this.setPos(this.getX(), this.getY() + 0.035D, this.getZ());
}
this.applyPull();
if (this.age % 10 == 0 && this.level() instanceof ServerLevel level) {
TimeDilationApi.createField(level, this.position(), Math.max(2.0D, this.radius() * 0.55D), 0.18D, 14);
TimeDilationApi.createField(level, this.position(), Math.max(2.0D, this.radius() * 0.55D), 0.18D, 14, this.ownerId, !this.assailantVariant);
if (this.age % 20 == 0 && level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
RoyalBlockDestruction.destroySphere(level, this, this.position(), Math.min(2.0D, this.radius() * 0.2D), 8, 30.0D, 0.0F);
}
@@ -207,6 +218,7 @@ public class RoyalBlackHoleEntity extends Entity implements GeoEntity {
this.age = tag.getInt(AGE_KEY);
this.activeTicks = tag.contains(ACTIVE_KEY) ? tag.getInt(ACTIVE_KEY) : DEFAULT_ACTIVE_TICKS;
this.ownerId = tag.hasUUID(OWNER_KEY) ? tag.getUUID(OWNER_KEY) : null;
this.assailantVariant = tag.getBoolean(ASSAILANT_KEY);
}
@Override
@@ -217,6 +229,7 @@ public class RoyalBlackHoleEntity extends Entity implements GeoEntity {
if (this.ownerId != null) {
tag.putUUID(OWNER_KEY, this.ownerId);
}
tag.putBoolean(ASSAILANT_KEY, this.assailantVariant);
}
@Override
@@ -98,6 +98,13 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
private static final int OBSTRUCTION_CLEAR_MAX_BLOCKS = 24;
private static final double OBSTRUCTION_CLEAR_MAX_RESISTANCE = 60.0D;
private static final float OBSTRUCTION_CLEAR_DROP_CHANCE = 0.1F;
// Keep visual muzzle points separate from the centered multipart hitboxes.
// Geo mouth fronts are near z=-219, with side heads centered at x=+/-21. At 2x render scale,
// one model pixel is 1/8 block.
private static final double BEAM_MUZZLE_FORWARD = 27.375D;
private static final double BEAM_MUZZLE_CENTER_Y = 11.5D;
private static final double BEAM_MUZZLE_SIDE_Y = 10.25D;
private static final double BEAM_MUZZLE_LATERAL = 2.625D;
protected static final double FLYING_MIN_HOVER = 2.5D;
protected static final double FLYING_PREFERRED_HOVER = 6.0D;
@@ -111,6 +118,8 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.BOOLEAN);
private static final EntityDataAccessor<Integer> BEAM_ELEMENT =
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.INT);
private static final EntityDataAccessor<Integer> BEAM_HEAD_SLOT =
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.INT);
private static final EntityDataAccessor<Float> BEAM_END_X =
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.FLOAT);
private static final EntityDataAccessor<Float> BEAM_END_Y =
@@ -260,6 +269,7 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
builder.define(HAS_BEAM_END, false);
builder.define(ACCELERATED, false);
builder.define(BEAM_ELEMENT, RoyalBeamElement.GENERIC.ordinal());
builder.define(BEAM_HEAD_SLOT, -1);
builder.define(BEAM_END_X, 0.0F);
builder.define(BEAM_END_Y, 0.0F);
builder.define(BEAM_END_Z, 0.0F);
@@ -396,7 +406,8 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
if (this.activeBeamHead != null) {
LivingEntity beamTarget = this.activeBeamHead.target(this.level());
if (!this.activeBeamHead.shooting() || beamTarget == null || !beamTarget.isAlive()) {
if (!this.activeBeamHead.shooting() || beamTarget == null || !beamTarget.isAlive()
|| this.distanceTo(beamTarget) < this.royalBeamMinimumRange()) {
this.stopRoyalBeam();
} else if (!this.beamStarted) {
return;
@@ -406,14 +417,14 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
this.playRoyalSound(this.royalBeamLoopSound(), 1.0F);
}
this.beamController.tick(
this.headAnchor(this.activeBeamHead),
this.beamAnchor(this.activeBeamHead),
beamTarget,
this.royalBeamSettings(),
this.royalBeamTerrainMode(this.activeBeamHead),
this::setRoyalBeamEndPosition);
Vec3 beamEnd = this.beamController.beamEndPosition();
if (beamEnd != null) {
this.tickRoyalBeamEffects(this.activeBeamHead, this.headAnchor(this.activeBeamHead), beamEnd);
this.tickRoyalBeamEffects(this.activeBeamHead, this.beamAnchor(this.activeBeamHead), beamEnd);
}
if (!this.beamController.isFiring()) {
this.stopRoyalBeam();
@@ -431,6 +442,7 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
LivingEntity target = head.target(this.level());
if (!head.readyToAttack() || this.attackScheduler.laneBusy(this.headLane(head))
|| target == null || !this.canAttack(target)
|| this.distanceTo(target) < this.royalBeamMinimumRange()
|| this.headWithinBiteReach(head, target)) {
continue;
}
@@ -456,8 +468,9 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
}
RoyalBossEntity.this.beamStarted = true;
RoyalBossEntity.this.beamController.start(
RoyalBossEntity.this.headAnchor(head), committedTarget.getEyePosition(), duration);
RoyalBossEntity.this.beamAnchor(head), committedTarget.getEyePosition(), duration);
RoyalBossEntity.this.entityData.set(BEAM_ELEMENT, RoyalBossEntity.this.royalBeamElement(head).ordinal());
RoyalBossEntity.this.entityData.set(BEAM_HEAD_SLOT, head.slot().ordinal());
RoyalBossEntity.this.setFiringRoyalBeam(true);
RoyalBossEntity.this.triggerAnim(head.slot().controllerName(), "shoot");
RoyalBossEntity.this.beamLoopSoundTicks = 20;
@@ -493,6 +506,7 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
this.attackScheduler.cancel(this.beamLane());
this.beamController.stop();
this.entityData.set(BEAM_ELEMENT, RoyalBeamElement.GENERIC.ordinal());
this.entityData.set(BEAM_HEAD_SLOT, -1);
this.playRoyalSound(this.royalBeamEndSound(), 1.0F);
this.setFiringRoyalBeam(false);
this.setRoyalBeamEndPosition(null);
@@ -708,6 +722,30 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
this.getZ() + forward.z * spec.forwardOffset() + right.z * spec.lateralOffset());
}
protected Vec3 beamAnchor(RoyalHead head) {
return beamAnchor(head.slot(), this.getX(), this.getY(), this.getZ(), this.getYRot());
}
private Vec3 beamAnchor(RoyalHead.Slot slot, double x, double y, double z, float yaw) {
double yawRadians = yaw * Mth.DEG_TO_RAD;
Vec3 forward = new Vec3(-Math.sin(yawRadians), 0.0D, Math.cos(yawRadians));
Vec3 right = new Vec3(forward.z, 0.0D, -forward.x);
double lateral = switch (slot) {
case LEFT -> -BEAM_MUZZLE_LATERAL;
case CENTER -> 0.0D;
case RIGHT -> BEAM_MUZZLE_LATERAL;
};
double vertical = slot == RoyalHead.Slot.CENTER ? BEAM_MUZZLE_CENTER_Y : BEAM_MUZZLE_SIDE_Y;
return new Vec3(
x + forward.x * BEAM_MUZZLE_FORWARD + right.x * lateral,
y + vertical,
z + forward.z * BEAM_MUZZLE_FORWARD + right.z * lateral);
}
protected double royalBeamMinimumRange() {
return AntarchySettings.queenBeamMinimumRange();
}
protected RoyalHead royalHead(RoyalHead.Slot slot) {
return this.heads[slot.ordinal()];
}
@@ -826,8 +864,15 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
}
public Vec3 getRoyalBeamShootFrom(float partialTicks) {
if (this.activeBeamHead != null) {
return this.headAnchor(this.activeBeamHead);
int slotIndex = this.activeBeamHead != null
? this.activeBeamHead.slot().ordinal()
: this.entityData.get(BEAM_HEAD_SLOT);
if (slotIndex >= 0 && slotIndex < RoyalHead.Slot.values().length) {
double x = Mth.lerp(partialTicks, this.xo, this.getX());
double y = Mth.lerp(partialTicks, this.yo, this.getY());
double z = Mth.lerp(partialTicks, this.zo, this.getZ());
float yaw = Mth.rotLerp(partialTicks, this.yRotO, this.getYRot());
return this.beamAnchor(RoyalHead.Slot.values()[slotIndex], x, y, z, yaw);
}
double x = Mth.lerp(partialTicks, this.xo, this.getX());
double y = Mth.lerp(partialTicks, this.yo, this.getY()) + this.getBbHeight() * 0.72D;
@@ -842,18 +887,28 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
: RoyalBeamElement.GENERIC;
}
@Nullable
public RoyalHead.Slot getRoyalBeamHeadSlot() {
int slotIndex = this.activeBeamHead != null
? this.activeBeamHead.slot().ordinal()
: this.entityData.get(BEAM_HEAD_SLOT);
return slotIndex >= 0 && slotIndex < RoyalHead.Slot.values().length
? RoyalHead.Slot.values()[slotIndex]
: null;
}
@Override
public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
controllers.add(new AnimationController<>(this, "locomotion", 4, this::locomotionPredicate));
controllers.add(new AnimationController<>(this, "head_left", 0, RoyalBossEntity::headIdle)
.triggerableAnim("bite", RawAnimation.begin().thenPlay("bite_1"))
.triggerableAnim("shoot", RawAnimation.begin().thenPlay("shoot_1")));
controllers.add(new AnimationController<>(this, "head_center", 0, RoyalBossEntity::headIdle)
.triggerableAnim("bite", RawAnimation.begin().thenPlay("bite_2"))
.triggerableAnim("shoot", RawAnimation.begin().thenPlay("shoot_2")));
controllers.add(new AnimationController<>(this, "head_right", 0, RoyalBossEntity::headIdle)
.triggerableAnim("bite", RawAnimation.begin().thenPlay("bite_3"))
.triggerableAnim("shoot", RawAnimation.begin().thenPlay("shoot_3")));
controllers.add(new AnimationController<>(this, "head_center", 0, RoyalBossEntity::headIdle)
.triggerableAnim("bite", RawAnimation.begin().thenPlay("bite_1"))
.triggerableAnim("shoot", RawAnimation.begin().thenPlay("shoot_1")));
controllers.add(new AnimationController<>(this, "head_right", 0, RoyalBossEntity::headIdle)
.triggerableAnim("bite", RawAnimation.begin().thenPlay("bite_2"))
.triggerableAnim("shoot", RawAnimation.begin().thenPlay("shoot_2")));
controllers.add(new AnimationController<>(this, "body_action", 0, this::bodyActionPredicate)
.triggerableAnim("stomp", RawAnimation.begin().thenPlay("stomp"))
.triggerableAnim("wing_gust", RawAnimation.begin().thenPlay("wing_gust"))
@@ -9,11 +9,11 @@ public final class RoyalBossMultipartLayout implements MultipartLayout {
public static final MultipartPartDefinition BODY = new MultipartPartDefinition(
"body", 20.0F, 24.0F, 1.00F, 0.0D, 3.0D, 0.0D, true);
public static final MultipartPartDefinition LEFT_HEAD = new MultipartPartDefinition(
"left_head", 4.0F, 4.0F, 1.30F, 12.0D, 20.0D, -7.0D, true);
"left_head", 4.0F, 4.0F, 1.30F, 24.75D, 8.5D, -2.625D, true);
public static final MultipartPartDefinition CENTER_HEAD = new MultipartPartDefinition(
"center_head", 4.5F, 4.5F, 1.20F, 13.0D, 22.0D, 0.0D, true);
"center_head", 4.5F, 4.5F, 1.20F, 24.75D, 9.5D, 0.0D, true);
public static final MultipartPartDefinition RIGHT_HEAD = new MultipartPartDefinition(
"right_head", 4.0F, 4.0F, 1.30F, 12.0D, 20.0D, 7.0D, true);
"right_head", 4.0F, 4.0F, 1.30F, 24.75D, 8.5D, 2.625D, true);
public static final MultipartPartDefinition LEFT_WING = new MultipartPartDefinition(
"left_wing", 14.0F, 16.0F, 0.85F, -2.0D, 14.0D, -13.0D, true);
public static final MultipartPartDefinition RIGHT_WING = new MultipartPartDefinition(
@@ -6,9 +6,9 @@ import org.jetbrains.annotations.Nullable;
public final class RoyalHead {
public enum Slot {
LEFT(1, "head_left", "bite_1", "shoot_1"),
CENTER(2, "head_center", "bite_2", "shoot_2"),
RIGHT(3, "head_right", "bite_3", "shoot_3");
LEFT(1, "head_left", "bite_3", "shoot_3"),
CENTER(2, "head_center", "bite_1", "shoot_1"),
RIGHT(3, "head_right", "bite_2", "shoot_2");
private final int partIndex;
private final String controllerName;
@@ -22,8 +22,9 @@ import software.bernie.geckolib.animation.RawAnimation;
import software.bernie.geckolib.util.GeckoLibUtil;
public class RoyalIceSpikeEntity extends Entity implements GeoEntity {
private static final RawAnimation EMERGE_ANIMATION = RawAnimation.begin().thenPlay("ice_spike");
private static final RawAnimation IMPACT_ANIMATION = RawAnimation.begin().thenPlay("ice_spike_impact");
// The exported asset contains one coordinated animation for all four spike groups.
private static final RawAnimation SPIKE_ANIMATION = RawAnimation.begin().thenPlay("animation");
private static final String ANIMATION_CONTROLLER = "ice_spike";
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
private boolean impacted;
@@ -46,15 +47,14 @@ public class RoyalIceSpikeEntity extends Entity implements GeoEntity {
@Override
public void tick() {
super.tick();
if (!this.level().isClientSide && this.tickCount == 1) {
this.triggerAnim("ice_spike", "emerge");
if (this.tickCount == 1) {
this.triggerAnim(ANIMATION_CONTROLLER, "emerge");
}
if (!this.level().isClientSide && this.tickCount == 6 && !this.impacted) {
this.impacted = true;
this.impact((ServerLevel) this.level());
this.triggerAnim("ice_spike", "impact");
}
if (!this.level().isClientSide && this.tickCount > 45) {
if (!this.level().isClientSide && this.tickCount > 110) {
this.discard();
}
if (this.level().isClientSide && this.tickCount < 10) {
@@ -86,9 +86,8 @@ public class RoyalIceSpikeEntity extends Entity implements GeoEntity {
@Override
public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
controllers.add(new AnimationController<>(this, "ice_spike", 0, state -> PlayState.STOP)
.triggerableAnim("emerge", EMERGE_ANIMATION)
.triggerableAnim("impact", IMPACT_ANIMATION));
controllers.add(new AnimationController<>(this, ANIMATION_CONTROLLER, 0, state -> PlayState.STOP)
.triggerableAnim("emerge", SPIKE_ANIMATION));
}
@Override
@@ -75,6 +75,7 @@ public class WindVortexEntity extends Entity {
private static final double FALL_ACCELERATION = 0.006D;
private static final double MAX_FALL_SPEED = 0.08D;
private static final double MINIMUM_DOWNWARD_DRIFT = 0.012D;
private static final double ENTITY_FORCE_SPEED_SCALE = 0.5D;
private static final int FADE_OUT_TICKS = 8;
public enum VortexMode {
@@ -509,12 +510,14 @@ public class WindVortexEntity extends Entity {
case GATHER_RETURN -> (0.05D + progress * 0.08D) * massScale;
} * playerScale;
if (mode == VortexMode.UPWARD && entity.onGround()) {
axialSpeed = Math.max(axialSpeed, entity instanceof Player ? 0.38D : 0.3D);
axialSpeed = Math.max(axialSpeed,
(entity instanceof Player ? 0.38D : 0.3D) * ENTITY_FORCE_SPEED_SCALE);
}
Vec3 wanted = radial.scale(radialError * pull)
.add(tangent.scale(spin))
.add(basis.axis.scale(axialSpeed));
.add(basis.axis.scale(axialSpeed))
.scale(ENTITY_FORCE_SPEED_SCALE);
Vec3 current = entity.getDeltaMovement();
Vec3 updatedMovement = new Vec3(
Mth.lerp(0.72D, current.x, wanted.x),
@@ -522,10 +525,13 @@ public class WindVortexEntity extends Entity {
Mth.lerp(0.72D, current.z, wanted.z)
);
if (this.travelling) {
updatedMovement = updatedMovement.add(this.travelVelocity.x * 0.8D, 0.0D, this.travelVelocity.z * 0.8D);
updatedMovement = updatedMovement.add(
this.travelVelocity.x * 0.8D * ENTITY_FORCE_SPEED_SCALE,
0.0D,
this.travelVelocity.z * 0.8D * ENTITY_FORCE_SPEED_SCALE);
}
if (mode == VortexMode.UPWARD && entity.onGround()) {
double minRise = entity instanceof Player ? 0.38D : 0.3D;
double minRise = (entity instanceof Player ? 0.38D : 0.3D) * ENTITY_FORCE_SPEED_SCALE;
updatedMovement = new Vec3(updatedMovement.x, Math.max(updatedMovement.y, minRise), updatedMovement.z);
entity.setOnGround(false);
}
@@ -543,7 +549,9 @@ public class WindVortexEntity extends Entity {
Vec3 radial = radialVector.lengthSqr() < 1.0E-6D ? basis.sideA : radialVector.scale(1.0D / horizontal);
Vec3 tangent = basis.axis.cross(radial).normalize();
double scale = this.launchStrength * Mth.clamp(this.getVortexHeight() / 5.0D, 0.5D, 2.5D);
entity.setDeltaMovement(tangent.scale(0.72D * scale).add(radial.scale(0.34D * scale)).add(basis.axis.scale((0.78D + progress * 0.28D) * scale)));
entity.setDeltaMovement(tangent.scale(0.72D * scale * ENTITY_FORCE_SPEED_SCALE)
.add(radial.scale(0.34D * scale * ENTITY_FORCE_SPEED_SCALE))
.add(basis.axis.scale((0.78D + progress * 0.28D) * scale * ENTITY_FORCE_SPEED_SCALE)));
entity.hasImpulse = true;
this.syncPlayerMotion(entity);
}
@@ -575,8 +583,8 @@ public class WindVortexEntity extends Entity {
Vec3 toOwner = target.subtract(entity.position());
double distance = toOwner.length();
Vec3 direction = distance < 1.0E-4D ? new Vec3(0.0D, 1.0D, 0.0D) : toOwner.scale(1.0D / distance);
double arc = Mth.clamp(distance * 0.06D, 0.25D, 1.1D);
double power = this.launchStrength * Mth.clamp(distance / 6.0D, 0.6D, 2.0D);
double arc = Mth.clamp(distance * 0.06D, 0.25D, 1.1D) * ENTITY_FORCE_SPEED_SCALE;
double power = this.launchStrength * Mth.clamp(distance / 6.0D, 0.6D, 2.0D) * ENTITY_FORCE_SPEED_SCALE;
entity.setDeltaMovement(direction.scale(power).add(0.0D, arc, 0.0D));
entity.fallDistance = 0.0F;
entity.hasImpulse = true;
@@ -47,6 +47,7 @@ public class EyeOfTheStormItem extends Item implements GeoItem {
private static final String IDLE_CONTROLLER = "idle_controller";
private static final String IDLE_ANIMATION = "spinning_idle";
private static final Map<UUID, Long> LAST_UPDRAFT_TICK = new ConcurrentHashMap<>();
private static final Map<UUID, Long> LAST_SURGE_TICK = new ConcurrentHashMap<>();
private static final float SURGE_PROJECTILE_SPEED = 0.65F;
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
@@ -108,6 +109,13 @@ public class EyeOfTheStormItem extends Item implements GeoItem {
return;
}
long now = level.getGameTime();
Long last = LAST_SURGE_TICK.get(player.getUUID());
if (last != null && now - last < AntarchySettings.eyeOfTheStormSurgeCooldownTicks()) {
return;
}
LAST_SURGE_TICK.put(player.getUUID(), now);
Vec3 look = player.getViewVector(1.0F);
launchStormVortex(level, player.getEyePosition().add(look), look, player);
@@ -1,6 +1,11 @@
package com.craisinlord.antarchy.content.item;
import com.craisinlord.antarchy.content.effect.RoyalEffectHooks;
import com.craisinlord.antarchy.content.entity.royal.RoyalBlackHoleEntity;
import com.craisinlord.antarchy.config.AntarchySettings;
import java.util.List;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.EquipmentSlotGroup;
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
@@ -9,9 +14,19 @@ import net.minecraft.world.item.AxeItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Tier;
import net.minecraft.world.item.TooltipFlag;
import net.minecraft.world.item.component.ItemAttributeModifiers;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
public class RoyalAssailantBattleAxeItem extends AxeItem {
private static final int BLACK_HOLE_COOLDOWN_TICKS = 20 * 20;
private static final int DILATED_DURATION_TICKS = 100;
private static final ResourceLocation REACH_MODIFIER_ID = ResourceLocation.fromNamespaceAndPath("antarchy", "royal_assailant_battleaxe_reach");
private static final ResourceLocation KNOCKBACK_MODIFIER_ID = ResourceLocation.fromNamespaceAndPath("antarchy", "royal_assailant_battleaxe_knockback");
private final Tier tier;
@@ -46,4 +61,44 @@ public class RoyalAssailantBattleAxeItem extends AxeItem {
public int getEnchantmentValue() {
return AntarchySettings.royalWeaponEnchantability();
}
@Override
public void appendHoverText(ItemStack stack, Item.TooltipContext context, List<Component> tooltipComponents, TooltipFlag tooltipFlag) {
tooltipComponents.add(Component.translatable("tooltip.antarchy.royal_assailant_battleaxe.black_hole")
.withStyle(ChatFormatting.GOLD));
tooltipComponents.add(Component.translatable("tooltip.antarchy.royal_assailant_battleaxe.dilation")
.withStyle(ChatFormatting.GOLD));
super.appendHoverText(stack, context, tooltipComponents, tooltipFlag);
}
@Override
public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand hand) {
ItemStack stack = player.getItemInHand(hand);
if (player.getCooldowns().isOnCooldown(this)) {
return InteractionResultHolder.fail(stack);
}
if (level.isClientSide) {
return InteractionResultHolder.sidedSuccess(stack, true);
}
if (level instanceof ServerLevel serverLevel) {
RoyalBlackHoleEntity blackHole = RoyalBlackHoleEntity.createAssailant(
serverLevel,
player.position().add(player.getLookAngle().normalize().scale(2.0D)).add(0.0D, 2.0D, 0.0D),
player.getUUID());
serverLevel.addFreshEntity(blackHole);
player.getCooldowns().addCooldown(this, BLACK_HOLE_COOLDOWN_TICKS);
return InteractionResultHolder.success(stack);
}
return InteractionResultHolder.pass(stack);
}
@Override
public boolean hurtEnemy(ItemStack stack, LivingEntity target, LivingEntity attacker) {
boolean hurt = super.hurtEnemy(stack, target, attacker);
if (hurt && attacker instanceof Player player && !attacker.level().isClientSide
&& RoyalEffectHooks.dilatedHolder() != null) {
target.addEffect(new MobEffectInstance(RoyalEffectHooks.dilatedHolder(), DILATED_DURATION_TICKS), player);
}
return hurt;
}
}
@@ -1,13 +1,32 @@
package com.craisinlord.antarchy.content.item;
import com.craisinlord.antarchy.content.effect.RoyalEffectEligibility;
import com.craisinlord.antarchy.content.effect.RoyalEffectHooks;
import com.craisinlord.antarchy.config.AntarchySettings;
import java.util.List;
import java.util.Comparator;
import java.util.function.Supplier;
import net.minecraft.core.Holder;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.ShieldItem;
import net.minecraft.world.item.TooltipFlag;
import net.minecraft.network.chat.Component;
import net.minecraft.ChatFormatting;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.AABB;
public class RoyalGuardianShieldItem extends ShieldItem {
private static final int COMMAND_COOLDOWN_TICKS = 20 * 15;
private static final int COMMAND_DURATION_TICKS = 20 * 30;
private static final double COMMAND_RANGE = 16.0D;
private final Supplier<Ingredient> repairIngredient;
public RoyalGuardianShieldItem(Item.Properties properties, Supplier<Ingredient> repairIngredient) {
@@ -24,4 +43,37 @@ public class RoyalGuardianShieldItem extends ShieldItem {
public int getEnchantmentValue() {
return AntarchySettings.royalWeaponEnchantability();
}
@Override
public void appendHoverText(ItemStack stack, Item.TooltipContext context, List<Component> tooltipComponents, TooltipFlag tooltipFlag) {
tooltipComponents.add(Component.translatable("tooltip.antarchy.royal_guardian_shield.command")
.withStyle(ChatFormatting.GOLD));
super.appendHoverText(stack, context, tooltipComponents, tooltipFlag);
}
@Override
public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand hand) {
ItemStack stack = player.getItemInHand(hand);
if (player.getCooldowns().isOnCooldown(this)) {
return InteractionResultHolder.fail(stack);
}
if (level.isClientSide) {
return InteractionResultHolder.sidedSuccess(stack, true);
}
Holder<MobEffect> commanded = RoyalEffectHooks.commandedHolder();
if (commanded == null) {
return InteractionResultHolder.fail(stack);
}
Mob target = level.getEntitiesOfClass(Mob.class,
new AABB(player.blockPosition()).inflate(COMMAND_RANGE),
mob -> RoyalEffectEligibility.canApplyCommanded(mob))
.stream()
.min(Comparator.comparingDouble((Mob mob) -> player.distanceToSqr(mob)).thenComparingInt(Mob::getId))
.orElse(null);
if (target == null || !target.addEffect(new MobEffectInstance(commanded, COMMAND_DURATION_TICKS), player)) {
return InteractionResultHolder.fail(stack);
}
player.getCooldowns().addCooldown(this, COMMAND_COOLDOWN_TICKS);
return InteractionResultHolder.success(stack);
}
}
@@ -1,6 +1,9 @@
package com.craisinlord.antarchy.content.item;
import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.client.model.ResourceBackedGeoItemModel;
import com.craisinlord.antarchy.content.client.renderer.AnimatedHeldItemRenderer;
import java.util.function.Consumer;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.EquipmentSlotGroup;
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
@@ -10,15 +13,25 @@ import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.SwordItem;
import net.minecraft.world.item.Tier;
import net.minecraft.world.item.component.ItemAttributeModifiers;
import software.bernie.geckolib.animatable.GeoItem;
import software.bernie.geckolib.animatable.client.GeoRenderProvider;
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
import software.bernie.geckolib.animation.AnimatableManager;
import software.bernie.geckolib.util.GeckoLibUtil;
public class RoyalGuardianSwordItem extends SwordItem {
public class RoyalGuardianSwordItem extends SwordItem implements GeoItem {
private static final ResourceLocation MODEL_LOCATION = ResourceLocation.fromNamespaceAndPath("antarchy", "geo/royal_guardian_sword.geo.json");
private static final ResourceLocation TEXTURE_LOCATION = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/item/royal_guardian/royal_guardian_sword.png");
private static final ResourceLocation ANIMATION_LOCATION = ResourceLocation.fromNamespaceAndPath("antarchy", "animations/static_item.animation.json");
private static final ResourceLocation REACH_MODIFIER_ID = ResourceLocation.fromNamespaceAndPath("antarchy", "royal_guardian_sword_reach");
private static final ResourceLocation KNOCKBACK_MODIFIER_ID = ResourceLocation.fromNamespaceAndPath("antarchy", "royal_guardian_sword_knockback");
private final Tier tier;
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
public RoyalGuardianSwordItem(Tier tier, Item.Properties properties) {
super(tier, properties);
this.tier = tier;
GeoItem.registerSyncedAnimatable(this);
}
@Override
@@ -46,4 +59,29 @@ public class RoyalGuardianSwordItem extends SwordItem {
public int getEnchantmentValue() {
return AntarchySettings.royalWeaponEnchantability();
}
@Override
public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
}
@Override
public AnimatableInstanceCache getAnimatableInstanceCache() {
return this.geoCache;
}
@Override
public void createGeoRenderer(Consumer<GeoRenderProvider> consumer) {
consumer.accept(new GeoRenderProvider() {
private AnimatedHeldItemRenderer<RoyalGuardianSwordItem> renderer;
@Override
public net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer getGeoItemRenderer() {
if (this.renderer == null) {
this.renderer = new AnimatedHeldItemRenderer<>(new ResourceBackedGeoItemModel<>(MODEL_LOCATION, TEXTURE_LOCATION, ANIMATION_LOCATION));
}
return this.renderer;
}
});
}
}
@@ -16,6 +16,7 @@ public final class TimeDilationApi {
private static BiConsumer<ServerPlayer, List<TimeDilationFieldSnapshot>> fieldSyncDispatcher = (player, fields) -> {
};
private static final Map<UUID, Double> SYNCED_CLIENT_RATES = new ConcurrentHashMap<>();
private static final ThreadLocal<Integer> ROTATION_BYPASS_DEPTH = ThreadLocal.withInitial(() -> 0);
private TimeDilationApi() {
}
@@ -31,7 +32,15 @@ public final class TimeDilationApi {
}
public static TimeDilationFieldEntity createField(ServerLevel level, Vec3 center, double radius, double rate, int durationTicks) {
TimeDilationFieldEntity field = TimeDilationFieldEntity.create(level, center, radius, rate, durationTicks);
return createField(level, center, radius, rate, durationTicks, null);
}
public static TimeDilationFieldEntity createField(ServerLevel level, Vec3 center, double radius, double rate, int durationTicks, UUID ownerId) {
return createField(level, center, radius, rate, durationTicks, ownerId, true);
}
public static TimeDilationFieldEntity createField(ServerLevel level, Vec3 center, double radius, double rate, int durationTicks, UUID ownerId, boolean visual) {
TimeDilationFieldEntity field = TimeDilationFieldEntity.create(level, center, radius, rate, durationTicks, ownerId, visual);
level.addFreshEntity(field);
return field;
}
@@ -53,6 +62,29 @@ public final class TimeDilationApi {
return getRate(entity) < TimeDilationMath.NORMAL_RATE;
}
public static void enterRotationBypass() {
ROTATION_BYPASS_DEPTH.set(ROTATION_BYPASS_DEPTH.get() + 1);
}
public static void exitRotationBypass() {
int depth = ROTATION_BYPASS_DEPTH.get() - 1;
if (depth <= 0) {
ROTATION_BYPASS_DEPTH.remove();
} else {
ROTATION_BYPASS_DEPTH.set(depth);
}
}
public static boolean isRotationBypassed() {
return ROTATION_BYPASS_DEPTH.get() > 0;
}
public static void setInheritedRate(Entity entity, double rate) {
if (entity instanceof TimeDilationEntityAccess access) {
access.antarchy$setInheritedTimeDilationRate(rate);
}
}
public static void applySyncedRate(Entity entity, double rate) {
applySyncedRate(entity.getUUID(), rate);
if (entity instanceof TimeDilationEntityAccess access) {
@@ -68,7 +100,7 @@ public final class TimeDilationApi {
/** Clears both the authoritative entity state and any client-side UUID cache. */
public static void clearRate(Entity entity) {
if (entity instanceof TimeDilationEntityAccess access) {
boolean wasDilated = access.antarchy$getTimeDilationRate() < TimeDilationMath.NORMAL_RATE;
boolean wasDilated = Math.abs(access.antarchy$getTimeDilationRate() - TimeDilationMath.NORMAL_RATE) > 0.001D;
access.antarchy$setTimeDilationRate(TimeDilationMath.NORMAL_RATE);
if (wasDilated) {
syncEntityRate(entity, TimeDilationMath.NORMAL_RATE);
@@ -91,7 +123,7 @@ public final class TimeDilationApi {
public static boolean consumeTick(Entity entity, String timerKey) {
double rate = getRate(entity);
if (rate >= TimeDilationMath.NORMAL_RATE || !(entity instanceof TimeDilationEntityAccess access)) {
if (Math.abs(rate - TimeDilationMath.NORMAL_RATE) < 0.001D || !(entity instanceof TimeDilationEntityAccess access)) {
return true;
}
return access.antarchy$consumeTimeDilationTick(timerKey, rate);
@@ -99,7 +131,7 @@ public final class TimeDilationApi {
public static int scaleCooldownTicks(Entity entity, int ticks) {
double rate = getRate(entity);
if (ticks <= 0 || rate >= TimeDilationMath.NORMAL_RATE) {
if (ticks <= 0 || Math.abs(rate - TimeDilationMath.NORMAL_RATE) < 0.001D) {
return ticks;
}
return (int) Math.ceil(ticks / Math.max(TimeDilationMath.MIN_RATE, rate));
@@ -5,6 +5,10 @@ public interface TimeDilationEntityAccess {
void antarchy$setTimeDilationRate(double rate);
double antarchy$getInheritedTimeDilationRate();
void antarchy$setInheritedTimeDilationRate(double rate);
boolean antarchy$consumeTimeDilationTick(String timerKey, double rate);
boolean antarchy$isInTimeDilationMove();
@@ -9,6 +9,7 @@ import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import java.util.UUID;
public class TimeDilationFieldEntity extends Entity {
private static final EntityDataAccessor<Float> RADIUS =
@@ -23,6 +24,8 @@ public class TimeDilationFieldEntity extends Entity {
private int durationTicks = -1;
private int age;
private UUID ownerId;
private boolean visual = true;
public TimeDilationFieldEntity(EntityType<? extends TimeDilationFieldEntity> entityType, Level level) {
super(entityType, level);
@@ -31,14 +34,32 @@ public class TimeDilationFieldEntity extends Entity {
}
public static TimeDilationFieldEntity create(Level level, Vec3 center, double radius, double rate, int durationTicks) {
return create(level, center, radius, rate, durationTicks, null);
}
public static TimeDilationFieldEntity create(Level level, Vec3 center, double radius, double rate, int durationTicks, UUID ownerId) {
return create(level, center, radius, rate, durationTicks, ownerId, true);
}
public static TimeDilationFieldEntity create(Level level, Vec3 center, double radius, double rate, int durationTicks, UUID ownerId, boolean visual) {
TimeDilationFieldEntity field = new TimeDilationFieldEntity(AntarchyObjects.TIME_DILATION_FIELD.get(), level);
field.setPos(center.x, center.y, center.z);
field.setFieldRadius(radius);
field.setFieldRate(rate);
field.durationTicks = durationTicks;
field.ownerId = ownerId;
field.visual = visual;
return field;
}
public boolean isOwnedBy(Entity entity) {
return this.ownerId != null && entity != null && this.ownerId.equals(entity.getUUID());
}
public boolean isVisual() {
return this.visual;
}
@Override
protected void defineSynchedData(SynchedEntityData.Builder builder) {
builder.define(RADIUS, 8.0F);
@@ -105,6 +126,8 @@ public class TimeDilationFieldEntity extends Entity {
this.setFieldRate(tag.getDouble(RATE_KEY));
this.durationTicks = tag.contains(DURATION_KEY) ? tag.getInt(DURATION_KEY) : -1;
this.age = tag.getInt(AGE_KEY);
this.ownerId = tag.hasUUID("OwnerUuid") ? tag.getUUID("OwnerUuid") : null;
this.visual = !tag.contains("Visual") || tag.getBoolean("Visual");
}
@Override
@@ -113,5 +136,9 @@ public class TimeDilationFieldEntity extends Entity {
tag.putDouble(RATE_KEY, this.fieldRate());
tag.putInt(DURATION_KEY, this.durationTicks);
tag.putInt(AGE_KEY, this.age);
if (this.ownerId != null) {
tag.putUUID("OwnerUuid", this.ownerId);
}
tag.putBoolean("Visual", this.visual);
}
}
@@ -1,6 +1,7 @@
package com.craisinlord.antarchy.content.time;
import java.util.List;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.phys.Vec3;
public final class TimeDilationFieldSampler {
@@ -27,4 +28,23 @@ public final class TimeDilationFieldSampler {
}
return TimeDilationMath.clampRate(combinedRate);
}
public static double sample(List<TimeDilationFieldEntity> fields, Entity entity) {
double combinedRate = TimeDilationMath.NORMAL_RATE;
for (TimeDilationFieldEntity field : fields) {
if (field.isOwnedBy(entity)) {
continue;
}
Vec3 center = field.position();
double dx = center.x - entity.getX();
double dy = center.y - entity.getY();
double dz = center.z - entity.getZ();
double distanceSqr = dx * dx + dy * dy + dz * dz;
if (distanceSqr < field.fieldRadiusSqr()) {
double falloff = TimeDilationMath.gaussianFalloff(Math.sqrt(distanceSqr), field.fieldRadius());
combinedRate *= TimeDilationMath.localFieldRate(field.effectiveFieldRate(), falloff);
}
}
return TimeDilationMath.clampRate(combinedRate);
}
}
@@ -6,7 +6,11 @@ import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.projectile.Projectile;
import com.craisinlord.antarchy.content.effect.DilatedMobEffect;
import com.craisinlord.antarchy.content.effect.ContractedMobEffect;
import com.craisinlord.antarchy.content.effect.ContractedMobEffect;
import com.craisinlord.antarchy.content.effect.ContractedMobEffect;
import com.craisinlord.antarchy.content.effect.RoyalEffectEligibility;
import com.craisinlord.antarchy.content.effect.RoyalEffectHooks;
@@ -20,7 +24,7 @@ public final class TimeDilationManager {
syncFieldSnapshots(level, fields);
updateEntities(level, fields);
if (!fields.isEmpty()) {
TimeDilationParticles.spawnFieldBorders(level, fields);
TimeDilationParticles.spawnFieldBorders(level, fields.stream().filter(TimeDilationFieldEntity::isVisual).toList());
}
}
}
@@ -61,18 +65,55 @@ public final class TimeDilationManager {
continue;
}
double previousRate = access.antarchy$getTimeDilationRate();
double fieldRate = TimeDilationFieldSampler.sample(fields, entity.position());
double effectRate = RoyalEffectHooks.dilatedHolder() != null
&& entity instanceof net.minecraft.world.entity.LivingEntity living
&& living.hasEffect(RoyalEffectHooks.dilatedHolder())
? DilatedMobEffect.RATE : TimeDilationMath.NORMAL_RATE;
double rate = Math.min(fieldRate, effectRate);
if (rate >= TimeDilationMath.NORMAL_RATE) {
double fieldRate = TimeDilationFieldSampler.sample(fields, entity);
double effectRate = TimeDilationMath.NORMAL_RATE;
if (RoyalEffectHooks.dilatedHolder() != null
&& entity instanceof net.minecraft.world.entity.LivingEntity living) {
var effect = living.getEffect(RoyalEffectHooks.dilatedHolder());
if (effect != null) {
effectRate = DilatedMobEffect.rateForAmplifier(effect.getAmplifier());
}
}
if (RoyalEffectHooks.contractedHolder() != null
&& entity instanceof net.minecraft.world.entity.LivingEntity living) {
var effect = living.getEffect(RoyalEffectHooks.contractedHolder());
if (effect != null) {
effectRate = Math.max(effectRate, ContractedMobEffect.rateForAmplifier(effect.getAmplifier()));
}
}
double inheritedRate = access.antarchy$getInheritedTimeDilationRate();
if (entity instanceof Projectile projectile && projectile.getOwner() != null) {
double ownerRate = TimeDilationApi.getRate(projectile.getOwner());
inheritedRate = ownerRate < TimeDilationMath.NORMAL_RATE
? Math.min(inheritedRate, ownerRate)
: Math.max(inheritedRate, ownerRate);
}
double slowRate = TimeDilationMath.NORMAL_RATE;
double fastRate = TimeDilationMath.NORMAL_RATE;
if (fieldRate < TimeDilationMath.NORMAL_RATE) {
slowRate = Math.min(slowRate, fieldRate);
} else {
fastRate = Math.max(fastRate, fieldRate);
}
if (effectRate < TimeDilationMath.NORMAL_RATE) {
slowRate = Math.min(slowRate, effectRate);
} else {
fastRate = Math.max(fastRate, effectRate);
}
if (inheritedRate < TimeDilationMath.NORMAL_RATE) {
slowRate = Math.min(slowRate, inheritedRate);
} else {
fastRate = Math.max(fastRate, inheritedRate);
}
double targetRate = slowRate < TimeDilationMath.NORMAL_RATE ? slowRate : fastRate;
double rate = TimeDilationMath.transitionRate(previousRate, targetRate);
if (Math.abs(targetRate - TimeDilationMath.NORMAL_RATE) < 0.001D
&& Math.abs(rate - TimeDilationMath.NORMAL_RATE) < 0.001D) {
TimeDilationApi.clearRate(entity);
} else {
access.antarchy$setTimeDilationRate(rate);
}
if (rate < TimeDilationMath.NORMAL_RATE && Math.abs(previousRate - rate) > 0.001D) {
if (Math.abs(previousRate - rate) > 0.001D) {
TimeDilationApi.syncEntityRate(entity, rate);
}
}
@@ -3,7 +3,9 @@ package com.craisinlord.antarchy.content.time;
public final class TimeDilationMath {
public static final double MIN_RATE = 0.05D;
public static final double NORMAL_RATE = 1.0D;
public static final double MAX_RATE = 3.0D;
public static final int FIELD_TRANSITION_TICKS = 20;
public static final int EFFECT_TRANSITION_TICKS = 20;
private static final double GAUSSIAN_EDGE_EXPONENT = -4.5D;
private TimeDilationMath() {
@@ -13,7 +15,16 @@ public final class TimeDilationMath {
if (Double.isNaN(rate) || Double.isInfinite(rate)) {
return NORMAL_RATE;
}
return Math.max(MIN_RATE, Math.min(NORMAL_RATE, rate));
return Math.max(MIN_RATE, Math.min(MAX_RATE, rate));
}
/** Moves an entity's effective rate toward a new effect/field target without a hard step. */
public static double transitionRate(double currentRate, double targetRate) {
double current = clampRate(currentRate);
double target = clampRate(targetRate);
double maximumStep = (MAX_RATE - MIN_RATE) / EFFECT_TRANSITION_TICKS;
double delta = Math.max(-maximumStep, Math.min(maximumStep, target - current));
return clampRate(current + delta);
}
public static double gaussianFalloff(double distance, double radius) {
@@ -2,6 +2,7 @@ package com.craisinlord.antarchy.mixins;
import com.craisinlord.antarchy.content.effect.CommandedEntityAccess;
import com.craisinlord.antarchy.content.effect.RoyalEffectEligibility;
import com.craisinlord.antarchy.content.entity.royal.RoyalBossEntity;
import java.util.UUID;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.Entity;
@@ -37,19 +38,19 @@ public abstract class LivingEntityRoyalEffectsMixin {
cir.setReturnValue(false);
return;
}
PlayerSource playerSource = antarchy$resolvePlayer(source);
if (playerSource == null) {
Entity commander = antarchy$resolveCommander(source);
if (commander == null) {
cir.setReturnValue(false);
return;
}
CommandedEntityAccess access = (CommandedEntityAccess) mob;
UUID current = access.antarchy$getCommanderUuid();
if (current != null && !current.equals(playerSource.player().getUUID())) {
if (current != null && !current.equals(commander.getUUID())) {
cir.setReturnValue(false);
return;
}
antarchy$previousCommander = current;
access.antarchy$setCommanderUuid(playerSource.player().getUUID());
access.antarchy$setCommanderUuid(commander.getUUID());
}
@Inject(method = "addEffect(Lnet/minecraft/world/effect/MobEffectInstance;Lnet/minecraft/world/entity/Entity;)Z", at = @At("RETURN"))
@@ -71,20 +72,16 @@ public abstract class LivingEntityRoyalEffectsMixin {
}
@Unique
private PlayerSource antarchy$resolvePlayer(Entity source) {
private Entity antarchy$resolveCommander(Entity source) {
if (source instanceof net.minecraft.world.entity.player.Player player) {
return new PlayerSource(player);
return player;
}
if (source instanceof Projectile projectile && projectile.getOwner() instanceof net.minecraft.world.entity.player.Player player) {
return new PlayerSource(player);
return player;
}
if (source instanceof AreaEffectCloud cloud && cloud.getOwner() instanceof net.minecraft.world.entity.player.Player player) {
return new PlayerSource(player);
return player;
}
return null;
}
@Unique
private record PlayerSource(net.minecraft.world.entity.player.Player player) {
return source instanceof RoyalBossEntity ? source : null;
}
}
@@ -13,13 +13,13 @@ public abstract class AbstractArrowMovementTimeDilationMixin {
@Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/phys/Vec3;add(Lnet/minecraft/world/phys/Vec3;)Lnet/minecraft/world/phys/Vec3;"))
private Vec3 antarchy$slowCollisionPath(Vec3 position, Vec3 movement) {
double rate = TimeDilationApi.getRate((AbstractArrow) (Object) this);
return position.add(rate >= TimeDilationMath.NORMAL_RATE ? movement : movement.scale(rate));
return position.add(Math.abs(rate - TimeDilationMath.NORMAL_RATE) < 0.001D ? movement : movement.scale(rate));
}
@Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/AbstractArrow;setPos(DDD)V"))
private void antarchy$slowPosition(AbstractArrow arrow, double x, double y, double z) {
double rate = Math.max(TimeDilationMath.MIN_RATE, TimeDilationApi.getRate(arrow));
if (rate >= TimeDilationMath.NORMAL_RATE) {
if (Math.abs(rate - TimeDilationMath.NORMAL_RATE) < 0.001D) {
arrow.setPos(x, y, z);
return;
}
@@ -21,7 +21,7 @@ public abstract class EntityDeltaMovementTimeDilationMixin {
}
double rate = TimeDilationApi.getRate(entity);
if (rate >= TimeDilationMath.NORMAL_RATE) {
if (Math.abs(rate - TimeDilationMath.NORMAL_RATE) < 0.001D) {
return nextMovement;
}
@@ -32,7 +32,7 @@ public abstract class EntityMoveTimeDilationMixin {
private Vec3 antarchy$scaleTimeDilatedMovement(Vec3 movement) {
Entity entity = (Entity) (Object) this;
double rate = TimeDilationApi.getRate(entity);
if (rate >= TimeDilationMath.NORMAL_RATE) {
if (Math.abs(rate - TimeDilationMath.NORMAL_RATE) < 0.001D) {
return movement;
}
return movement.scale(rate);
@@ -13,6 +13,9 @@ public abstract class EntityRotationTimeDilationMixin {
@ModifyVariable(method = "setYRot", at = @At("HEAD"), argsOnly = true)
private float antarchy$slowYaw(float nextYaw) {
Entity entity = (Entity) (Object) this;
if (TimeDilationApi.isRotationBypassed()) {
return nextYaw;
}
double rate = TimeDilationApi.getRate(entity);
if (rate >= TimeDilationMath.NORMAL_RATE) {
return nextYaw;
@@ -23,6 +26,9 @@ public abstract class EntityRotationTimeDilationMixin {
@ModifyVariable(method = "setXRot", at = @At("HEAD"), argsOnly = true)
private float antarchy$slowPitch(float nextPitch) {
Entity entity = (Entity) (Object) this;
if (TimeDilationApi.isRotationBypassed()) {
return nextPitch;
}
double rate = TimeDilationApi.getRate(entity);
if (rate >= TimeDilationMath.NORMAL_RATE) {
return nextPitch;
@@ -13,6 +13,8 @@ public abstract class EntityTimeDilationStateMixin implements TimeDilationEntity
@Unique
private double antarchy$timeDilationRate = TimeDilationMath.NORMAL_RATE;
@Unique
private double antarchy$inheritedTimeDilationRate = TimeDilationMath.NORMAL_RATE;
@Unique
private final Map<String, Double> antarchy$timeDilationTimerProgress = new HashMap<>();
@Unique
private boolean antarchy$inTimeDilationMove;
@@ -32,10 +34,20 @@ public abstract class EntityTimeDilationStateMixin implements TimeDilationEntity
}
}
@Override
public double antarchy$getInheritedTimeDilationRate() {
return this.antarchy$inheritedTimeDilationRate;
}
@Override
public void antarchy$setInheritedTimeDilationRate(double rate) {
this.antarchy$inheritedTimeDilationRate = TimeDilationMath.clampRate(rate);
}
@Override
public boolean antarchy$consumeTimeDilationTick(String timerKey, double rate) {
double clampedRate = TimeDilationMath.clampRate(rate);
if (clampedRate >= TimeDilationMath.NORMAL_RATE) {
if (Math.abs(clampedRate - TimeDilationMath.NORMAL_RATE) < 0.001D) {
return true;
}
@@ -12,7 +12,7 @@ public abstract class HurtingProjectileMovementTimeDilationMixin {
@Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/AbstractHurtingProjectile;setPos(DDD)V"))
private void antarchy$slowPosition(AbstractHurtingProjectile projectile, double x, double y, double z) {
double rate = Math.max(TimeDilationMath.MIN_RATE, TimeDilationApi.getRate(projectile));
if (rate >= TimeDilationMath.NORMAL_RATE) {
if (Math.abs(rate - TimeDilationMath.NORMAL_RATE) < 0.001D) {
projectile.setPos(x, y, z);
return;
}
@@ -4,7 +4,6 @@ import com.craisinlord.antarchy.content.time.TimeDilationApi;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
@@ -20,22 +19,6 @@ public abstract class LivingEntityTimeDilationMixin {
}
}
@Inject(method = "tickEffects", at = @At("HEAD"), cancellable = true)
private void antarchy$slowEffectTicks(CallbackInfo ci) {
Entity entity = (Entity) (Object) this;
if (!TimeDilationApi.consumeTick(entity, "living_effects")) {
ci.cancel();
}
}
@Inject(method = "updatingUsingItem", at = @At("HEAD"), cancellable = true)
private void antarchy$slowUsingItem(CallbackInfo ci) {
Entity entity = (Entity) (Object) this;
if (!TimeDilationApi.consumeTick(entity, "living_using_item")) {
ci.cancel();
}
}
@Inject(method = "swing(Lnet/minecraft/world/InteractionHand;Z)V", at = @At("HEAD"), cancellable = true)
private void antarchy$slowSwingStart(InteractionHand hand, boolean updateSelf, CallbackInfo ci) {
Entity entity = (Entity) (Object) this;
@@ -44,11 +27,4 @@ public abstract class LivingEntityTimeDilationMixin {
}
}
@Inject(method = "updateUsingItem", at = @At("HEAD"), cancellable = true)
private void antarchy$slowItemUseProgress(ItemStack stack, CallbackInfo ci) {
Entity entity = (Entity) (Object) this;
if (!TimeDilationApi.consumeTick(entity, "living_item_use_progress")) {
ci.cancel();
}
}
}
@@ -1,10 +1,18 @@
package com.craisinlord.antarchy.mixins.time;
import com.craisinlord.antarchy.content.client.ClientTimeDilationTicker;
import com.craisinlord.antarchy.content.time.TimeDilationApi;
import com.craisinlord.antarchy.content.time.TimeDilationMath;
import com.craisinlord.antarchy.content.effect.ContractedMobEffect;
import com.craisinlord.antarchy.content.effect.DilatedMobEffect;
import com.craisinlord.antarchy.content.effect.RoyalEffectHooks;
import com.craisinlord.antarchy.mixins.client.EntityBoundSoundInstanceAccessor;
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
import net.minecraft.client.resources.sounds.SoundInstance;
import net.minecraft.client.sounds.SoundEngine;
import net.minecraft.client.Minecraft;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@@ -13,9 +21,40 @@ public abstract class SoundEngineTimeDilationMixin {
@ModifyReturnValue(method = "calculatePitch", at = @At("RETURN"))
private float antarchy$dilatePitch(float pitch, SoundInstance sound) {
double rate = ClientTimeDilationTicker.rateAt(sound.getX(), sound.getY(), sound.getZ());
if (rate >= TimeDilationMath.NORMAL_RATE) {
if (sound instanceof EntityBoundSoundInstanceAccessor accessor) {
double entityRate = rateForEntity(accessor.antarchy$getEntity());
rate = combineRates(rate, entityRate);
}
Minecraft minecraft = Minecraft.getInstance();
if (minecraft.player != null) {
double listenerRate = rateForEntity(minecraft.player);
rate = combineRates(rate, listenerRate);
}
if (Math.abs(rate - TimeDilationMath.NORMAL_RATE) < 0.001D) {
return pitch;
}
return (float) (pitch * Math.max(TimeDilationMath.MIN_RATE, rate));
}
private static double combineRates(double first, double second) {
if (first < TimeDilationMath.NORMAL_RATE || second < TimeDilationMath.NORMAL_RATE) {
return Math.min(first, second);
}
return Math.max(first, second);
}
private static double rateForEntity(Entity entity) {
double rate = TimeDilationApi.getRate(entity);
if (entity instanceof LivingEntity living) {
if (RoyalEffectHooks.dilatedHolder() != null && living.hasEffect(RoyalEffectHooks.dilatedHolder())) {
rate = Math.min(rate, DilatedMobEffect.rateForAmplifier(
living.getEffect(RoyalEffectHooks.dilatedHolder()).getAmplifier()));
}
if (RoyalEffectHooks.contractedHolder() != null && living.hasEffect(RoyalEffectHooks.contractedHolder())) {
rate = combineRates(rate, ContractedMobEffect.rateForAmplifier(
living.getEffect(RoyalEffectHooks.contractedHolder()).getAmplifier()));
}
}
return rate;
}
}
@@ -12,7 +12,7 @@ public abstract class ThrowableProjectileMovementTimeDilationMixin {
@Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/ThrowableProjectile;setPos(DDD)V"))
private void antarchy$slowPosition(ThrowableProjectile projectile, double x, double y, double z) {
double rate = Math.max(TimeDilationMath.MIN_RATE, TimeDilationApi.getRate(projectile));
if (rate >= TimeDilationMath.NORMAL_RATE) {
if (Math.abs(rate - TimeDilationMath.NORMAL_RATE) < 0.001D) {
projectile.setPos(x, y, z);
return;
}
@@ -88,6 +88,7 @@
"time.EntityMoveTimeDilationMixin",
"time.EntityTimeDilationStateMixin",
"time.EntityRotationTimeDilationMixin",
"time.EntityCrouchTimeDilationMixin",
"time.LivingEntityKnockbackTimeDilationMixin",
"time.CreeperTimeDilationMixin",
"time.EndCrystalTimeDilationMixin",
@@ -101,9 +102,11 @@
"time.AbstractArrowMovementTimeDilationMixin",
"time.ThrowableProjectileMovementTimeDilationMixin",
"time.HurtingProjectileMovementTimeDilationMixin",
"time.ProjectileTimeDilationMixin",
"time.AbstractArrowActionTimeDilationMixin",
"time.RangedAttackGoalTimeDilationMixin",
"time.RangedBowAttackGoalTimeDilationMixin"
"time.RangedBowAttackGoalTimeDilationMixin",
"time.GeckoLibAnimationControllerTimeDilationMixin"
],
"client": [
"client.AbstractMinecartRendererMixin",
@@ -117,6 +120,8 @@
"client.ElytraModelAccessor",
"client.FrogRendererElythiaMixin",
"client.GameRendererSwingThroughGrassMixin",
"client.EntityBoundSoundInstanceAccessor",
"client.InventoryScreenRotationBypassMixin",
"client.ExperimentalSettingsPopupMixin",
"client.KrakensGraspChargePoseMixin",
"client.LightningBoltRendererMixin",
@@ -2,40 +2,35 @@
"variants": {
"thickness=base,vertical_direction=down": {
"model": "antarchy:block/typhonite_spike_down_base",
"x": 180,
"uvlock": true
"x": 180
},
"thickness=base,vertical_direction=up": {
"model": "antarchy:block/typhonite_spike_up_base"
},
"thickness=frustum,vertical_direction=down": {
"model": "antarchy:block/typhonite_spike_down_frustum",
"x": 180,
"uvlock": true
"x": 180
},
"thickness=frustum,vertical_direction=up": {
"model": "antarchy:block/typhonite_spike_up_frustum"
},
"thickness=middle,vertical_direction=down": {
"model": "antarchy:block/typhonite_spike_down_middle",
"x": 180,
"uvlock": true
"x": 180
},
"thickness=middle,vertical_direction=up": {
"model": "antarchy:block/typhonite_spike_up_middle"
},
"thickness=tip,vertical_direction=down": {
"model": "antarchy:block/typhonite_spike_down_tip",
"x": 180,
"uvlock": true
"x": 180
},
"thickness=tip,vertical_direction=up": {
"model": "antarchy:block/typhonite_spike_up_tip"
},
"thickness=tip_merge,vertical_direction=down": {
"model": "antarchy:block/typhonite_spike_down_tip_merge",
"x": 180,
"uvlock": true
"x": 180
},
"thickness=tip_merge,vertical_direction=up": {
"model": "antarchy:block/typhonite_spike_up_tip_merge"
@@ -494,8 +494,23 @@
{"origin": [19, 0, 13], "size": [5, 6, 7], "uv": [466, 173], "mirror": true},
{"origin": [24, 0, 9], "size": [6, 10, 13], "inflate": 0.01, "uv": [38, 249], "mirror": true}
]
},
{
"name": "beam_anchor_center",
"parent": "head",
"pivot": [0, 91.5, -219]
},
{
"name": "beam_anchor_left",
"parent": "L_head",
"pivot": [21, 82.5, -219]
},
{
"name": "beam_anchor_right",
"parent": "R_head",
"pivot": [-21, 82.5, -219]
}
]
}
]
}
}
@@ -473,8 +473,23 @@
{"origin": [19, 0, 13], "size": [5, 6, 7], "uv": [466, 173], "mirror": true},
{"origin": [24, 0, 9], "size": [6, 10, 13], "inflate": 0.01, "uv": [38, 249], "mirror": true}
]
},
{
"name": "beam_anchor_center",
"parent": "head",
"pivot": [0, 91.5, -219]
},
{
"name": "beam_anchor_left",
"parent": "L_head",
"pivot": [21, 82.5, -219]
},
{
"name": "beam_anchor_right",
"parent": "R_head",
"pivot": [-21, 82.5, -219]
}
]
}
]
}
}
@@ -533,6 +533,8 @@
"effect.antarchy.paralyzed.description": "Verhindert, dass sich Ziele bewegen.",
"effect.antarchy.inverted": "Umgekehrt",
"effect.antarchy.inverted.description": "Kehrt die Schwerkraft des Ziels um.",
"effect.antarchy.commanded.description": "Kämpft für den Spieler, der das Ziel kommandiert hat.",
"effect.antarchy.dilated.description": "Verlangsamt den Zeitablauf für das betroffene Wesen.",
"effect.antarchy.stinky": "Stinkend",
"effect.antarchy.stinky.description": "Vertreibt passive und neutrale Kreaturen und zieht Gliederfüßer an.",
"effect.antarchy.gooped.description": "Verlangsamt Bewegung und Angriffsgeschwindigkeit.",
@@ -543,6 +543,9 @@
"item.antarchy.royal_assailant_battleaxe": "Royal Assailant Battle Axe",
"item.antarchy.royal_assailant_staff": "Royal Assailant Staff",
"tooltip.antarchy.royal_assailant_staff": "Opens paired tears that summon four allied Manticores for 30 seconds.",
"tooltip.antarchy.royal_assailant_battleaxe.black_hole": "Use to create a Royal Black Hole",
"tooltip.antarchy.royal_assailant_battleaxe.dilation": "Hits apply Temporal Dilation",
"tooltip.antarchy.royal_guardian_shield.command": "Use to command the nearest mob",
"tooltip.antarchy.royal_assailant_chestplate.invert": "Press the inversion key to toggle inverted gravity on and off.",
"tooltip.antarchy.royal_assailant_boots.fall": "Cancels fall damage while falling upward.",
"item.antarchy.mantis_claw": "Mantis Claw",
@@ -753,8 +756,10 @@
"effect.antarchy.inverted.description": "Inverts the target's gravity.",
"effect.antarchy.commanded": "Commanded",
"effect.antarchy.commanded.description": "Fights for the player who commanded it.",
"effect.antarchy.dilated": "Dilated",
"effect.antarchy.dilated": "Temporal Dilation",
"effect.antarchy.dilated.description": "Slows the passage of time for the affected entity.",
"effect.antarchy.contracted": "Temporal Contraction",
"effect.antarchy.contracted.description": "Speeds the passage of time for the affected entity.",
"effect.antarchy.stinky": "Stinky",
"effect.antarchy.stinky.description": "Repels passive and neutral mobs, attracts arthropods.",
"effect.antarchy.gooped": "Gooped",
@@ -1084,14 +1089,22 @@
"item.minecraft.lingering_potion.effect.long_command": "Lingering Potion of Command",
"item.minecraft.tipped_arrow.effect.command": "Arrow of Command",
"item.minecraft.tipped_arrow.effect.long_command": "Arrow of Command",
"item.minecraft.potion.effect.time_dilation": "Potion of Time Dilation",
"item.minecraft.potion.effect.long_time_dilation": "Potion of Time Dilation",
"item.minecraft.splash_potion.effect.time_dilation": "Splash Potion of Time Dilation",
"item.minecraft.splash_potion.effect.long_time_dilation": "Splash Potion of Time Dilation",
"item.minecraft.lingering_potion.effect.time_dilation": "Lingering Potion of Time Dilation",
"item.minecraft.lingering_potion.effect.long_time_dilation": "Lingering Potion of Time Dilation",
"item.minecraft.tipped_arrow.effect.time_dilation": "Arrow of Time Dilation",
"item.minecraft.tipped_arrow.effect.long_time_dilation": "Arrow of Time Dilation",
"item.minecraft.potion.effect.time_dilation": "Potion of Temporal Dilation",
"item.minecraft.potion.effect.long_time_dilation": "Potion of Strong Temporal Dilation",
"item.minecraft.splash_potion.effect.time_dilation": "Splash Potion of Temporal Dilation",
"item.minecraft.splash_potion.effect.long_time_dilation": "Splash Potion of Strong Temporal Dilation",
"item.minecraft.lingering_potion.effect.time_dilation": "Lingering Potion of Temporal Dilation",
"item.minecraft.lingering_potion.effect.long_time_dilation": "Lingering Potion of Strong Temporal Dilation",
"item.minecraft.tipped_arrow.effect.time_dilation": "Arrow of Temporal Dilation",
"item.minecraft.tipped_arrow.effect.long_time_dilation": "Arrow of Strong Temporal Dilation",
"item.minecraft.potion.effect.time_contraction": "Potion of Temporal Contraction",
"item.minecraft.splash_potion.effect.time_contraction": "Splash Potion of Temporal Contraction",
"item.minecraft.lingering_potion.effect.time_contraction": "Lingering Potion of Temporal Contraction",
"item.minecraft.tipped_arrow.effect.time_contraction": "Arrow of Temporal Contraction",
"item.minecraft.potion.effect.long_time_contraction": "Potion of Strong Temporal Contraction",
"item.minecraft.splash_potion.effect.long_time_contraction": "Splash Potion of Strong Temporal Contraction",
"item.minecraft.lingering_potion.effect.long_time_contraction": "Lingering Potion of Strong Temporal Contraction",
"item.minecraft.tipped_arrow.effect.long_time_contraction": "Arrow of Strong Temporal Contraction",
"item.minecraft.potion.effect.paralysis": "Potion of Paralysis",
"item.minecraft.potion.effect.long_paralysis": "Potion of Paralysis",
"item.minecraft.splash_potion.effect.paralysis": "Splash Potion of Paralysis",
@@ -1150,6 +1163,12 @@
"item.minecraft.tipped_arrow.effect.strong_haste": "Arrow of Haste II",
"advancements.antarchy.cancel_out.title": "1 - 1 = ?",
"advancements.antarchy.cancel_out.description": "Have Growth and Shrinking active at the same time.",
"advancements.antarchy.enter_the_speed_force.title": "Enter the speed force",
"advancements.antarchy.enter_the_speed_force.description": "Gain Temporal Contraction.",
"advancements.antarchy.probably_wondering_how_i_got_here.title": "You're probably wondering how I got here",
"advancements.antarchy.probably_wondering_how_i_got_here.description": "Gain Temporal Dilation.",
"advancements.antarchy.temporal_contradiction.title": "Temporal Contradiction",
"advancements.antarchy.temporal_contradiction.description": "Have Temporal Dilation and Temporal Contraction active at the same time.",
"entity.antarchy.cheep": "Cheep",
"item.antarchy.cheep": "Cheep",
"item.antarchy.cheep_spawn_egg": "Cheep Spawn Egg",
@@ -1187,6 +1206,7 @@
"advancements.antarchy.mucus_obtained.description": "Obtain some Mucus.",
"block.antarchy.cavaryn_portal": "Cavaryn Portal",
"biome.antarchy.cavaryn_moleworm_caves": "Moleworm Caves",
"biome.antarchy.wormy_caves": "Wormy Caves",
"block.antarchy.termite_nest": "Termite Nest",
"block.antarchy.chitin_spike": "Chitin Spike",
"block.antarchy.chitin_block": "Chitin Block",
@@ -1196,7 +1216,7 @@
"block.antarchy.amber_moss_carpet": "Amber Moss Carpet",
"block.antarchy.amber_lichen": "Amber Lichen",
"block.antarchy.mucus": "Mucus",
"tooltip.antarchy.mucus_slippery": "Makes the block it's on slippery like ice",
"tooltip.antarchy.mucus_slippery": "Makes the block it's on even more slippery than ice",
"block.antarchy.bile_vein": "Bile Vein",
"block.antarchy.creepvine": "Creepvine",
"block.antarchy.creeping_horror_egg": "Creeping Horror Egg",
@@ -1408,4 +1428,5 @@
,"decree.antarchy.advance.subtitle": "Close on the King or be judged."
,"decree.antarchy.show_no_mercy": "SHOW NO MERCY"
,"decree.antarchy.show_no_mercy.subtitle": "Keep dealing damage."
,"menu.antarchy.royal_judgment": "Royal Judgment"
}
@@ -533,6 +533,8 @@
"effect.antarchy.paralyzed.description": "Impide que los objetivos se muevan.",
"effect.antarchy.inverted": "Invertido",
"effect.antarchy.inverted.description": "Invierte la gravedad del objetivo.",
"effect.antarchy.commanded.description": "Lucha por el jugador que lo comandó.",
"effect.antarchy.dilated.description": "Ralentiza el paso del tiempo para la criatura afectada.",
"effect.antarchy.stinky": "Apestoso",
"effect.antarchy.stinky.description": "Ahuyenta a las criaturas pasivas y neutrales, y atrae a los artrópodos.",
"effect.antarchy.gooped.description": "Reduce la velocidad de movimiento y de ataque.",
@@ -533,6 +533,8 @@
"effect.antarchy.paralyzed.description": "Empêche les cibles de se déplacer.",
"effect.antarchy.inverted": "Inversé",
"effect.antarchy.inverted.description": "Inverse la gravité de la cible.",
"effect.antarchy.commanded.description": "Combat pour le joueur qui l’a commandé.",
"effect.antarchy.dilated.description": "Ralentit le passage du temps pour l’entité affectée.",
"effect.antarchy.stinky": "Puant",
"effect.antarchy.stinky.description": "Repousse les créatures passives et neutres, et attire les arthropodes.",
"effect.antarchy.gooped.description": "Ralentit la vitesse de déplacement et d'attaque.",
@@ -533,6 +533,8 @@
"effect.antarchy.paralyzed.description": "Impedisce ai bersagli di muoversi.",
"effect.antarchy.inverted": "Invertito",
"effect.antarchy.inverted.description": "Inverte la gravità del bersaglio.",
"effect.antarchy.commanded.description": "Combatte per il giocatore che lo ha comandato.",
"effect.antarchy.dilated.description": "Rallenta il passare del tempo per l’entità colpita.",
"effect.antarchy.stinky": "Puzzolente",
"effect.antarchy.stinky.description": "Respinge le creature passive e neutrali e attira gli artropodi.",
"effect.antarchy.gooped.description": "Riduce la velocità di movimento e di attacco.",
@@ -533,6 +533,8 @@
"effect.antarchy.paralyzed.description": "対象が動けなくなります。",
"effect.antarchy.inverted": "重力反転",
"effect.antarchy.inverted.description": "対象の重力を反転させます。",
"effect.antarchy.commanded.description": "命令したプレイヤーのために戦います。",
"effect.antarchy.dilated.description": "影響を受けたエンティティの時間の流れを遅くします。",
"effect.antarchy.stinky": "悪臭",
"effect.antarchy.stinky.description": "友好的および中立のMobを遠ざけ、節足動物を引き寄せます。",
"effect.antarchy.gooped.description": "移動速度と攻撃速度を低下させます。",
@@ -533,6 +533,8 @@
"effect.antarchy.paralyzed.description": "대상이 움직이지 못하게 합니다.",
"effect.antarchy.inverted": "반전",
"effect.antarchy.inverted.description": "대상의 중력을 반전시킵니다.",
"effect.antarchy.commanded.description": "명령한 플레이어를 위해 싸웁니다.",
"effect.antarchy.dilated.description": "영향받은 개체의 시간 흐름을 늦춥니다.",
"effect.antarchy.stinky": "악취",
"effect.antarchy.stinky.description": "수동적 및 중립적 몹을 쫓아내고 절지동물을 끌어들입니다.",
"effect.antarchy.gooped.description": "이동 속도와 공격 속도를 늦춥니다.",
@@ -533,6 +533,8 @@
"effect.antarchy.paralyzed.description": "Impede que os alvos se movam.",
"effect.antarchy.inverted": "Invertido",
"effect.antarchy.inverted.description": "Inverte a gravidade do alvo.",
"effect.antarchy.commanded.description": "Luta pelo jogador que o comandou.",
"effect.antarchy.dilated.description": "Diminui a passagem do tempo para a entidade afetada.",
"effect.antarchy.stinky": "Fedido",
"effect.antarchy.stinky.description": "Afasta mobs passivos e neutros e atrai artrópodes.",
"effect.antarchy.gooped.description": "Reduz a velocidade de movimento e de ataque.",
@@ -504,6 +504,8 @@
"effect.antarchy.paralyzed.description": "Не дает целям двигаться.",
"effect.antarchy.inverted": "Инверсия",
"effect.antarchy.inverted.description": "Инвертирует гравитацию цели.",
"effect.antarchy.commanded.description": "Сражается за игрока, который им командует.",
"effect.antarchy.dilated.description": "Замедляет течение времени для существа под действием эффекта.",
"effect.antarchy.stinky": "Вонючесть",
"effect.antarchy.stinky.description": "Отпугивает мирных и нейтральных мобов, но притягивает членистоногих.",
"effect.antarchy.gooped.description": "Замедляет движение и скорость атаки.",
@@ -533,6 +533,8 @@
"effect.antarchy.paralyzed.description": "阻止目标移动。",
"effect.antarchy.inverted": "反转",
"effect.antarchy.inverted.description": "反转目标的重力。",
"effect.antarchy.commanded.description": "为命令它的玩家而战。",
"effect.antarchy.dilated.description": "减缓受影响生物的时间流逝。",
"effect.antarchy.stinky": "臭气",
"effect.antarchy.stinky.description": "驱赶被动和中立生物,吸引节肢生物。",
"effect.antarchy.gooped.description": "减缓移动速度和攻击速度。",
@@ -533,6 +533,8 @@
"effect.antarchy.paralyzed.description": "阻止目標移動。",
"effect.antarchy.inverted": "反轉",
"effect.antarchy.inverted.description": "反轉目標的重力。",
"effect.antarchy.commanded.description": "為命令它的玩家而戰。",
"effect.antarchy.dilated.description": "減緩受影響生物的時間流逝。",
"effect.antarchy.stinky": "臭氣",
"effect.antarchy.stinky.description": "驅趕被動與中立生物,吸引節肢生物。",
"effect.antarchy.gooped.description": "降低移動速度與攻擊速度。",
@@ -1,138 +1 @@
{
"parent": "builtin/entity",
"display": {
"thirdperson_righthand": {
"rotation": [
0,
0,
0
],
"translation": [
-5.25,
2.0,
-5
],
"scale": [
0.8,
0.8,
0.8
]
},
"thirdperson_lefthand": {
"rotation": [
0,
0,
0
],
"translation": [
-5.25,
2.0,
-5
],
"scale": [
0.8,
0.8,
0.8
]
},
"firstperson_righthand": {
"rotation": [
10,
0,
0
],
"translation": [
-1,
2.0,
0.5
],
"scale": [
0.6,
0.6,
0.6
]
},
"firstperson_lefthand": {
"rotation": [
10,
0,
0
],
"translation": [
-1,
2.0,
0.5
],
"scale": [
0.6,
0.6,
0.6
]
},
"ground": {
"translation": [
0,
2,
0
],
"scale": [
0.5,
0.5,
0.5
]
},
"gui": {
"rotation": [
30,
-135,
0
],
"translation": [
0.25,
-4.75,
0
],
"scale": [
0.85,
0.85,
0.85
]
},
"head": {
"translation": [
0,
0,
-8.25
]
},
"fixed": {
"rotation": [
90,
45,
90
],
"translation": [
5.25,
3.75,
0
]
},
"on_shelf": {
"rotation": [
90,
0,
90
],
"translation": [
8.25,
0,
0
],
"scale": [
1.3,
1.3,
1.3
]
}
}
}
{"parent":"builtin/entity"}
@@ -9,7 +9,7 @@
},
"display": {
"announce_to_chat": true,
"background": "antarchy:textures/block/myrmite/myrmite",
"background": "antarchy:textures/block/myrmite/myrmite.png",
"description": {
"translate": "advancements.antarchy.visit_cavaryn.description"
},
@@ -9,7 +9,7 @@
},
"display": {
"announce_to_chat": true,
"background": "antarchy:textures/block/ouranwood/mossy_ouranwood_log",
"background": "antarchy:textures/block/ouranwood/mossy_ouranwood_log.png",
"description": {
"translate": "advancements.antarchy.visit_elythia.description"
},
@@ -9,7 +9,7 @@
},
"display": {
"announce_to_chat": true,
"background": "antarchy:textures/block/nyxite",
"background": "antarchy:textures/block/nyxite.png",
"description": {
"translate": "advancements.antarchy.visit_thoraxis.description"
},
@@ -164,7 +164,7 @@
],
"humidity": [
-0.15,
1.0
0.45
],
"continentalness": [
-1.0,
@@ -186,6 +186,36 @@
},
"biome": "antarchy:cavaryn_moleworm_caves"
},
{
"parameters": {
"temperature": [
-1.0,
1.0
],
"humidity": [
0.45,
1.0
],
"continentalness": [
-1.0,
1.0
],
"erosion": [
-1.0,
1.0
],
"weirdness": [
-0.6,
0.9
],
"depth": [
0.15,
2.0
],
"offset": 0.0
},
"biome": "antarchy:wormy_caves"
},
{
"parameters": {
"temperature": [
@@ -57,12 +57,12 @@
{
"biome": "antarchy:butterfly_fields",
"parameters": {
"temperature": [0.55, 0.8],
"humidity": [0.82, 1.0],
"continentalness": [-0.93, 0.25],
"erosion": [-1.0, 0.65],
"weirdness": [0.75, 1.0],
"depth": [0.0, 0.25],
"temperature": [0.68, 0.78],
"humidity": [0.9, 1.0],
"continentalness": [0.05, 0.2],
"erosion": [0.05, 0.35],
"weirdness": [0.85, 1.0],
"depth": [0.0, 0.2],
"offset": 0.0
}
},
@@ -74,7 +74,7 @@
"continentalness": [0.25, 0.72],
"erosion": [-0.5, 0.55],
"weirdness": [-0.55, 0.62],
"depth": [0.0, 0.35],
"depth": [0.0, 1.0],
"offset": 0.0
}
},
@@ -3,24 +3,38 @@
"pools": [
{
"rolls": 1,
"conditions": [
{
"condition": "minecraft:match_tool",
"predicate": {
"components": {
"minecraft:enchantments": {
"levels": {
"minecraft:silk_touch": 1
}
}
}
}
}
],
"entries": [
{
"type": "minecraft:item",
"name": "antarchy:star_coral"
"type": "minecraft:alternatives",
"children": [
{
"type": "minecraft:item",
"conditions": [
{
"condition": "minecraft:match_tool",
"predicate": {
"components": {
"minecraft:enchantments": {
"levels": {
"minecraft:silk_touch": 1
}
}
}
}
}
],
"name": "antarchy:star_coral"
},
{
"type": "minecraft:item",
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
],
"name": "antarchy:star_coral"
}
]
}
]
}
@@ -32,7 +32,7 @@
"condition": "minecraft:survives_explosion"
}
],
"name": "antarchy:dead_star_coral_block"
"name": "antarchy:star_coral_block"
}
]
}
@@ -3,24 +3,38 @@
"pools": [
{
"rolls": 1,
"conditions": [
{
"condition": "minecraft:match_tool",
"predicate": {
"components": {
"minecraft:enchantments": {
"levels": {
"minecraft:silk_touch": 1
}
}
}
}
}
],
"entries": [
{
"type": "minecraft:item",
"name": "antarchy:star_coral_fan"
"type": "minecraft:alternatives",
"children": [
{
"type": "minecraft:item",
"conditions": [
{
"condition": "minecraft:match_tool",
"predicate": {
"components": {
"minecraft:enchantments": {
"levels": {
"minecraft:silk_touch": 1
}
}
}
}
}
],
"name": "antarchy:star_coral_fan"
},
{
"type": "minecraft:item",
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
],
"name": "antarchy:star_coral_fan"
}
]
}
]
}
@@ -3,24 +3,38 @@
"pools": [
{
"rolls": 1,
"conditions": [
{
"condition": "minecraft:match_tool",
"predicate": {
"components": {
"minecraft:enchantments": {
"levels": {
"minecraft:silk_touch": 1
}
}
}
}
}
],
"entries": [
{
"type": "minecraft:item",
"name": "antarchy:star_coral_fan"
"type": "minecraft:alternatives",
"children": [
{
"type": "minecraft:item",
"conditions": [
{
"condition": "minecraft:match_tool",
"predicate": {
"components": {
"minecraft:enchantments": {
"levels": {
"minecraft:silk_touch": 1
}
}
}
}
}
],
"name": "antarchy:star_coral_fan"
},
{
"type": "minecraft:item",
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
],
"name": "antarchy:star_coral_fan"
}
]
}
]
}
@@ -2,6 +2,7 @@
"values": [
"antarchy:cavaryn",
"antarchy:cavaryn_moleworm_caves",
"antarchy:wormy_caves",
"antarchy:glowcap_caves",
"antarchy:biowart_caves",
"antarchy:brooding_tunnels",
@@ -203,6 +203,59 @@
]
}
},
{
"type": "minecraft:condition",
"if_true": {
"type": "minecraft:biome",
"biome_is": ["antarchy:wormy_caves"]
},
"then_run": {
"type": "minecraft:sequence",
"sequence": [
{
"type": "minecraft:condition",
"if_true": {
"type": "minecraft:stone_depth",
"offset": 0,
"surface_type": "floor",
"add_surface_depth": false,
"secondary_depth_range": 0
},
"then_run": {
"type": "minecraft:condition",
"if_true": {
"type": "minecraft:noise_threshold",
"noise": "antarchy:surface_blend",
"min_threshold": -0.28,
"max_threshold": 0.18
},
"then_run": {
"type": "minecraft:block",
"result_state": {
"Name": "minecraft:mud"
}
}
}
},
{
"type": "minecraft:condition",
"if_true": {
"type": "minecraft:stone_depth",
"offset": 0,
"surface_type": "floor",
"add_surface_depth": true,
"secondary_depth_range": 0
},
"then_run": {
"type": "minecraft:block",
"result_state": {
"Name": "antarchy:loam"
}
}
}
]
}
},
{
"type": "minecraft:condition",
"if_true": {