Bile vein with temp texture, cysts and funal ouranwood forest biome
This commit is contained in:
1 parent
b416c96ea2
commit
aad8a1e1c5
52 files changed
+1361
-343
No files matched your search
@@ -225,6 +225,8 @@ public final class AntarchyObjects {
|
||||
public static Supplier<BlockEntityType<HushweedBlockEntity>> HUSHWEED_BLOCK_ENTITY = (Supplier<BlockEntityType<HushweedBlockEntity>>) UNBOUND;
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Supplier<SimpleParticleType> STINKY_GAS = (Supplier<SimpleParticleType>) UNBOUND;
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Supplier<SimpleParticleType> STINKY_FLY = (Supplier<SimpleParticleType>) UNBOUND;
|
||||
|
||||
private AntarchyObjects() {
|
||||
}
|
||||
@@ -316,6 +318,7 @@ public final class AntarchyObjects {
|
||||
Supplier<BlockEntityType<WaspNestBlockEntity>> waspNestBlockEntity,
|
||||
Supplier<BlockEntityType<HushweedBlockEntity>> hushweedBlockEntity,
|
||||
Supplier<SimpleParticleType> stinkyGas,
|
||||
Supplier<SimpleParticleType> stinkyFly,
|
||||
Supplier<Holder<Attribute>> doubleDamageChance,
|
||||
Supplier<Holder<Attribute>> bloodglassMaxHearts,
|
||||
Supplier<Holder<MobEffect>> bloodglassWard
|
||||
@@ -406,6 +409,7 @@ public final class AntarchyObjects {
|
||||
WASP_NEST_BLOCK_ENTITY = waspNestBlockEntity;
|
||||
HUSHWEED_BLOCK_ENTITY = hushweedBlockEntity;
|
||||
STINKY_GAS = stinkyGas;
|
||||
STINKY_FLY = stinkyFly;
|
||||
DOUBLE_DAMAGE_CHANCE = doubleDamageChance;
|
||||
BLOODGLASS_MAX_HEARTS = bloodglassMaxHearts;
|
||||
BLOODGLASS_WARD = bloodglassWard;
|
||||
|
||||
@@ -12,7 +12,6 @@ import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public final class StinkyBehavior {
|
||||
public static final int STINKY_EFFECT_DURATION_TICKS = 60;
|
||||
public static final double STINK_BUG_AURA_RADIUS = 5.0D;
|
||||
public static final double STINKY_NAUSEA_RADIUS = 4.0D;
|
||||
private static final int TRAIL_INTERVAL_TICKS = 4;
|
||||
@@ -59,6 +58,17 @@ public final class StinkyBehavior {
|
||||
entity.getBbWidth() * 0.12D,
|
||||
0.005D
|
||||
);
|
||||
serverLevel.sendParticles(
|
||||
AntarchyObjects.STINKY_FLY.get(),
|
||||
entity.getX(),
|
||||
entity.getY(0.45D),
|
||||
entity.getZ(),
|
||||
1,
|
||||
entity.getBbWidth() * 0.35D,
|
||||
entity.getBbHeight() * 0.2D,
|
||||
entity.getBbWidth() * 0.35D,
|
||||
0.0D
|
||||
);
|
||||
applyNearbyNausea(entity, STINKY_NAUSEA_RADIUS, STINKY_NAUSEA_DURATION_TICKS);
|
||||
if (entity.tickCount % REACTION_INTERVAL_TICKS == 0) {
|
||||
reactToStinkySource(entity);
|
||||
@@ -80,6 +90,17 @@ public final class StinkyBehavior {
|
||||
entity.getBbWidth() * 0.35D,
|
||||
0.045D
|
||||
);
|
||||
serverLevel.sendParticles(
|
||||
AntarchyObjects.STINKY_FLY.get(),
|
||||
entity.getX(),
|
||||
entity.getY(0.45D),
|
||||
entity.getZ(),
|
||||
Math.max(2, count / 6),
|
||||
entity.getBbWidth() * 0.45D,
|
||||
entity.getBbHeight() * 0.25D,
|
||||
entity.getBbWidth() * 0.45D,
|
||||
0.0D
|
||||
);
|
||||
applyNearbyNausea(entity, STINK_BUG_AURA_RADIUS, STINK_BUG_BURST_NAUSEA_DURATION_TICKS);
|
||||
}
|
||||
|
||||
@@ -108,6 +129,9 @@ public final class StinkyBehavior {
|
||||
mob -> mob.isAlive() && mob != source
|
||||
)) {
|
||||
if (mob.getType().is(EntityTypeTags.SENSITIVE_TO_BANE_OF_ARTHROPODS)) {
|
||||
if (source.getType().is(EntityTypeTags.SENSITIVE_TO_BANE_OF_ARTHROPODS)) {
|
||||
continue;
|
||||
}
|
||||
attractArthropod(mob, source);
|
||||
continue;
|
||||
}
|
||||
@@ -167,4 +191,5 @@ public final class StinkyBehavior {
|
||||
}
|
||||
return !mob.isAlliedTo(source);
|
||||
}
|
||||
|
||||
}
|
||||
+5
-3
@@ -2,6 +2,7 @@ package com.craisinlord.antarchy.content.block;
|
||||
|
||||
import com.craisinlord.antarchy.content.AntarchyObjects;
|
||||
import com.craisinlord.antarchy.content.entity.CreepingHorrorEntity;
|
||||
import com.craisinlord.antarchy.content.block.AmberMossBlock;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
@@ -87,7 +88,7 @@ public class CreepingHorrorEggBlock extends Block {
|
||||
|
||||
@Override
|
||||
protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
|
||||
if (!this.shouldUpdateHatchLevel(level)) {
|
||||
if (!this.shouldUpdateHatchLevel(level, pos)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -174,8 +175,9 @@ public class CreepingHorrorEggBlock extends Block {
|
||||
level.setBlock(pos, state.setValue(EGGS, eggs - 1), 2);
|
||||
}
|
||||
|
||||
private boolean shouldUpdateHatchLevel(Level level) {
|
||||
return level.random.nextInt(500) == 0;
|
||||
private boolean shouldUpdateHatchLevel(Level level, BlockPos pos) {
|
||||
boolean onAmberMoss = level.getBlockState(pos.below()).getBlock() instanceof AmberMossBlock;
|
||||
return level.random.nextInt(onAmberMoss ? 150 : 500) == 0;
|
||||
}
|
||||
|
||||
private boolean canDestroyEgg(Level level, Entity entity) {
|
||||
|
||||
+5
-3
@@ -2,6 +2,7 @@ package com.craisinlord.antarchy.content.block;
|
||||
|
||||
import com.craisinlord.antarchy.content.AntarchyObjects;
|
||||
import com.craisinlord.antarchy.content.entity.LurkingTerrorEntity;
|
||||
import com.craisinlord.antarchy.content.block.AmberMossBlock;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
@@ -87,7 +88,7 @@ public class LurkingTerrorEggBlock extends Block {
|
||||
|
||||
@Override
|
||||
protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
|
||||
if (!this.shouldUpdateHatchLevel(level)) {
|
||||
if (!this.shouldUpdateHatchLevel(level, pos)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -174,8 +175,9 @@ public class LurkingTerrorEggBlock extends Block {
|
||||
level.setBlock(pos, state.setValue(EGGS, eggs - 1), 2);
|
||||
}
|
||||
|
||||
private boolean shouldUpdateHatchLevel(Level level) {
|
||||
return level.random.nextInt(500) == 0;
|
||||
private boolean shouldUpdateHatchLevel(Level level, BlockPos pos) {
|
||||
boolean onAmberMoss = level.getBlockState(pos.below()).getBlock() instanceof AmberMossBlock;
|
||||
return level.random.nextInt(onAmberMoss ? 150 : 500) == 0;
|
||||
}
|
||||
|
||||
private boolean canDestroyEgg(Level level, Entity entity) {
|
||||
|
||||
+4
-1
@@ -111,8 +111,11 @@ public class LurkingTerrorEntity extends Monster implements GeoEntity {
|
||||
}
|
||||
return state.setAndContinue(ATTACK_LAND_ANIM);
|
||||
}
|
||||
if (!this.onGround()) {
|
||||
return state.setAndContinue(FLY_ANIM);
|
||||
}
|
||||
if (state.isMoving()) {
|
||||
return state.setAndContinue(this.onGround() ? WALK_ANIM : FLY_ANIM);
|
||||
return state.setAndContinue(WALK_ANIM);
|
||||
}
|
||||
return state.setAndContinue(IDLE_ANIM);
|
||||
}
|
||||
|
||||
+11
-4
@@ -334,11 +334,18 @@ public class OctopusBombEntity extends Monster implements GeoEntity {
|
||||
if (--this.wanderRetargetTicks <= 0) {
|
||||
this.wanderRetargetTicks = 40 + this.random.nextInt(40);
|
||||
float angle = this.random.nextFloat() * (float) (Math.PI * 2);
|
||||
this.wanderDx = Mth.cos(angle) * 0.1f;
|
||||
this.wanderDy = -0.05f + this.random.nextFloat() * 0.1f;
|
||||
this.wanderDz = Mth.sin(angle) * 0.1f;
|
||||
this.wanderDx = Mth.cos(angle) * 0.015f;
|
||||
this.wanderDz = Mth.sin(angle) * 0.015f;
|
||||
this.wanderDy = -0.01f + this.random.nextFloat() * 0.01f; // slight downward bias
|
||||
}
|
||||
this.setDeltaMovement(this.getDeltaMovement().add(this.wanderDx, this.wanderDy, this.wanderDz));
|
||||
|
||||
// Surface avoidance: if the block above is not water, push down
|
||||
float dy = this.wanderDy;
|
||||
if (!this.level().getFluidState(this.blockPosition().above()).is(net.minecraft.tags.FluidTags.WATER)) {
|
||||
dy = -0.03f;
|
||||
}
|
||||
|
||||
this.setDeltaMovement(this.getDeltaMovement().add(this.wanderDx, dy, this.wanderDz));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
+62
-31
@@ -4,6 +4,7 @@ import com.craisinlord.antarchy.content.AntarchyTags;
|
||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Vec3i;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
@@ -18,10 +19,21 @@ import software.bernie.geckolib.animatable.GeoEntity;
|
||||
|
||||
public class TermiteEntity extends BaseAntEntity implements GeoEntity {
|
||||
private static final int WOOD_BITE_ANIMATION_TICKS = 8;
|
||||
private static final int WOOD_SEARCH_INTERVAL_TICKS = 10;
|
||||
private static final int WOOD_SEARCH_INTERVAL_TICKS = 20;
|
||||
private static final int WOOD_REPATH_INTERVAL_TICKS = 6;
|
||||
private static final int WOOD_SEARCH_RADIUS_HORIZONTAL = 12;
|
||||
private static final int WOOD_SEARCH_RADIUS_VERTICAL = 4;
|
||||
private static final Vec3i[] IMMEDIATE_WOOD_OFFSETS = {
|
||||
new Vec3i(0, 1, 0),
|
||||
new Vec3i(0, 0, -1),
|
||||
new Vec3i(0, 0, 1),
|
||||
new Vec3i(1, 0, 0),
|
||||
new Vec3i(-1, 0, 0),
|
||||
new Vec3i(0, 1, -1),
|
||||
new Vec3i(0, 1, 1),
|
||||
new Vec3i(1, 1, 0),
|
||||
new Vec3i(-1, 1, 0),
|
||||
};
|
||||
@Nullable
|
||||
private BlockPos targetWoodPos;
|
||||
private int nextWoodSearchTick;
|
||||
@@ -125,7 +137,9 @@ public class TermiteEntity extends BaseAntEntity implements GeoEntity {
|
||||
}
|
||||
|
||||
private boolean tryEatNearbyWood() {
|
||||
for (BlockPos targetPos : this.getImmediateWoodChecks()) {
|
||||
BlockPos basePos = this.blockPosition();
|
||||
for (Vec3i offset : IMMEDIATE_WOOD_OFFSETS) {
|
||||
BlockPos targetPos = basePos.offset(offset);
|
||||
BlockState targetState = this.level().getBlockState(targetPos);
|
||||
if (!targetState.is(AntarchyTags.Blocks.TERMITE_FOODS)) {
|
||||
continue;
|
||||
@@ -141,22 +155,6 @@ public class TermiteEntity extends BaseAntEntity implements GeoEntity {
|
||||
return false;
|
||||
}
|
||||
|
||||
private BlockPos[] getImmediateWoodChecks() {
|
||||
BlockPos basePos = this.blockPosition();
|
||||
BlockPos abovePos = basePos.above();
|
||||
return new BlockPos[] {
|
||||
basePos.above(),
|
||||
basePos.north(),
|
||||
basePos.south(),
|
||||
basePos.east(),
|
||||
basePos.west(),
|
||||
abovePos.north(),
|
||||
abovePos.south(),
|
||||
abovePos.east(),
|
||||
abovePos.west()
|
||||
};
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private BlockPos getCurrentWoodTarget() {
|
||||
if (this.targetWoodPos != null && this.isValidWoodTarget(this.targetWoodPos)) {
|
||||
@@ -175,20 +173,52 @@ public class TermiteEntity extends BaseAntEntity implements GeoEntity {
|
||||
@Nullable
|
||||
private BlockPos findClosestWoodTarget() {
|
||||
BlockPos origin = this.blockPosition();
|
||||
int ox = origin.getX();
|
||||
int oy = origin.getY();
|
||||
int oz = origin.getZ();
|
||||
BlockPos bestPos = null;
|
||||
double bestDistance = Double.MAX_VALUE;
|
||||
double bestDistSq = Double.MAX_VALUE;
|
||||
BlockPos.MutableBlockPos candidate = new BlockPos.MutableBlockPos();
|
||||
|
||||
for (BlockPos pos : BlockPos.betweenClosed(
|
||||
origin.offset(-WOOD_SEARCH_RADIUS_HORIZONTAL, -WOOD_SEARCH_RADIUS_VERTICAL, -WOOD_SEARCH_RADIUS_HORIZONTAL),
|
||||
origin.offset(WOOD_SEARCH_RADIUS_HORIZONTAL, WOOD_SEARCH_RADIUS_VERTICAL + 2, WOOD_SEARCH_RADIUS_HORIZONTAL))) {
|
||||
if (!this.isValidWoodTarget(pos)) {
|
||||
continue;
|
||||
for (int r = 0; r <= WOOD_SEARCH_RADIUS_HORIZONTAL; r++) {
|
||||
if (bestPos != null && bestDistSq <= (double)(r * r)) {
|
||||
break;
|
||||
}
|
||||
|
||||
double distance = pos.distSqr(origin);
|
||||
if (distance < bestDistance) {
|
||||
bestDistance = distance;
|
||||
bestPos = pos.immutable();
|
||||
for (int dy = -WOOD_SEARCH_RADIUS_VERTICAL; dy <= WOOD_SEARCH_RADIUS_VERTICAL + 2; dy++) {
|
||||
if (r == 0) {
|
||||
candidate.set(ox, oy + dy, oz);
|
||||
if (this.isValidWoodTarget(candidate)) {
|
||||
double d = candidate.distSqr(origin);
|
||||
if (d < bestDistSq) { bestDistSq = d; bestPos = candidate.immutable(); }
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// North/South faces (dz = ±r)
|
||||
for (int dx = -r; dx <= r; dx++) {
|
||||
candidate.set(ox + dx, oy + dy, oz - r);
|
||||
if (this.isValidWoodTarget(candidate)) {
|
||||
double d = candidate.distSqr(origin);
|
||||
if (d < bestDistSq) { bestDistSq = d; bestPos = candidate.immutable(); }
|
||||
}
|
||||
candidate.set(ox + dx, oy + dy, oz + r);
|
||||
if (this.isValidWoodTarget(candidate)) {
|
||||
double d = candidate.distSqr(origin);
|
||||
if (d < bestDistSq) { bestDistSq = d; bestPos = candidate.immutable(); }
|
||||
}
|
||||
}
|
||||
// East/West faces (dx = ±r, corners already covered above)
|
||||
for (int dz = -r + 1; dz <= r - 1; dz++) {
|
||||
candidate.set(ox - r, oy + dy, oz + dz);
|
||||
if (this.isValidWoodTarget(candidate)) {
|
||||
double d = candidate.distSqr(origin);
|
||||
if (d < bestDistSq) { bestDistSq = d; bestPos = candidate.immutable(); }
|
||||
}
|
||||
candidate.set(ox + r, oy + dy, oz + dz);
|
||||
if (this.isValidWoodTarget(candidate)) {
|
||||
double d = candidate.distSqr(origin);
|
||||
if (d < bestDistSq) { bestDistSq = d; bestPos = candidate.immutable(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,9 +252,10 @@ public class TermiteEntity extends BaseAntEntity implements GeoEntity {
|
||||
}
|
||||
|
||||
private boolean isWalkableStandPos(BlockPos pos) {
|
||||
BlockState floorState = this.level().getBlockState(pos.below());
|
||||
BlockPos floor = pos.below();
|
||||
BlockState floorState = this.level().getBlockState(floor);
|
||||
return this.level().getBlockState(pos).isAir()
|
||||
&& this.level().getBlockState(pos.above()).isAir()
|
||||
&& floorState.isFaceSturdy(this.level(), pos.below(), Direction.UP);
|
||||
&& floorState.isFaceSturdy(this.level(), floor, Direction.UP);
|
||||
}
|
||||
}
|
||||
@@ -62,6 +62,14 @@ public class BigBerthaItem extends SwordItem implements GeoItem {
|
||||
private static final String SPIN_TICKS_TAG = "antarchy.big_bertha_spin_ticks";
|
||||
private static final String SPIN_DIRECTION_X_TAG = "antarchy.big_bertha_spin_direction_x";
|
||||
private static final String SPIN_DIRECTION_Z_TAG = "antarchy.big_bertha_spin_direction_z";
|
||||
private static final String TORETERROR_JUMPING_TAG = "antarchy.toreterror_jumping";
|
||||
private static final String TORETERROR_LAUNCHED_TAG = "antarchy.toreterror_launched";
|
||||
private static final int TORETERROR_LANDING_RADIUS = 6;
|
||||
private static final int TORETERROR_COOLDOWN_TICKS = 200;
|
||||
private static final int TORETERROR_SHAKE_TICKS = 25;
|
||||
|
||||
/** Client-side only: how many ticks of camera shake remain from a Toreterror landing. */
|
||||
public static int clientShakeTicks = 0;
|
||||
private static final ResourceLocation ATTACK_RANGE_MODIFIER_ID = ResourceLocation.fromNamespaceAndPath("antarchy", "big_bertha_attack_range");
|
||||
private final Tier tier;
|
||||
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
||||
@@ -116,6 +124,14 @@ public class BigBerthaItem extends SwordItem implements GeoItem {
|
||||
return InteractionResultHolder.sidedSuccess(stack, level.isClientSide);
|
||||
}
|
||||
|
||||
if (mode == BossMode.TORETERROR) {
|
||||
if (player.getCooldowns().isOnCooldown(this)) {
|
||||
return InteractionResultHolder.fail(stack);
|
||||
}
|
||||
startToreterrorJump(level, player, stack);
|
||||
return InteractionResultHolder.sidedSuccess(stack, level.isClientSide);
|
||||
}
|
||||
|
||||
if (mode != BossMode.MOLEVORE) {
|
||||
return InteractionResultHolder.pass(stack);
|
||||
}
|
||||
@@ -144,7 +160,7 @@ public class BigBerthaItem extends SwordItem implements GeoItem {
|
||||
case LUCID -> applyLucidHit(target, player, serverLevel);
|
||||
case NIGHTMARE -> applyNightmareHit(target, serverLevel);
|
||||
case KRAKEN -> applyKrakenHit(player, target, serverLevel);
|
||||
case MOLEVORE -> {
|
||||
case MOLEVORE, TORETERROR -> {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,6 +174,32 @@ public class BigBerthaItem extends SwordItem implements GeoItem {
|
||||
return;
|
||||
}
|
||||
|
||||
// Toreterror jump tracking
|
||||
if (isToreterrorJumping(stack) && player.getMainHandItem() == stack) {
|
||||
player.fallDistance = 0.0F; // prevent fall damage during the crash-down
|
||||
boolean launched = readInt(stack, TORETERROR_LAUNCHED_TAG) == 1;
|
||||
if (!launched && !player.onGround()) {
|
||||
CustomData.update(DataComponents.CUSTOM_DATA, stack, tag -> tag.putInt(TORETERROR_LAUNCHED_TAG, 1));
|
||||
}
|
||||
if (launched && player.onGround()) {
|
||||
CustomData.update(DataComponents.CUSTOM_DATA, stack, tag -> {
|
||||
tag.remove(TORETERROR_JUMPING_TAG);
|
||||
tag.remove(TORETERROR_LAUNCHED_TAG);
|
||||
});
|
||||
if (!level.isClientSide && player instanceof ServerPlayer serverPlayer) {
|
||||
applyToreterrorLanding((ServerLevel) level, serverPlayer);
|
||||
}
|
||||
if (level.isClientSide) {
|
||||
clientShakeTicks = TORETERROR_SHAKE_TICKS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tick client shake counter
|
||||
if (level.isClientSide && clientShakeTicks > 0) {
|
||||
clientShakeTicks--;
|
||||
}
|
||||
|
||||
int spinTicks = getSpinTicks(stack);
|
||||
if (spinTicks <= 0) {
|
||||
return;
|
||||
@@ -317,6 +359,43 @@ public class BigBerthaItem extends SwordItem implements GeoItem {
|
||||
}
|
||||
}
|
||||
|
||||
private void startToreterrorJump(Level level, Player player, ItemStack stack) {
|
||||
CustomData.update(DataComponents.CUSTOM_DATA, stack, tag -> {
|
||||
tag.putInt(TORETERROR_JUMPING_TAG, 1);
|
||||
tag.remove(TORETERROR_LAUNCHED_TAG);
|
||||
});
|
||||
player.setDeltaMovement(player.getDeltaMovement().x, 1.5D, player.getDeltaMovement().z);
|
||||
player.hasImpulse = true;
|
||||
player.fallDistance = 0.0F;
|
||||
player.getCooldowns().addCooldown(this, TORETERROR_COOLDOWN_TICKS);
|
||||
player.awardStat(Stats.ITEM_USED.get(this));
|
||||
level.playSound(null, player.blockPosition(), SoundEvents.GENERIC_EXPLODE.value(), SoundSource.PLAYERS, 1.0F, 0.6F);
|
||||
}
|
||||
|
||||
private void applyToreterrorLanding(ServerLevel level, ServerPlayer player) {
|
||||
ItemStack heldStack = player.getMainHandItem();
|
||||
float damage = (float) (player.getAttributeValue(Attributes.ATTACK_DAMAGE) * 2.0D);
|
||||
AABB aoe = player.getBoundingBox().inflate(TORETERROR_LANDING_RADIUS, 3.0D, TORETERROR_LANDING_RADIUS);
|
||||
for (LivingEntity victim : level.getEntitiesOfClass(LivingEntity.class, aoe,
|
||||
e -> e.isAlive() && e != player && !e.isSpectator())) {
|
||||
victim.hurt(player.damageSources().playerAttack(player), damage);
|
||||
Vec3 knockDir = victim.position().subtract(player.position()).multiply(1.0D, 0.0D, 1.0D);
|
||||
if (knockDir.lengthSqr() < 1.0E-4D) knockDir = player.getLookAngle().multiply(1.0D, 0.0D, 1.0D);
|
||||
Vec3 normalized = knockDir.normalize();
|
||||
victim.push(normalized.x * 2.5D, 0.6D, normalized.z * 2.5D);
|
||||
victim.hurtMarked = true;
|
||||
}
|
||||
level.playSound(null, player.blockPosition(), SoundEvents.GENERIC_EXPLODE.value(), SoundSource.PLAYERS, 1.5F, 0.75F);
|
||||
level.sendParticles(ParticleTypes.EXPLOSION, player.getX(), player.getY() + 0.5D, player.getZ(), 4, 1.5D, 0.3D, 1.5D, 0.0D);
|
||||
level.sendParticles(ParticleTypes.SPLASH, player.getX(), player.getY() + 0.5D, player.getZ(), 60, 3.0D, 0.5D, 3.0D, 0.2D);
|
||||
level.sendParticles(ParticleTypes.CRIT, player.getX(), player.getY() + 0.5D, player.getZ(), 20, 2.0D, 0.5D, 2.0D, 0.1D);
|
||||
heldStack.hurtAndBreak(1, player, EquipmentSlot.MAINHAND);
|
||||
}
|
||||
|
||||
private static boolean isToreterrorJumping(ItemStack stack) {
|
||||
return readInt(stack, TORETERROR_JUMPING_TAG) == 1;
|
||||
}
|
||||
|
||||
private void tickMolevoreSpin(ServerLevel level, ServerPlayer player, ItemStack stack, int spinTicks) {
|
||||
Vec3 direction = getStoredSpinDirection(stack);
|
||||
double verticalBoost = player.onGround() ? 0.08D : Math.max(-0.08D, player.getDeltaMovement().y);
|
||||
@@ -505,7 +584,8 @@ public class BigBerthaItem extends SwordItem implements GeoItem {
|
||||
NIGHTMARE(1, "tooltip.antarchy.big_bertha.mode.nightmare", "message.antarchy.big_bertha.mode.nightmare"),
|
||||
KRAKEN(2, "tooltip.antarchy.big_bertha.mode.kraken", "message.antarchy.big_bertha.mode.kraken"),
|
||||
MOLEVORE(3, "tooltip.antarchy.big_bertha.mode.molevore", "message.antarchy.big_bertha.mode.molevore"),
|
||||
LUCID(4, "tooltip.antarchy.big_bertha.mode.lucid", "message.antarchy.big_bertha.mode.lucid");
|
||||
LUCID(4, "tooltip.antarchy.big_bertha.mode.lucid", "message.antarchy.big_bertha.mode.lucid"),
|
||||
TORETERROR(5, "tooltip.antarchy.big_bertha.mode.toreterror", "message.antarchy.big_bertha.mode.toreterror");
|
||||
|
||||
private final int id;
|
||||
private final String tooltipKey;
|
||||
@@ -523,7 +603,8 @@ public class BigBerthaItem extends SwordItem implements GeoItem {
|
||||
case LUCID -> NIGHTMARE;
|
||||
case NIGHTMARE -> KRAKEN;
|
||||
case KRAKEN -> MOLEVORE;
|
||||
case MOLEVORE -> BASILISK;
|
||||
case MOLEVORE -> TORETERROR;
|
||||
case TORETERROR -> BASILISK;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+196
@@ -0,0 +1,196 @@
|
||||
package com.craisinlord.antarchy.content.worldgen.cavaryn;
|
||||
|
||||
import com.craisinlord.antarchy.Antarchy;
|
||||
import com.mojang.serialization.Codec;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.level.WorldGenLevel;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.LiquidBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.levelgen.feature.Feature;
|
||||
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
||||
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
|
||||
public final class CavarynBileCystFeature extends Feature<NoneFeatureConfiguration> {
|
||||
private static final ResourceLocation BILE_VEIN_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "bile_vein");
|
||||
private static final ResourceLocation BILE_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "bile");
|
||||
private static final int SEARCH_RADIUS = 8;
|
||||
private static final int SEARCH_ATTEMPTS = 20;
|
||||
private static final int VERTICAL_SCAN = 10;
|
||||
// Chance that each exposed vein face oozes bile liquid outward into the cave
|
||||
private static final float OOZE_CHANCE = 0.22f;
|
||||
|
||||
public CavarynBileCystFeature(Codec<NoneFeatureConfiguration> codec) {
|
||||
super(codec);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean place(FeaturePlaceContext<NoneFeatureConfiguration> context) {
|
||||
Block bileVeinBlock = getBlock(BILE_VEIN_ID);
|
||||
Block bileBlock = getBlock(BILE_ID);
|
||||
if (bileVeinBlock == null || !(bileBlock instanceof LiquidBlock)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WorldGenLevel level = context.level();
|
||||
RandomSource random = context.random();
|
||||
|
||||
BlockPos center = findCenter(level, context.origin(), random);
|
||||
if (center == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return placeCyst(level, center, bileVeinBlock, bileBlock, random);
|
||||
}
|
||||
|
||||
// Find a solid block adjacent to cave air, then step 1-2 blocks deeper into the wall
|
||||
// so the cyst is embedded rather than sitting right on the surface.
|
||||
private static BlockPos findCenter(WorldGenLevel level, BlockPos origin, RandomSource random) {
|
||||
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
|
||||
for (int attempt = 0; attempt < SEARCH_ATTEMPTS; attempt++) {
|
||||
int x = origin.getX() + random.nextInt(SEARCH_RADIUS * 2 + 1) - SEARCH_RADIUS;
|
||||
int z = origin.getZ() + random.nextInt(SEARCH_RADIUS * 2 + 1) - SEARCH_RADIUS;
|
||||
int y = origin.getY() + random.nextInt(VERTICAL_SCAN * 2 + 1) - VERTICAL_SCAN;
|
||||
y = Mth.clamp(y, level.getMinBuildHeight() + 6, level.getMaxBuildHeight() - 6);
|
||||
mutable.set(x, y, z);
|
||||
|
||||
if (!isSolid(level.getBlockState(mutable))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Need at least one open neighbor (at cave surface)
|
||||
Direction openDir = null;
|
||||
for (Direction dir : Direction.values()) {
|
||||
if (level.getBlockState(mutable.relative(dir)).canBeReplaced()) {
|
||||
openDir = dir;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (openDir == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Step 1-2 blocks away from the opening so the cyst sits inside the wall
|
||||
int depth = 1 + random.nextInt(2);
|
||||
BlockPos candidate = mutable.immutable().relative(openDir.getOpposite(), depth);
|
||||
if (isSolid(level.getBlockState(candidate))) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean placeCyst(WorldGenLevel level, BlockPos center, Block veinBlock, Block bileBlock, RandomSource random) {
|
||||
// Per-axis radii: 1.5–13.5 so the cyst diameter ranges roughly 3–27
|
||||
double rx = 1.5 + random.nextDouble() * 12.0;
|
||||
double ry = 1.5 + random.nextDouble() * 12.0;
|
||||
double rz = 1.5 + random.nextDouble() * 12.0;
|
||||
|
||||
// Random stretch: pick one axis and scale it up 1.3–2x for elongated cysts
|
||||
int stretchAxis = random.nextInt(3);
|
||||
if (stretchAxis == 0) rx *= 1.3 + random.nextDouble() * 0.7;
|
||||
else if (stretchAxis == 1) ry *= 1.3 + random.nextDouble() * 0.7;
|
||||
else rz *= 1.3 + random.nextDouble() * 0.7;
|
||||
|
||||
// Independent sine frequencies per wobble term — drives the lumpy distortion
|
||||
double f1x = 0.6 + random.nextDouble() * 1.2;
|
||||
double f1z = 0.6 + random.nextDouble() * 1.2;
|
||||
double f2y = 0.7 + random.nextDouble() * 1.0;
|
||||
double f2x = 0.5 + random.nextDouble() * 0.9;
|
||||
double f3z = 0.8 + random.nextDouble() * 1.1;
|
||||
double f3y = 0.5 + random.nextDouble() * 0.8;
|
||||
double wobbleAmp = 0.15 + random.nextDouble() * 0.2; // surface roughness
|
||||
|
||||
int maxR = (int) Math.ceil(Math.max(Math.max(rx, ry), rz)) + 2;
|
||||
List<BlockPos> placed = new ArrayList<>();
|
||||
|
||||
for (int dx = -maxR; dx <= maxR; dx++) {
|
||||
for (int dy = -maxR; dy <= maxR; dy++) {
|
||||
for (int dz = -maxR; dz <= maxR; dz++) {
|
||||
double baseDist = Math.sqrt(
|
||||
(dx * dx) / (rx * rx) +
|
||||
(dy * dy) / (ry * ry) +
|
||||
(dz * dz) / (rz * rz));
|
||||
|
||||
// Multi-frequency sine interference — gives lumpy, non-spherical surface
|
||||
double wobble = wobbleAmp * (
|
||||
0.4 * Math.sin(dx * f1x + dz * f1z) +
|
||||
0.35 * Math.cos(dy * f2y + dx * f2x) +
|
||||
0.25 * Math.sin(dz * f3z + dy * f3y));
|
||||
|
||||
double distorted = baseDist + wobble;
|
||||
if (distorted > 1.0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BlockPos pos = center.offset(dx, dy, dz);
|
||||
BlockState existing = level.getBlockState(pos);
|
||||
if (!isSolid(existing)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (distorted < 0.7) {
|
||||
// Interior — fill with bile liquid
|
||||
BlockState bileState = bileBlock.defaultBlockState();
|
||||
level.setBlock(pos, bileState, 2);
|
||||
scheduleFluidTick(level, pos, bileState);
|
||||
} else {
|
||||
// Outer shell — bile vein blocks
|
||||
level.setBlock(pos, veinBlock.defaultBlockState(), 2);
|
||||
placed.add(pos.immutable());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (placed.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 30% chance this cyst oozes at all
|
||||
if (random.nextFloat() >= 0.30f) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Ooze bile out of exposed faces — "popped pimple" seep
|
||||
for (BlockPos cystPos : placed) {
|
||||
for (Direction dir : Direction.values()) {
|
||||
BlockPos adj = cystPos.relative(dir);
|
||||
BlockState adjState = level.getBlockState(adj);
|
||||
if ((adjState.isAir() || adjState.canBeReplaced()) && random.nextFloat() < OOZE_CHANCE) {
|
||||
BlockState bileState = bileBlock.defaultBlockState();
|
||||
level.setBlock(adj, bileState, 2);
|
||||
scheduleFluidTick(level, adj, bileState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isSolid(BlockState state) {
|
||||
return state.blocksMotion() && !state.is(Blocks.BEDROCK) && state.getFluidState().isEmpty();
|
||||
}
|
||||
|
||||
private static void scheduleFluidTick(WorldGenLevel level, BlockPos pos, BlockState state) {
|
||||
FluidState fluidState = state.getFluidState();
|
||||
if (!fluidState.isEmpty()) {
|
||||
level.scheduleTick(pos, fluidState.getType(), fluidState.getType().getTickDelay(level));
|
||||
}
|
||||
}
|
||||
|
||||
private static Block getBlock(ResourceLocation id) {
|
||||
Optional<Block> block = BuiltInRegistries.BLOCK.getOptional(id);
|
||||
return block.orElse(null);
|
||||
}
|
||||
}
|
||||
-150
@@ -1,150 +0,0 @@
|
||||
package com.craisinlord.antarchy.content.worldgen.cavaryn;
|
||||
|
||||
import com.craisinlord.antarchy.Antarchy;
|
||||
import com.mojang.serialization.Codec;
|
||||
import java.util.Optional;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.level.WorldGenLevel;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.LiquidBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.levelgen.feature.Feature;
|
||||
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
||||
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
|
||||
public final class CavarynBilePoolFeature extends Feature<NoneFeatureConfiguration> {
|
||||
private static final ResourceLocation BILE_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "bile");
|
||||
private static final int SEARCH_RADIUS = 8;
|
||||
private static final int SEARCH_ATTEMPTS = 24;
|
||||
private static final int FLOOR_SCAN_RANGE = 14;
|
||||
|
||||
public CavarynBilePoolFeature(Codec<NoneFeatureConfiguration> codec) {
|
||||
super(codec);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean place(FeaturePlaceContext<NoneFeatureConfiguration> context) {
|
||||
Block bileBlock = getBlock(BILE_ID);
|
||||
if (!(bileBlock instanceof LiquidBlock)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WorldGenLevel level = context.level();
|
||||
RandomSource random = context.random();
|
||||
BlockPos floorCenter = findPoolFloor(level, context.origin(), random);
|
||||
if (floorCenter == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return placePool(level, floorCenter, bileBlock.defaultBlockState(), random);
|
||||
}
|
||||
|
||||
private static BlockPos findPoolFloor(WorldGenLevel level, BlockPos origin, RandomSource random) {
|
||||
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
|
||||
for (int attempt = 0; attempt < SEARCH_ATTEMPTS; attempt++) {
|
||||
int x = origin.getX() + random.nextInt(SEARCH_RADIUS * 2 + 1) - SEARCH_RADIUS;
|
||||
int z = origin.getZ() + random.nextInt(SEARCH_RADIUS * 2 + 1) - SEARCH_RADIUS;
|
||||
int startY = origin.getY() + random.nextInt(FLOOR_SCAN_RANGE * 2 + 1) - FLOOR_SCAN_RANGE;
|
||||
startY = Math.max(level.getMinBuildHeight() + 3, Math.min(level.getMaxBuildHeight() - 4, startY));
|
||||
|
||||
for (int y = startY; y >= Math.max(level.getMinBuildHeight() + 2, startY - FLOOR_SCAN_RANGE); y--) {
|
||||
mutable.set(x, y, z);
|
||||
BlockState floorState = level.getBlockState(mutable);
|
||||
if (!isValidFloor(level, mutable, floorState)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BlockState aboveState = level.getBlockState(mutable.above());
|
||||
if (!isOpenBlock(aboveState)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (countSolidNeighbors(level, mutable) >= 3) {
|
||||
return mutable.immutable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean placePool(WorldGenLevel level, BlockPos center, BlockState bileState, RandomSource random) {
|
||||
boolean placedAny = false;
|
||||
int radius = 2 + random.nextInt(3);
|
||||
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
|
||||
|
||||
for (int dx = -radius; dx <= radius; dx++) {
|
||||
for (int dz = -radius; dz <= radius; dz++) {
|
||||
double normalized = (dx * dx + dz * dz) / (double) Math.max(1, radius * radius);
|
||||
if (normalized > 1.0D + random.nextDouble() * 0.2D) {
|
||||
continue;
|
||||
}
|
||||
|
||||
double density = 1.0D - Math.min(1.0D, normalized);
|
||||
int localDepth = density > 0.45D || random.nextFloat() < 0.35F ? 2 : 1;
|
||||
localDepth = Mth.clamp(localDepth, 1, 2);
|
||||
|
||||
for (int depth = 0; depth < localDepth; depth++) {
|
||||
mutable.set(center.getX() + dx, center.getY() - depth, center.getZ() + dz);
|
||||
BlockState existing = level.getBlockState(mutable);
|
||||
FluidState existingFluid = existing.getFluidState();
|
||||
if (existing.is(Blocks.BEDROCK)) {
|
||||
break;
|
||||
}
|
||||
if (!existing.canBeReplaced() && existingFluid.isEmpty() && !existing.blocksMotion()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
level.setBlock(mutable, bileState, 2);
|
||||
scheduleFluidTick(level, mutable, bileState);
|
||||
placedAny = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return placedAny;
|
||||
}
|
||||
|
||||
private static boolean isValidFloor(WorldGenLevel level, BlockPos pos, BlockState state) {
|
||||
return !state.isAir()
|
||||
&& !state.is(Blocks.BEDROCK)
|
||||
&& state.getFluidState().isEmpty()
|
||||
&& state.blocksMotion()
|
||||
&& state.isFaceSturdy(level, pos, Direction.UP);
|
||||
}
|
||||
|
||||
private static boolean isOpenBlock(BlockState state) {
|
||||
return state.isAir() || state.canBeReplaced() || !state.getFluidState().isEmpty();
|
||||
}
|
||||
|
||||
private static int countSolidNeighbors(WorldGenLevel level, BlockPos pos) {
|
||||
int solidNeighbors = 0;
|
||||
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
|
||||
for (Direction direction : Direction.Plane.HORIZONTAL) {
|
||||
mutable.setWithOffset(pos, direction);
|
||||
if (isValidFloor(level, mutable, level.getBlockState(mutable))) {
|
||||
solidNeighbors++;
|
||||
}
|
||||
}
|
||||
return solidNeighbors;
|
||||
}
|
||||
|
||||
private static void scheduleFluidTick(WorldGenLevel level, BlockPos pos, BlockState state) {
|
||||
FluidState fluidState = state.getFluidState();
|
||||
if (!fluidState.isEmpty()) {
|
||||
level.scheduleTick(pos, fluidState.getType(), fluidState.getType().getTickDelay(level));
|
||||
}
|
||||
}
|
||||
|
||||
private static Block getBlock(ResourceLocation id) {
|
||||
Optional<Block> block = BuiltInRegistries.BLOCK.getOptional(id);
|
||||
return block.orElse(null);
|
||||
}
|
||||
}
|
||||
+238
@@ -0,0 +1,238 @@
|
||||
package com.craisinlord.antarchy.content.worldgen.cavaryn;
|
||||
|
||||
import com.craisinlord.antarchy.Antarchy;
|
||||
import com.mojang.serialization.Codec;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.level.WorldGenLevel;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.LiquidBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.levelgen.feature.Feature;
|
||||
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
||||
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
|
||||
public final class CavarynBileVeinFeature extends Feature<NoneFeatureConfiguration> {
|
||||
private static final ResourceLocation BILE_VEIN_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "bile_vein");
|
||||
private static final ResourceLocation BILE_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "bile");
|
||||
private static final int SEARCH_RADIUS = 10;
|
||||
private static final int SEARCH_ATTEMPTS = 24;
|
||||
private static final int VERTICAL_SCAN = 12;
|
||||
private static final float BRANCH_CHANCE = 0.12f;
|
||||
private static final float LIQUID_POCKET_CHANCE = 0.04f;
|
||||
|
||||
public CavarynBileVeinFeature(Codec<NoneFeatureConfiguration> codec) {
|
||||
super(codec);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean place(FeaturePlaceContext<NoneFeatureConfiguration> context) {
|
||||
Block bileVeinBlock = getBlock(BILE_VEIN_ID);
|
||||
Block bileBlock = getBlock(BILE_ID);
|
||||
if (bileVeinBlock == null || !(bileBlock instanceof LiquidBlock)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WorldGenLevel level = context.level();
|
||||
RandomSource random = context.random();
|
||||
|
||||
BlockPos start = findStart(level, context.origin(), random);
|
||||
if (start == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return growVeinNetwork(level, start, bileVeinBlock, bileBlock, random);
|
||||
}
|
||||
|
||||
// Find a solid block that sits at a cave boundary
|
||||
private static BlockPos findStart(WorldGenLevel level, BlockPos origin, RandomSource random) {
|
||||
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
|
||||
for (int attempt = 0; attempt < SEARCH_ATTEMPTS; attempt++) {
|
||||
int x = origin.getX() + random.nextInt(SEARCH_RADIUS * 2 + 1) - SEARCH_RADIUS;
|
||||
int z = origin.getZ() + random.nextInt(SEARCH_RADIUS * 2 + 1) - SEARCH_RADIUS;
|
||||
int y = origin.getY() + random.nextInt(VERTICAL_SCAN * 2 + 1) - VERTICAL_SCAN;
|
||||
y = Mth.clamp(y, level.getMinBuildHeight() + 2, level.getMaxBuildHeight() - 3);
|
||||
mutable.set(x, y, z);
|
||||
|
||||
if (!isVeinCandidate(level.getBlockState(mutable))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (Direction dir : Direction.values()) {
|
||||
if (level.getBlockState(mutable.relative(dir)).canBeReplaced()) {
|
||||
return mutable.immutable();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean growVeinNetwork(WorldGenLevel level, BlockPos start, Block veinBlock, Block bileBlock, RandomSource random) {
|
||||
Set<BlockPos> visited = new HashSet<>();
|
||||
List<BranchStart> pendingBranches = new ArrayList<>();
|
||||
boolean placedAny = false;
|
||||
|
||||
Direction mainDir = Direction.values()[random.nextInt(6)];
|
||||
placedAny |= growArm(level, start, mainDir, 45 + random.nextInt(25), visited, pendingBranches, veinBlock, bileBlock, random);
|
||||
|
||||
for (BranchStart branch : pendingBranches) {
|
||||
Direction branchDir = perpendiculars(branch.dir())[random.nextInt(4)];
|
||||
int branchLen = 15 + random.nextInt(20);
|
||||
growArm(level, branch.pos(), branchDir, branchLen, visited, null, veinBlock, bileBlock, random);
|
||||
}
|
||||
|
||||
return placedAny;
|
||||
}
|
||||
|
||||
private boolean growArm(
|
||||
WorldGenLevel level,
|
||||
BlockPos start,
|
||||
Direction initialDir,
|
||||
int maxSteps,
|
||||
Set<BlockPos> visited,
|
||||
List<BranchStart> branches,
|
||||
Block veinBlock,
|
||||
Block bileBlock,
|
||||
RandomSource random
|
||||
) {
|
||||
BlockPos current = start;
|
||||
Direction dir = initialDir;
|
||||
boolean placedAny = false;
|
||||
|
||||
for (int step = 0; step < maxSteps; step++) {
|
||||
if (visited.contains(current)) {
|
||||
current = current.relative(biasedNextDir(dir, random));
|
||||
continue;
|
||||
}
|
||||
|
||||
BlockState state = level.getBlockState(current);
|
||||
if (!isVeinCandidate(state)) {
|
||||
// Try to redirect
|
||||
BlockPos redirect = findSolidNeighbor(current, dir, visited, level, random);
|
||||
if (redirect == null) {
|
||||
break;
|
||||
}
|
||||
current = redirect;
|
||||
state = level.getBlockState(current);
|
||||
if (!isVeinCandidate(state)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
visited.add(current);
|
||||
level.setBlock(current, veinBlock.defaultBlockState(), 2);
|
||||
placedAny = true;
|
||||
|
||||
if (random.nextFloat() < LIQUID_POCKET_CHANCE) {
|
||||
tryPlaceLiquidPocket(level, current, bileBlock, visited, random);
|
||||
}
|
||||
|
||||
if (branches != null && random.nextFloat() < BRANCH_CHANCE) {
|
||||
Direction[] perps = perpendiculars(dir);
|
||||
branches.add(new BranchStart(current, perps[random.nextInt(perps.length)]));
|
||||
}
|
||||
|
||||
dir = biasedNextDir(dir, random);
|
||||
current = current.relative(dir);
|
||||
}
|
||||
|
||||
return placedAny;
|
||||
}
|
||||
|
||||
private static Direction biasedNextDir(Direction current, RandomSource random) {
|
||||
int roll = random.nextInt(10);
|
||||
if (roll < 6) {
|
||||
return current;
|
||||
}
|
||||
return perpendiculars(current)[roll - 6];
|
||||
}
|
||||
|
||||
private static BlockPos findSolidNeighbor(BlockPos from, Direction preferredDir, Set<BlockPos> visited, WorldGenLevel level, RandomSource random) {
|
||||
Direction[] perps = perpendiculars(preferredDir);
|
||||
for (int i = perps.length - 1; i > 0; i--) {
|
||||
int j = random.nextInt(i + 1);
|
||||
Direction tmp = perps[i];
|
||||
perps[i] = perps[j];
|
||||
perps[j] = tmp;
|
||||
}
|
||||
for (Direction d : perps) {
|
||||
BlockPos candidate = from.relative(d);
|
||||
if (!visited.contains(candidate) && isVeinCandidate(level.getBlockState(candidate))) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void tryPlaceLiquidPocket(WorldGenLevel level, BlockPos veinPos, Block bileBlock, Set<BlockPos> visited, RandomSource random) {
|
||||
Direction[] dirs = Direction.values().clone();
|
||||
for (int i = dirs.length - 1; i > 0; i--) {
|
||||
int j = random.nextInt(i + 1);
|
||||
Direction tmp = dirs[i];
|
||||
dirs[i] = dirs[j];
|
||||
dirs[j] = tmp;
|
||||
}
|
||||
for (Direction d : dirs) {
|
||||
BlockPos candidate = veinPos.relative(d);
|
||||
if (visited.contains(candidate)) {
|
||||
continue;
|
||||
}
|
||||
BlockState candidateState = level.getBlockState(candidate);
|
||||
if (!isVeinCandidate(candidateState)) {
|
||||
continue;
|
||||
}
|
||||
if (isEnclosed(level, candidate) || random.nextFloat() < 0.05f) {
|
||||
BlockState bileState = bileBlock.defaultBlockState();
|
||||
level.setBlock(candidate, bileState, 2);
|
||||
scheduleFluidTick(level, candidate, bileState);
|
||||
visited.add(candidate);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isEnclosed(WorldGenLevel level, BlockPos pos) {
|
||||
for (Direction d : Direction.values()) {
|
||||
BlockState neighbor = level.getBlockState(pos.relative(d));
|
||||
if (neighbor.isAir() || neighbor.canBeReplaced()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isVeinCandidate(BlockState state) {
|
||||
return state.blocksMotion() && !state.is(Blocks.BEDROCK) && state.getFluidState().isEmpty();
|
||||
}
|
||||
|
||||
private static Direction[] perpendiculars(Direction dir) {
|
||||
return switch (dir.getAxis()) {
|
||||
case X -> new Direction[]{Direction.UP, Direction.DOWN, Direction.NORTH, Direction.SOUTH};
|
||||
case Z -> new Direction[]{Direction.UP, Direction.DOWN, Direction.EAST, Direction.WEST};
|
||||
case Y -> new Direction[]{Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST};
|
||||
};
|
||||
}
|
||||
|
||||
private static void scheduleFluidTick(WorldGenLevel level, BlockPos pos, BlockState state) {
|
||||
FluidState fluidState = state.getFluidState();
|
||||
if (!fluidState.isEmpty()) {
|
||||
level.scheduleTick(pos, fluidState.getType(), fluidState.getType().getTickDelay(level));
|
||||
}
|
||||
}
|
||||
|
||||
private static Block getBlock(ResourceLocation id) {
|
||||
Optional<Block> block = BuiltInRegistries.BLOCK.getOptional(id);
|
||||
return block.orElse(null);
|
||||
}
|
||||
|
||||
private record BranchStart(BlockPos pos, Direction dir) {}
|
||||
}
|
||||
+96
-48
@@ -1,23 +1,33 @@
|
||||
package com.craisinlord.antarchy.content.worldgen.cavaryn;
|
||||
|
||||
import com.craisinlord.antarchy.Antarchy;
|
||||
import com.craisinlord.antarchy.content.AntarchyObjects;
|
||||
import com.craisinlord.antarchy.content.block.CreepingHorrorEggBlock;
|
||||
import com.craisinlord.antarchy.content.block.LurkingTerrorEggBlock;
|
||||
import com.mojang.serialization.Codec;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.level.WorldGenLevel;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.levelgen.feature.Feature;
|
||||
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
||||
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
|
||||
|
||||
public final class CavarynEggPatchFeature extends Feature<NoneFeatureConfiguration> {
|
||||
private static final ResourceLocation AMBER_MOSS_BLOCK_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "amber_moss_block");
|
||||
private static final int SEARCH_RADIUS = 8;
|
||||
private static final int SEARCH_ATTEMPTS = 20;
|
||||
private static final int FLOOR_SCAN_RANGE = 10;
|
||||
private static final int SEARCH_ATTEMPTS = 24;
|
||||
private static final int VERTICAL_SCAN = 12;
|
||||
private static final int MAX_RADIUS_Y = 3;
|
||||
|
||||
public CavarynEggPatchFeature(Codec<NoneFeatureConfiguration> codec) {
|
||||
super(codec);
|
||||
@@ -29,77 +39,118 @@ public final class CavarynEggPatchFeature extends Feature<NoneFeatureConfigurati
|
||||
RandomSource random = context.random();
|
||||
BlockPos origin = context.origin();
|
||||
|
||||
BlockPos surfacePos = findSurfacePos(level, origin, random);
|
||||
if (surfacePos == null) {
|
||||
Block amberMossBlock = getBlock(AMBER_MOSS_BLOCK_ID);
|
||||
BlockPos center = findCavityCenter(level, origin, random);
|
||||
if (center == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
EggType eggType = random.nextBoolean() ? EggType.CREEPING_HORROR : EggType.LURKING_TERROR;
|
||||
return placePatch(level, surfacePos, random, eggType);
|
||||
return carveCavityAndPlaceEggs(level, center, random, eggType, amberMossBlock);
|
||||
}
|
||||
|
||||
private static BlockPos findSurfacePos(WorldGenLevel level, BlockPos origin, RandomSource random) {
|
||||
private static BlockPos findCavityCenter(WorldGenLevel level, BlockPos origin, RandomSource random) {
|
||||
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
|
||||
for (int attempt = 0; attempt < SEARCH_ATTEMPTS; attempt++) {
|
||||
int x = origin.getX() + random.nextInt(SEARCH_RADIUS * 2 + 1) - SEARCH_RADIUS;
|
||||
int z = origin.getZ() + random.nextInt(SEARCH_RADIUS * 2 + 1) - SEARCH_RADIUS;
|
||||
int startY = origin.getY() + random.nextInt(FLOOR_SCAN_RANGE * 2 + 1) - FLOOR_SCAN_RANGE;
|
||||
startY = Math.max(level.getMinBuildHeight() + 2, Math.min(level.getMaxBuildHeight() - 3, startY));
|
||||
int y = origin.getY() + random.nextInt(VERTICAL_SCAN * 2 + 1) - VERTICAL_SCAN;
|
||||
y = Mth.clamp(y, level.getMinBuildHeight() + MAX_RADIUS_Y + 2, level.getMaxBuildHeight() - MAX_RADIUS_Y - 2);
|
||||
|
||||
for (int y = startY; y >= Math.max(level.getMinBuildHeight() + 1, startY - FLOOR_SCAN_RANGE); y--) {
|
||||
mutable.set(x, y, z);
|
||||
BlockState floorState = level.getBlockState(mutable);
|
||||
BlockState airState = level.getBlockState(mutable.above());
|
||||
if (floorState.getFluidState().isEmpty()
|
||||
&& floorState.blocksMotion()
|
||||
&& floorState.isFaceSturdy(level, mutable, Direction.UP)
|
||||
&& airState.canBeReplaced()) {
|
||||
return mutable.immutable();
|
||||
}
|
||||
mutable.set(x, y, z);
|
||||
if (isSolidEnoughForCavity(level, mutable)) {
|
||||
return mutable.immutable();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean placePatch(WorldGenLevel level, BlockPos center, RandomSource random, EggType eggType) {
|
||||
int radius = 2 + random.nextInt(3);
|
||||
boolean placedAny = false;
|
||||
List<BlockPos> eggSpots = new java.util.ArrayList<>();
|
||||
private static boolean isSolidEnoughForCavity(WorldGenLevel level, BlockPos center) {
|
||||
BlockState centerState = level.getBlockState(center);
|
||||
if (!centerState.blocksMotion() || centerState.is(Blocks.BEDROCK)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int dx = -radius; dx <= radius; dx++) {
|
||||
for (int dz = -radius; dz <= radius; dz++) {
|
||||
double distance = dx * dx + dz * dz;
|
||||
if (distance > radius * radius + random.nextInt(2)) {
|
||||
continue;
|
||||
int solidCount = 0;
|
||||
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
|
||||
for (int dx = -2; dx <= 2; dx += 2) {
|
||||
for (int dy = -1; dy <= 1; dy++) {
|
||||
for (int dz = -2; dz <= 2; dz += 2) {
|
||||
mutable.set(center.getX() + dx, center.getY() + dy, center.getZ() + dz);
|
||||
if (level.getBlockState(mutable).blocksMotion()) {
|
||||
solidCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return solidCount >= 9;
|
||||
}
|
||||
|
||||
BlockPos floorPos = center.offset(dx, 0, dz);
|
||||
BlockState floorState = level.getBlockState(floorPos);
|
||||
BlockPos eggPos = floorPos.above();
|
||||
BlockState aboveState = level.getBlockState(eggPos);
|
||||
if (!isValidEggFloor(level, floorPos, floorState, aboveState)) {
|
||||
continue;
|
||||
private boolean carveCavityAndPlaceEggs(WorldGenLevel level, BlockPos center, RandomSource random, EggType eggType, Block amberMossBlock) {
|
||||
int rx = 3 + random.nextInt(3);
|
||||
int ry = 2 + random.nextInt(2);
|
||||
int rz = 3 + random.nextInt(3);
|
||||
|
||||
for (int dx = -rx; dx <= rx; dx++) {
|
||||
for (int dy = -ry; dy <= ry; dy++) {
|
||||
for (int dz = -rz; dz <= rz; dz++) {
|
||||
double norm = (double)(dx * dx) / (rx * rx)
|
||||
+ (double)(dy * dy) / (ry * ry)
|
||||
+ (double)(dz * dz) / (rz * rz);
|
||||
if (norm > 1.0) {
|
||||
continue;
|
||||
}
|
||||
BlockPos pos = center.offset(dx, dy, dz);
|
||||
BlockState existing = level.getBlockState(pos);
|
||||
if (!existing.is(Blocks.BEDROCK) && existing.blocksMotion() && existing.getFluidState().isEmpty()) {
|
||||
level.setBlock(pos, Blocks.AIR.defaultBlockState(), 2);
|
||||
}
|
||||
}
|
||||
eggSpots.add(eggPos);
|
||||
}
|
||||
}
|
||||
|
||||
if (eggSpots.isEmpty()) {
|
||||
return placedAny;
|
||||
List<BlockPos> eggPositions = new ArrayList<>();
|
||||
for (int dx = -rx; dx <= rx; dx++) {
|
||||
for (int dy = -ry - 1; dy <= ry; dy++) {
|
||||
for (int dz = -rz; dz <= rz; dz++) {
|
||||
BlockPos pos = center.offset(dx, dy, dz);
|
||||
if (!level.getBlockState(pos).isAir()) {
|
||||
continue;
|
||||
}
|
||||
BlockPos below = pos.below();
|
||||
BlockState belowState = level.getBlockState(below);
|
||||
if (belowState.blocksMotion() && !belowState.isAir() && belowState.isFaceSturdy(level, below, Direction.UP)) {
|
||||
eggPositions.add(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int eggCount = Math.min(eggSpots.size(), 2 + random.nextInt(3));
|
||||
for (int i = 0; i < eggCount; i++) {
|
||||
BlockPos eggPos = eggSpots.get(random.nextInt(eggSpots.size()));
|
||||
if (!level.getBlockState(eggPos).canBeReplaced()) {
|
||||
if (eggPositions.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean placedAny = false;
|
||||
for (BlockPos eggPos : eggPositions) {
|
||||
if (random.nextFloat() > 0.65f) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Replace the floor block with amber moss so eggs hatch faster
|
||||
if (amberMossBlock != null) {
|
||||
BlockPos floorPos = eggPos.below();
|
||||
BlockState floorState = level.getBlockState(floorPos);
|
||||
if (floorState.blocksMotion() && !floorState.is(Blocks.BEDROCK) && floorState.getFluidState().isEmpty()) {
|
||||
level.setBlock(floorPos, amberMossBlock.defaultBlockState(), 2);
|
||||
}
|
||||
}
|
||||
|
||||
BlockState eggState = eggType == EggType.CREEPING_HORROR
|
||||
? AntarchyObjects.CREEPING_HORROR_EGGS.get().defaultBlockState()
|
||||
: AntarchyObjects.LURKING_TERROR_EGGS.get().defaultBlockState();
|
||||
eggState = eggState.setValue(eggType == EggType.CREEPING_HORROR ? CreepingHorrorEggBlock.EGGS : LurkingTerrorEggBlock.EGGS, 1 + random.nextInt(4));
|
||||
eggState = eggState.setValue(
|
||||
eggType == EggType.CREEPING_HORROR ? CreepingHorrorEggBlock.EGGS : LurkingTerrorEggBlock.EGGS,
|
||||
1 + random.nextInt(4));
|
||||
level.setBlock(eggPos, eggState, 3);
|
||||
placedAny = true;
|
||||
}
|
||||
@@ -107,12 +158,9 @@ public final class CavarynEggPatchFeature extends Feature<NoneFeatureConfigurati
|
||||
return placedAny;
|
||||
}
|
||||
|
||||
private static boolean isValidEggFloor(WorldGenLevel level, BlockPos floorPos, BlockState floorState, BlockState aboveState) {
|
||||
return !floorState.isAir()
|
||||
&& floorState.getFluidState().isEmpty()
|
||||
&& floorState.blocksMotion()
|
||||
&& floorState.isFaceSturdy(level, floorPos, Direction.UP)
|
||||
&& aboveState.canBeReplaced();
|
||||
private static Block getBlock(ResourceLocation id) {
|
||||
Optional<Block> block = BuiltInRegistries.BLOCK.getOptional(id);
|
||||
return block.orElse(null);
|
||||
}
|
||||
|
||||
private enum EggType {
|
||||
|
||||
+7
-4
@@ -118,12 +118,15 @@ public class ElythiaBiomeSource extends BiomeSource {
|
||||
// and ambient effects work correctly above the water surface.
|
||||
Climate.TargetPoint target = sampler.sample(x, this.seaLevelQuartY, z);
|
||||
if (target.continentalness() < OCEAN_CONTINENTALNESS_THRESHOLD) {
|
||||
return this.delegate.getNoiseBiome(x, this.seaLevelQuartY, z, sampler);
|
||||
Holder<Biome> seaLevelBiome = this.delegate.getNoiseBiome(x, this.seaLevelQuartY, z, sampler);
|
||||
// MultiNoise can return a land biome at sea-level depth — force ocean if so
|
||||
if (isOceanBiome(seaLevelBiome)) return seaLevelBiome;
|
||||
return oceanHolder != null ? oceanHolder : seaLevelBiome;
|
||||
}
|
||||
|
||||
// Land column below or at sea level: force ocean for any biome not allowed there.
|
||||
// Use <= so quart 19 (blocks 76-79, partly underwater) is covered.
|
||||
if (y <= this.seaLevelQuartY && oceanHolder != null && !allowedBelowSeaLevel(biome)) {
|
||||
// Land column at or below sea level: force ocean for any biome not allowed there.
|
||||
// +1 quart above seaLevelQuartY so blocks 76-83 (around the waterline) are all caught.
|
||||
if (y <= this.seaLevelQuartY + 1 && oceanHolder != null && !allowedBelowSeaLevel(biome)) {
|
||||
return oceanHolder;
|
||||
}
|
||||
|
||||
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
package com.craisinlord.antarchy.content.worldgen.elythia;
|
||||
|
||||
import com.craisinlord.antarchy.content.AntarchyObjects;
|
||||
import com.mojang.serialization.Codec;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.level.WorldGenLevel;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.LeavesBlock;
|
||||
import net.minecraft.world.level.block.RotatedPillarBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import net.minecraft.world.level.levelgen.feature.Feature;
|
||||
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
||||
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
|
||||
|
||||
public class FallenOuranwoodFeature extends Feature<NoneFeatureConfiguration> {
|
||||
|
||||
public FallenOuranwoodFeature(Codec<NoneFeatureConfiguration> codec) {
|
||||
super(codec);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean place(FeaturePlaceContext<NoneFeatureConfiguration> context) {
|
||||
WorldGenLevel level = context.level();
|
||||
RandomSource random = context.random();
|
||||
BlockPos origin = context.origin();
|
||||
|
||||
Direction.Axis axis = random.nextBoolean() ? Direction.Axis.X : Direction.Axis.Z;
|
||||
int length = 36 + random.nextInt(44); // 36–79 blocks long
|
||||
int outerRadius = 1 + random.nextInt(3); // 1–3 (cross-section up to 7-wide)
|
||||
boolean hollow = outerRadius >= 2;
|
||||
|
||||
Block ouranwoodLog = BuiltInRegistries.BLOCK.getOptional(
|
||||
ResourceLocation.fromNamespaceAndPath("antarchy", "ouranwood_log"))
|
||||
.orElse(AntarchyObjects.MOSSY_OURANWOOD_LOG.get());
|
||||
|
||||
BlockState mossyLogState = AntarchyObjects.MOSSY_OURANWOOD_LOG.get().defaultBlockState()
|
||||
.setValue(RotatedPillarBlock.AXIS, axis);
|
||||
BlockState freshLogState = ouranwoodLog.defaultBlockState()
|
||||
.setValue(RotatedPillarBlock.AXIS, axis);
|
||||
BlockState woodState = AntarchyObjects.MOSSY_OURANWOOD_WOOD.get().defaultBlockState()
|
||||
.setValue(RotatedPillarBlock.AXIS, Direction.Axis.Y);
|
||||
|
||||
// Pre-generate a smoothed damage profile along the length (0=solid, 1=gap)
|
||||
float[] damage = new float[length];
|
||||
for (int i = 0; i < length; i++) damage[i] = random.nextFloat();
|
||||
for (int pass = 0; pass < 4; pass++) {
|
||||
for (int i = 1; i < length - 1; i++) {
|
||||
damage[i] = (damage[i - 1] + damage[i] * 2 + damage[i + 1]) / 4f;
|
||||
}
|
||||
}
|
||||
// Bias upward so more sections are heavily damaged
|
||||
for (int i = 0; i < length; i++) damage[i] = damage[i] * damage[i];
|
||||
|
||||
int anchorY = level.getHeight(Heightmap.Types.WORLD_SURFACE_WG, origin.getX(), origin.getZ());
|
||||
boolean placed = false;
|
||||
|
||||
for (int step = 0; step < length; step++) {
|
||||
int bx = axis == Direction.Axis.X ? origin.getX() + step : origin.getX();
|
||||
int bz = axis == Direction.Axis.Z ? origin.getZ() + step : origin.getZ();
|
||||
|
||||
float dmg = damage[step];
|
||||
|
||||
// Full gap sections — log has completely rotted through here
|
||||
if (dmg > 0.78f) continue;
|
||||
|
||||
int surfaceY = level.getHeight(Heightmap.Types.WORLD_SURFACE_WG, bx, bz);
|
||||
int centerY = Math.max(anchorY, Math.min(anchorY + 2, surfaceY)) + outerRadius;
|
||||
|
||||
for (int dy = -outerRadius; dy <= outerRadius; dy++) {
|
||||
for (int dp = -outerRadius; dp <= outerRadius; dp++) {
|
||||
double dist = Math.sqrt(dy * dy + dp * dp);
|
||||
if (dist > outerRadius + 0.5) continue;
|
||||
|
||||
boolean isShell = dist >= outerRadius - 0.5;
|
||||
|
||||
// Hollow interior: always skip center when hollow
|
||||
if (hollow && dist < outerRadius - 0.5) continue;
|
||||
|
||||
// Heavy-damage sections: only keep fragments of the shell
|
||||
if (dmg > 0.55f && !isShell) continue;
|
||||
if (dmg > 0.55f && random.nextFloat() < (dmg - 0.55f) * 3.5f) continue;
|
||||
|
||||
// All sections: random rot holes punched through the shell
|
||||
if (isShell && random.nextFloat() < dmg * 0.4f) continue;
|
||||
|
||||
int px = axis == Direction.Axis.X ? bx : bx + dp;
|
||||
int pz = axis == Direction.Axis.Z ? bz : bz + dp;
|
||||
BlockPos pos = new BlockPos(px, centerY + dy, pz);
|
||||
|
||||
if (!canReplace(level.getBlockState(pos))) continue;
|
||||
|
||||
// Block material mix: mostly mossy log, some fresh log patches, some moss
|
||||
float r = random.nextFloat();
|
||||
BlockState toPlace;
|
||||
if (r < 0.08f) {
|
||||
toPlace = Blocks.MOSS_BLOCK.defaultBlockState();
|
||||
} else if (r < 0.22f) {
|
||||
toPlace = freshLogState; // fresher wood, less decayed patch
|
||||
} else if (r < 0.32f) {
|
||||
toPlace = woodState;
|
||||
} else {
|
||||
toPlace = mossyLogState;
|
||||
}
|
||||
|
||||
level.setBlock(pos, toPlace, 2);
|
||||
placed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Moss patches scattered along the log's footprint
|
||||
int mossCount = 20 + random.nextInt(25);
|
||||
for (int i = 0; i < mossCount; i++) {
|
||||
int mx = origin.getX() + random.nextInt(length + 6) - 3;
|
||||
int mz = axis == Direction.Axis.X
|
||||
? origin.getZ() + random.nextInt(9) - 4
|
||||
: origin.getZ() + random.nextInt(length + 6) - 3;
|
||||
int my = level.getHeight(Heightmap.Types.WORLD_SURFACE_WG, mx, mz);
|
||||
BlockPos mossPos = new BlockPos(mx, my, mz);
|
||||
|
||||
if (!canReplace(level.getBlockState(mossPos))) continue;
|
||||
BlockState below = level.getBlockState(mossPos.below());
|
||||
if (!below.isFaceSturdy(level, mossPos.below(), Direction.UP)) continue;
|
||||
|
||||
level.setBlock(mossPos,
|
||||
random.nextFloat() < 0.35f
|
||||
? Blocks.MOSS_BLOCK.defaultBlockState()
|
||||
: Blocks.MOSS_CARPET.defaultBlockState(),
|
||||
2);
|
||||
}
|
||||
|
||||
return placed;
|
||||
}
|
||||
|
||||
private static boolean canReplace(BlockState state) {
|
||||
return state.isAir() || state.canBeReplaced() || (state.getBlock() instanceof LeavesBlock);
|
||||
}
|
||||
}
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
package com.craisinlord.antarchy.content.worldgen.elythia;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.level.WorldGenLevel;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.HugeMushroomBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import net.minecraft.world.level.levelgen.feature.Feature;
|
||||
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
||||
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
|
||||
|
||||
public class FungalMushroomFeature extends Feature<NoneFeatureConfiguration> {
|
||||
|
||||
public FungalMushroomFeature(Codec<NoneFeatureConfiguration> codec) {
|
||||
super(codec);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean place(FeaturePlaceContext<NoneFeatureConfiguration> context) {
|
||||
WorldGenLevel level = context.level();
|
||||
RandomSource random = context.random();
|
||||
BlockPos origin = context.origin();
|
||||
|
||||
boolean isRed = random.nextBoolean();
|
||||
Block capBlock = isRed ? Blocks.RED_MUSHROOM_BLOCK : Blocks.BROWN_MUSHROOM_BLOCK;
|
||||
Block smallMushroom = isRed ? Blocks.RED_MUSHROOM : Blocks.BROWN_MUSHROOM;
|
||||
|
||||
// 1-in-3 chance of a large mushroom (~3x the small variant)
|
||||
boolean isLarge = random.nextInt(3) == 0;
|
||||
|
||||
int stemSize = isLarge ? (2 + random.nextInt(3)) : (random.nextBoolean() ? 2 : 3);
|
||||
int stemHeight = isLarge ? (18 + random.nextInt(19)) : (6 + random.nextInt(7)); // large: 18–36, small: 6–12
|
||||
|
||||
// Lean: stem drifts in a random horizontal direction over its height
|
||||
double leanAngle = random.nextDouble() * Math.PI * 2;
|
||||
double leanDX = Math.cos(leanAngle);
|
||||
double leanDZ = Math.sin(leanAngle);
|
||||
double maxLean = isLarge
|
||||
? (6.0 + random.nextDouble() * 10.0) // large: 6–16 block lean
|
||||
: (2.0 + random.nextDouble() * 3.5); // small: 2–5.5 block lean
|
||||
|
||||
int baseY = origin.getY();
|
||||
int stemOffset = stemSize == 2 ? 0 : -1; // center 3x3 on origin
|
||||
|
||||
// Pore-only stem state (inner faces; sides visible from outside)
|
||||
BlockState stemPore = Blocks.MUSHROOM_STEM.defaultBlockState()
|
||||
.setValue(HugeMushroomBlock.NORTH, false)
|
||||
.setValue(HugeMushroomBlock.SOUTH, false)
|
||||
.setValue(HugeMushroomBlock.EAST, false)
|
||||
.setValue(HugeMushroomBlock.WEST, false)
|
||||
.setValue(HugeMushroomBlock.UP, false)
|
||||
.setValue(HugeMushroomBlock.DOWN, false);
|
||||
BlockState stemSide = Blocks.MUSHROOM_STEM.defaultBlockState()
|
||||
.setValue(HugeMushroomBlock.NORTH, true)
|
||||
.setValue(HugeMushroomBlock.SOUTH, true)
|
||||
.setValue(HugeMushroomBlock.EAST, true)
|
||||
.setValue(HugeMushroomBlock.WEST, true)
|
||||
.setValue(HugeMushroomBlock.UP, false)
|
||||
.setValue(HugeMushroomBlock.DOWN, false);
|
||||
|
||||
// Place leaning stem
|
||||
for (int dy = 0; dy < stemHeight; dy++) {
|
||||
double leanProgress = (double) dy / stemHeight;
|
||||
int leanX = (int) Math.round(leanDX * maxLean * leanProgress);
|
||||
int leanZ = (int) Math.round(leanDZ * maxLean * leanProgress);
|
||||
|
||||
for (int dx = 0; dx < stemSize; dx++) {
|
||||
for (int dz = 0; dz < stemSize; dz++) {
|
||||
BlockPos pos = new BlockPos(
|
||||
origin.getX() + stemOffset + dx + leanX,
|
||||
baseY + dy,
|
||||
origin.getZ() + stemOffset + dz + leanZ);
|
||||
if (canReplace(level.getBlockState(pos))) {
|
||||
// Outer ring shows bark, interior is pores
|
||||
boolean isEdge = (dx == 0 || dx == stemSize - 1 || dz == 0 || dz == stemSize - 1);
|
||||
level.setBlock(pos, isEdge ? stemSide : stemPore, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cap: cone-shaped, follows the lean, with irregular per-block radius noise
|
||||
double capCenterX = origin.getX() + (stemSize == 2 ? 0.5 : 0) + leanDX * maxLean;
|
||||
double capCenterZ = origin.getZ() + (stemSize == 2 ? 0.5 : 0) + leanDZ * maxLean;
|
||||
int capTopY = baseY + stemHeight;
|
||||
int baseCapRadius = isLarge
|
||||
? (stemSize + 7 + random.nextInt(6)) // large: ~11–18 at base
|
||||
: (stemSize + 2 + random.nextInt(2)); // small: 4–6 at base
|
||||
|
||||
// Per-position radius jitter table — sampled before the loop for consistency
|
||||
// Each (dx, dz) slot gets a random ±1.5 bias baked in
|
||||
int jitterRange = baseCapRadius + 4;
|
||||
float[][] jitter = new float[jitterRange * 2 + 1][jitterRange * 2 + 1];
|
||||
for (float[] row : jitter) {
|
||||
for (int j = 0; j < row.length; j++) {
|
||||
row[j] = random.nextFloat() * 3.0f - 1.5f; // ±1.5 blocks
|
||||
}
|
||||
}
|
||||
|
||||
int capLayers = baseCapRadius + 2;
|
||||
for (int cl = 0; cl < capLayers; cl++) {
|
||||
int capY = capTopY + cl;
|
||||
double nomRadius = baseCapRadius - cl;
|
||||
if (nomRadius < 0) break;
|
||||
|
||||
// The cap center also shifts slightly with lean for a drooping overhang feel
|
||||
double layerCapX = capCenterX + leanDX * cl * 0.3;
|
||||
double layerCapZ = capCenterZ + leanDZ * cl * 0.3;
|
||||
|
||||
for (int dx = -(jitterRange); dx <= jitterRange; dx++) {
|
||||
for (int dz = -(jitterRange); dz <= jitterRange; dz++) {
|
||||
double dist = Math.sqrt(
|
||||
(origin.getX() + dx - layerCapX) * (origin.getX() + dx - layerCapX)
|
||||
+ (origin.getZ() + dz - layerCapZ) * (origin.getZ() + dz - layerCapZ));
|
||||
|
||||
float j = jitter[dx + jitterRange][dz + jitterRange];
|
||||
double effectiveRadius = nomRadius + j;
|
||||
|
||||
if (dist > effectiveRadius + 0.5) continue;
|
||||
if (effectiveRadius < 0) continue;
|
||||
|
||||
BlockPos capPos = new BlockPos(origin.getX() + dx, capY, origin.getZ() + dz);
|
||||
if (!canReplace(level.getBlockState(capPos))) continue;
|
||||
|
||||
boolean isOuter = dist >= effectiveRadius - 0.7;
|
||||
boolean isTop = cl == capLayers - 1;
|
||||
|
||||
BlockState capState = capBlock.defaultBlockState()
|
||||
.setValue(HugeMushroomBlock.UP, isTop || isOuter)
|
||||
.setValue(HugeMushroomBlock.NORTH, isOuter)
|
||||
.setValue(HugeMushroomBlock.SOUTH, isOuter)
|
||||
.setValue(HugeMushroomBlock.EAST, isOuter)
|
||||
.setValue(HugeMushroomBlock.WEST, isOuter)
|
||||
.setValue(HugeMushroomBlock.DOWN, false);
|
||||
|
||||
level.setBlock(capPos, capState, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mycelium patches around base
|
||||
int myceliumCount = isLarge ? (25 + random.nextInt(25)) : (12 + random.nextInt(12));
|
||||
for (int i = 0; i < myceliumCount; i++) {
|
||||
int radius = isLarge ? (stemSize + 8 + random.nextInt(8)) : (stemSize + 3 + random.nextInt(3));
|
||||
int mx = origin.getX() + random.nextInt(radius * 2 + 1) - radius;
|
||||
int mz = origin.getZ() + random.nextInt(radius * 2 + 1) - radius;
|
||||
int my = level.getHeight(Heightmap.Types.WORLD_SURFACE_WG, mx, mz) - 1;
|
||||
BlockPos myceliumPos = new BlockPos(mx, my, mz);
|
||||
|
||||
BlockState existing = level.getBlockState(myceliumPos);
|
||||
if (existing.is(Blocks.GRASS_BLOCK) || existing.is(Blocks.DIRT)
|
||||
|| existing.is(Blocks.MOSS_BLOCK) || existing.is(Blocks.ROOTED_DIRT)) {
|
||||
level.setBlock(myceliumPos, Blocks.MYCELIUM.defaultBlockState(), 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Small mushrooms scattered around
|
||||
int smallCount = isLarge ? (10 + random.nextInt(15)) : (5 + random.nextInt(8));
|
||||
for (int i = 0; i < smallCount; i++) {
|
||||
int radius = isLarge ? (stemSize + 10 + random.nextInt(10)) : (stemSize + 4 + random.nextInt(4));
|
||||
int sx = origin.getX() + random.nextInt(radius * 2 + 1) - radius;
|
||||
int sz = origin.getZ() + random.nextInt(radius * 2 + 1) - radius;
|
||||
int sy = level.getHeight(Heightmap.Types.WORLD_SURFACE_WG, sx, sz);
|
||||
BlockPos smallPos = new BlockPos(sx, sy, sz);
|
||||
|
||||
if (!canReplace(level.getBlockState(smallPos))) continue;
|
||||
BlockState below = level.getBlockState(smallPos.below());
|
||||
if (!below.isFaceSturdy(level, smallPos.below(), Direction.UP)) continue;
|
||||
|
||||
Block plant = random.nextBoolean() ? smallMushroom
|
||||
: (isRed ? Blocks.BROWN_MUSHROOM : Blocks.RED_MUSHROOM);
|
||||
BlockState plantState = plant.defaultBlockState();
|
||||
if (plantState.canSurvive(level, smallPos)) {
|
||||
level.setBlock(smallPos, plantState, 2);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean canReplace(BlockState state) {
|
||||
return state.isAir() || state.canBeReplaced()
|
||||
|| (state.getBlock() instanceof net.minecraft.world.level.block.LeavesBlock);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"variants": {
|
||||
"": {
|
||||
"model": "antarchy:block/bile_vein"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@
|
||||
"block.antarchy.amber_moss_block": "Amber Moss Block",
|
||||
"block.antarchy.amber_moss_carpet": "Amber Moss Carpet",
|
||||
"block.antarchy.amber_lichen": "Amber Lichen",
|
||||
"block.antarchy.bile_vein": "Bile Vein",
|
||||
"block.antarchy.duplicator_sapling": "Duplicator Sapling",
|
||||
"block.antarchy.creepvine": "Creepvine",
|
||||
"block.antarchy.duct_tape": "Duct Tape",
|
||||
@@ -272,6 +273,7 @@
|
||||
"item.antarchy.amber_moss_block": "Amber Moss Block",
|
||||
"item.antarchy.amber_moss_carpet": "Amber Moss Carpet",
|
||||
"item.antarchy.amber_lichen": "Amber Lichen",
|
||||
"item.antarchy.bile_vein": "Bile Vein",
|
||||
"item.antarchy.creepvine": "Creepvine",
|
||||
"item.antarchy.chiten": "Chiten",
|
||||
"item.antarchy.chiten_block": "Chiten Block",
|
||||
@@ -416,6 +418,7 @@
|
||||
"message.antarchy.big_bertha.mode.nightmare": "Nightmare",
|
||||
"message.antarchy.big_bertha.mode.kraken": "Kraken",
|
||||
"message.antarchy.big_bertha.mode.molevore": "Molevore",
|
||||
"message.antarchy.big_bertha.mode.toreterror": "Toreterror",
|
||||
"message.antarchy.ultimate_tool.mode_3x3": "Switched to 3x3 Mining",
|
||||
"message.antarchy.ultimate_tool.mode_default": "Switched to Default Mining",
|
||||
"advancements.antarchy.hey_listen.title": "Hey Listen",
|
||||
@@ -442,6 +445,7 @@
|
||||
"tooltip.antarchy.big_bertha.mode.nightmare": "Players suffer Dread; hits inflict weakness.",
|
||||
"tooltip.antarchy.big_bertha.mode.kraken": "Hits slam targets back and call lightning.",
|
||||
"tooltip.antarchy.big_bertha.mode.molevore": "Right-click to spin forward and drill through Molevore blocks.",
|
||||
"tooltip.antarchy.big_bertha.mode.toreterror": "Right-click to launch into the air and crash down with an AOE shockwave.",
|
||||
"tooltip.antarchy.ultimate_tools_3x3": "Shift-right-click to toggle 3x3 Mining.",
|
||||
"tooltip.antarchy.moggles.reveal": "Gives night vision and points to nearby caves.",
|
||||
"tooltip.antarchy.moggles.underground": "Works only while you have no sky access.",
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:block/cube_all",
|
||||
"textures": {
|
||||
"all": "antarchy:block/bile/bile_vein"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"parent": "antarchy:block/bile_vein"
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"textures": [
|
||||
"antarchy:stinky_fly"
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 954 B |
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"animation": {
|
||||
"frametime": 16,
|
||||
"interpolate": true,
|
||||
"frames": [
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
1
|
||||
]
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 468 B |
Binary file not shown.
|
After Width: | Height: | Size: 114 B |
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"type": "minecraft:block",
|
||||
"pools": [
|
||||
{
|
||||
"conditions": [
|
||||
{
|
||||
"condition": "minecraft:survives_explosion"
|
||||
}
|
||||
],
|
||||
"entries": [
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "antarchy:bile_vein"
|
||||
}
|
||||
],
|
||||
"rolls": 1.0
|
||||
}
|
||||
],
|
||||
"random_sequence": "antarchy:blocks/bile_vein"
|
||||
}
|
||||
@@ -37,11 +37,10 @@
|
||||
[],
|
||||
[],
|
||||
[
|
||||
"antarchy:cavaryn_bile_pools",
|
||||
"antarchy:cavaryn_amber_moss_patch",
|
||||
"antarchy:cavaryn_bile_veins",
|
||||
"antarchy:cavaryn_bile_cysts",
|
||||
"antarchy:cavaryn_wall_amber_moss",
|
||||
"antarchy:cavaryn_creepvine",
|
||||
"minecraft:glow_lichen",
|
||||
"antarchy:cavaryn_chiten_spikes",
|
||||
"antarchy:cavaryn_terror_egg_patch"
|
||||
],
|
||||
@@ -63,15 +62,16 @@
|
||||
"maxCount": 5
|
||||
}
|
||||
],
|
||||
"creature": [],
|
||||
"ambient": [
|
||||
"creature": [
|
||||
{
|
||||
"type": "minecraft:bat",
|
||||
"type": "antarchy:stink_bug",
|
||||
"weight": 10,
|
||||
"minCount": 4,
|
||||
"maxCount": 8
|
||||
"minCount": 1,
|
||||
"maxCount": 3
|
||||
}
|
||||
],
|
||||
"ambient": [
|
||||
],
|
||||
"axolotls": [],
|
||||
"underground_water_creature": [],
|
||||
"water_creature": [],
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
{
|
||||
"has_precipitation": false,
|
||||
"temperature": 0.78,
|
||||
"downfall": 0.95,
|
||||
"effects": {
|
||||
"fog_color": 8084735,
|
||||
"water_color": 5021432,
|
||||
"water_fog_color": 2502722,
|
||||
"sky_color": 8084735,
|
||||
"foliage_color": 2867501,
|
||||
"grass_color": 4304168,
|
||||
"grass_color_modifier": "none",
|
||||
"particle": {
|
||||
"probability": 0.009,
|
||||
"options": {
|
||||
"type": "minecraft:spore_blossom_air"
|
||||
}
|
||||
},
|
||||
"mood_sound": {
|
||||
"sound": "minecraft:ambient.crimson_forest.mood",
|
||||
"tick_delay": 6000,
|
||||
"block_search_extent": 8,
|
||||
"offset": 2.0
|
||||
}
|
||||
},
|
||||
"spawn_costs": {},
|
||||
"carvers": {
|
||||
"air": [],
|
||||
"liquid": []
|
||||
},
|
||||
"features": [
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
"minecraft:ore_coal_upper",
|
||||
"minecraft:ore_coal_lower",
|
||||
"minecraft:ore_iron_upper",
|
||||
"minecraft:ore_iron_middle",
|
||||
"minecraft:ore_iron_small",
|
||||
"minecraft:ore_gold",
|
||||
"minecraft:ore_gold_lower",
|
||||
"minecraft:ore_redstone",
|
||||
"minecraft:ore_redstone_lower",
|
||||
"minecraft:ore_diamond",
|
||||
"minecraft:ore_diamond_medium",
|
||||
"minecraft:ore_diamond_large",
|
||||
"minecraft:ore_diamond_buried",
|
||||
"minecraft:ore_lapis",
|
||||
"minecraft:ore_lapis_buried",
|
||||
"minecraft:ore_copper"
|
||||
],
|
||||
[
|
||||
"antarchy:elythia_underground",
|
||||
"minecraft:large_dripstone",
|
||||
"minecraft:pointed_dripstone"
|
||||
],
|
||||
[],
|
||||
[
|
||||
"antarchy:ouranwood_trees_sparse",
|
||||
"antarchy:elythia_forest_flora",
|
||||
"antarchy:elythia_brown_ant_nests",
|
||||
"antarchy:fallen_ouranwood_tree",
|
||||
"antarchy:fungal_mushroom"
|
||||
],
|
||||
[]
|
||||
],
|
||||
"creature_spawn_probability": 0.07,
|
||||
"spawners": {
|
||||
"monster": [],
|
||||
"creature": [
|
||||
{
|
||||
"type": "antarchy:caterpillar",
|
||||
"weight": 5,
|
||||
"minCount": 1,
|
||||
"maxCount": 2
|
||||
},
|
||||
{
|
||||
"type": "antarchy:flying_squirrel",
|
||||
"weight": 2,
|
||||
"minCount": 1,
|
||||
"maxCount": 2
|
||||
}
|
||||
],
|
||||
"ambient": [
|
||||
{
|
||||
"type": "antarchy:butterfly",
|
||||
"weight": 7,
|
||||
"minCount": 1,
|
||||
"maxCount": 2
|
||||
}
|
||||
],
|
||||
"axolotls": [],
|
||||
"underground_water_creature": [],
|
||||
"water_creature": [],
|
||||
"water_ambient": [],
|
||||
"misc": []
|
||||
}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"type": "antarchy:cavaryn_bile_cysts",
|
||||
"config": {}
|
||||
}
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"type": "antarchy:cavaryn_bile_pools",
|
||||
"config": {}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"type": "antarchy:cavaryn_bile_veins",
|
||||
"config": {}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"type": "antarchy:fallen_ouranwood_tree",
|
||||
"config": {}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"type": "antarchy:fungal_mushroom",
|
||||
"config": {}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
"sea_level": 32,
|
||||
"disable_mob_generation": false,
|
||||
"aquifers_enabled": true,
|
||||
"ore_veins_enabled": true,
|
||||
"ore_veins_enabled": false,
|
||||
"legacy_random_source": false,
|
||||
"default_block": {
|
||||
"Name": "antarchy:myrmite"
|
||||
@@ -99,73 +99,9 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"vein_toggle": {
|
||||
"type": "minecraft:interpolated",
|
||||
"argument": {
|
||||
"type": "minecraft:range_choice",
|
||||
"input": "minecraft:y",
|
||||
"min_inclusive": 0,
|
||||
"max_exclusive": 208,
|
||||
"when_in_range": {
|
||||
"type": "minecraft:noise",
|
||||
"noise": "minecraft:ore_veininess",
|
||||
"xz_scale": 1.5,
|
||||
"y_scale": 1.5
|
||||
},
|
||||
"when_out_of_range": 0
|
||||
}
|
||||
},
|
||||
"vein_ridged": {
|
||||
"type": "minecraft:add",
|
||||
"argument1": -0.07999999821186066,
|
||||
"argument2": {
|
||||
"type": "minecraft:max",
|
||||
"argument1": {
|
||||
"type": "minecraft:abs",
|
||||
"argument": {
|
||||
"type": "minecraft:interpolated",
|
||||
"argument": {
|
||||
"type": "minecraft:range_choice",
|
||||
"input": "minecraft:y",
|
||||
"min_inclusive": 0,
|
||||
"max_exclusive": 208,
|
||||
"when_in_range": {
|
||||
"type": "minecraft:noise",
|
||||
"noise": "minecraft:ore_vein_a",
|
||||
"xz_scale": 4,
|
||||
"y_scale": 4
|
||||
},
|
||||
"when_out_of_range": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"argument2": {
|
||||
"type": "minecraft:abs",
|
||||
"argument": {
|
||||
"type": "minecraft:interpolated",
|
||||
"argument": {
|
||||
"type": "minecraft:range_choice",
|
||||
"input": "minecraft:y",
|
||||
"min_inclusive": 0,
|
||||
"max_exclusive": 208,
|
||||
"when_in_range": {
|
||||
"type": "minecraft:noise",
|
||||
"noise": "minecraft:ore_vein_b",
|
||||
"xz_scale": 4,
|
||||
"y_scale": 4
|
||||
},
|
||||
"when_out_of_range": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"vein_gap": {
|
||||
"type": "minecraft:noise",
|
||||
"noise": "minecraft:ore_gap",
|
||||
"xz_scale": 1,
|
||||
"y_scale": 1
|
||||
}
|
||||
"vein_toggle": 0,
|
||||
"vein_ridged": 0,
|
||||
"vein_gap": 0
|
||||
},
|
||||
"spawn_target": [
|
||||
{
|
||||
|
||||
@@ -430,7 +430,7 @@
|
||||
},
|
||||
"then_run": {
|
||||
"type": "minecraft:block",
|
||||
"result_state": { "Name": "minecraft:gravel" }
|
||||
"result_state": { "Name": "minecraft:sand" }
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -511,7 +511,7 @@
|
||||
},
|
||||
"then_run": {
|
||||
"type": "minecraft:block",
|
||||
"result_state": { "Name": "minecraft:gravel" }
|
||||
"result_state": { "Name": "minecraft:sand" }
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"feature": "antarchy:cavaryn_bile_pools",
|
||||
"feature": "antarchy:cavaryn_bile_cysts",
|
||||
"placement": [
|
||||
{
|
||||
"type": "minecraft:count",
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"feature": "antarchy:cavaryn_bile_veins",
|
||||
"placement": [
|
||||
{
|
||||
"type": "minecraft:count",
|
||||
"count": 5
|
||||
},
|
||||
{
|
||||
"type": "minecraft:in_square"
|
||||
},
|
||||
{
|
||||
"type": "minecraft:height_range",
|
||||
"height": {
|
||||
"type": "minecraft:uniform",
|
||||
"min_inclusive": {
|
||||
"above_bottom": 8
|
||||
},
|
||||
"max_inclusive": {
|
||||
"below_top": 16
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "minecraft:biome"
|
||||
}
|
||||
]
|
||||
}
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
"placement": [
|
||||
{
|
||||
"type": "minecraft:count",
|
||||
"count": 2
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"type": "minecraft:in_square"
|
||||
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"feature": "antarchy:fallen_ouranwood_tree",
|
||||
"placement": [
|
||||
{ "type": "minecraft:rarity_filter", "chance": 5 },
|
||||
{ "type": "minecraft:in_square" },
|
||||
{ "type": "minecraft:heightmap", "heightmap": "WORLD_SURFACE_WG" },
|
||||
{ "type": "minecraft:biome" }
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"feature": "antarchy:fungal_mushroom",
|
||||
"placement": [
|
||||
{ "type": "minecraft:rarity_filter", "chance": 4 },
|
||||
{ "type": "minecraft:in_square" },
|
||||
{ "type": "minecraft:heightmap", "heightmap": "WORLD_SURFACE_WG" },
|
||||
{ "type": "minecraft:biome" }
|
||||
]
|
||||
}
|
||||
@@ -37,6 +37,7 @@
|
||||
"antarchy:nyxite_brick_slab",
|
||||
"antarchy:nyxite_brick_wall",
|
||||
"antarchy:myrmite",
|
||||
"antarchy:bile_vein",
|
||||
"antarchy:chiten_block",
|
||||
"antarchy:chiten_spike",
|
||||
"antarchy:shellstone",
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
"antarchy:shellstone_brick_stairs",
|
||||
"antarchy:shellstone_brick_slab",
|
||||
"antarchy:shellstone_brick_wall",
|
||||
"antarchy:chiten_block"
|
||||
"antarchy:chiten_block",
|
||||
"antarchy:bile_vein"
|
||||
]
|
||||
}
|
||||
Reference in new issue
Block a user