Compare commits

..
Author SHA1 Message Date
craisinlord 58fdbd84cf Revise README 2026-10-26 17:20:19 -05:00
craisinlord 1dbbe47364 Update README 2026-10-26 17:19:38 -05:00
craisinlord c4e157671f 2.2.9
2.2.9
2026-10-26 16:53:02 -05:00
craisinlord 8626d205f7 2.2.9 2026-10-26 16:52:32 -05:00
craisinlord 5a8cb58cb0 2.2.9 2026-10-25 13:24:58 -05:00
craisinlord 3700359dfb ultimate tool vein mining 2026-10-21 19:45:43 -05:00
craisinlord e505367aed Merge pull request #81 from craisinlord/anthology-split
2.2.6
2026-10-20 10:24:44 -05:00
craisinlord c00d57e4e0 2.2.6 2026-10-20 10:23:25 -05:00
craisinlord ffadad3caf Merge pull request #79 from craisinlord/anthology-split
2.2.5
2026-10-17 14:46:58 -05:00
craisinlord 758fa58b1b 2.2.5
add missing local jars to git
2026-10-17 14:41:03 -05:00
craisinlord 770b5a607e fix apotheosis 1.20 crash 2026-10-16 15:34:52 -05:00
craisinlord 333269c3da perf improvements with portal guns
fix infinity crash
2026-10-16 14:55:59 -05:00
craisinlord 2c63c7bb0b Merge pull request #75 from craisinlord/anthology-split
1.20 backport
2026-10-14 17:43:07 -05:00
craisinlord d54264c6c8 1.20 backport 2026-10-14 17:39:56 -05:00
craisinlord adb7372f3f Merge pull request #74 from craisinlord/anthology-split
Anthology split
2026-10-13 08:37:52 -05:00
craisinlord f7e7bebac3 anthology split 2026-10-12 19:55:08 -05:00
craisinlord bba2a56671 Move gravity direction system to Anthology
Gravity API, mixins, projectile compat, inverted effect, gravity sync and
/gravity now live in the Anthology library. Antarchy registers the Underside
region, antiwater, stale-inversion cleanup and portal gun camera roll through
GravityHooks, and depends on the local Anthology jar in anthology_jars/.
2026-10-12 15:37:13 -05:00
craisinlord 0cad456efd improve portal gun perf 2026-10-12 15:00:42 -05:00
5212 changed files with 72795 additions and 98578 deletions

No files matched your search

+4 -1
View File
@@ -2,8 +2,11 @@ https://www.curseforge.com/minecraft/mc-mods/antarchy
ANTS! ANTS! ANTS! ANTS! ANTS! ANTS!
Antarchy requires Architectury API, AntOS, Integrated API, GeckoLib, and Sizeable Foliage. Antarchy requires Architectury API, Anthology API, AntOS, Integrated API, GeckoLib, and Sizeable Foliage.
## Credits ## Credits
Russian localization: suheckii Russian localization: suheckii
NOTICE: SOME generative AI (claude code) was used as a tool to create this mod, including for things such as performance improvements and porting to other versions. This mod was not vibe coded, and has no AI generated art. I do not support AI generated art.
Every penny that was spent on AI for my minecraft projects, I matched that as a donation to environmental causes.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
-10
View File
@@ -10,9 +10,6 @@ allprojects {
group = rootProject.maven_group group = rootProject.maven_group
repositories { repositories {
// CurseForge Maven artifacts must be resolved from CurseMaven. The
// Fabric repository does not proxy these coordinates reliably and can
// prevent Gradle from reaching the working repository.
maven { maven {
name = "CurseMaven" name = "CurseMaven"
url = "https://www.cursemaven.com" url = "https://www.cursemaven.com"
@@ -63,13 +60,10 @@ allprojects {
} }
// Don't build the root project itself.
tasks.named('jar') { tasks.named('jar') {
enabled = false enabled = false
} }
// Delegate forge-1.20.1 tasks to its own Gradle 8.8 wrapper. ForgeGradle 6 can't run
// on Gradle 9 and includeBuild can't mix Gradle versions, so we shell out instead.
def forge1201Dir = file('forge-1.20.1') def forge1201Dir = file('forge-1.20.1')
def forge1201Wrapper = providers.systemProperty('os.name').get().toLowerCase().contains('win') def forge1201Wrapper = providers.systemProperty('os.name').get().toLowerCase().contains('win')
? new File(forge1201Dir, 'gradlew.bat') ? new File(forge1201Dir, 'gradlew.bat')
@@ -84,10 +78,6 @@ def forge1201Wrapper = providers.systemProperty('os.name').get().toLowerCase().c
} }
} }
// Delegate fabric-1.20.1 tasks to its own standalone Gradle wrapper. Fabric Loom's
// build-wide tinyRemapperService isn't classloader-safe across two loom projects
// targeting different Minecraft versions in the same Gradle invocation, so
// fabric-1.20.1 can't be a normal included subproject alongside fabric-1.21.1.
def fabric120Dir = file('fabric-1.20.1') def fabric120Dir = file('fabric-1.20.1')
def fabric120Wrapper = providers.systemProperty('os.name').get().toLowerCase().contains('win') def fabric120Wrapper = providers.systemProperty('os.name').get().toLowerCase().contains('win')
? new File(fabric120Dir, 'gradlew.bat') ? new File(fabric120Dir, 'gradlew.bat')
-1
View File
@@ -6,7 +6,6 @@ base {
archivesName = "${mod_id}-common-1.20.1" archivesName = "${mod_id}-common-1.20.1"
} }
// Source-only module — each loader module compiles these sources itself.
tasks.named('compileJava').configure { tasks.named('compileJava').configure {
enabled = false enabled = false
} }
@@ -1,6 +1,9 @@
package com.craisinlord.antarchy; package com.craisinlord.antarchy;
import com.craisinlord.antarchy.content.computer.AntarchyArchiveLocators;
import com.craisinlord.antarchy.content.AntarchyAnthologyHooks;
import com.craisinlord.antarchy.content.util.AttributeRangeInit; import com.craisinlord.antarchy.content.util.AttributeRangeInit;
import com.craisinlord.antarchy.content.worldgen.VillagePoolAdditions;
import com.craisinlord.integrated_api.events.lifecycle.ServerGoingToStartEvent; import com.craisinlord.integrated_api.events.lifecycle.ServerGoingToStartEvent;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@@ -8,12 +11,17 @@ import org.apache.logging.log4j.Logger;
public class Antarchy { public class Antarchy {
public static final String MODID = "antarchy"; public static final String MODID = "antarchy";
public static final String MOD_VERSION = "2.0.0";
public static final Logger LOGGER = LogManager.getLogger(); public static final Logger LOGGER = LogManager.getLogger();
public static volatile boolean physicalClient;
public static void init() { public static void init() {
AttributeRangeInit.apply(); AttributeRangeInit.apply();
AntarchyArchiveLocators.register();
AntarchyAnthologyHooks.register();
ServerGoingToStartEvent.EVENT.addListener(Antarchy::serverAboutToStart); ServerGoingToStartEvent.EVENT.addListener(Antarchy::serverAboutToStart);
} }
private static void serverAboutToStart(final ServerGoingToStartEvent event) { private static void serverAboutToStart(final ServerGoingToStartEvent event) {
VillagePoolAdditions.apply(event.getServer());
} }
} }
@@ -0,0 +1,77 @@
package com.craisinlord.antarchy.compat.entity;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.attributes.Attribute;
import net.minecraft.world.entity.ai.attributes.AttributeInstance;
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
import net.minecraft.world.entity.player.Player;
import org.jetbrains.annotations.Nullable;
public final class EntityReach {
public static final double DEFAULT_ENTITY_INTERACTION_RANGE = 3.0D;
public static final double DEFAULT_BLOCK_INTERACTION_RANGE = 4.5D;
private static final double CREATIVE_ENTITY_BONUS = 2.0D;
private static final double CREATIVE_BLOCK_BONUS = 0.5D;
private EntityReach() {
}
@Nullable
public static Attribute attribute() {
java.util.function.Supplier<Attribute> supplier = AntarchyObjects.ENTITY_REACH;
return supplier == null ? null : supplier.get();
}
@Nullable
public static AttributeInstance instance(LivingEntity entity) {
Attribute attribute = attribute();
return attribute == null ? null : entity.getAttribute(attribute);
}
public static double entityInteractionRange(LivingEntity entity) {
AttributeInstance instance = instance(entity);
double range = instance != null ? instance.getValue() : DEFAULT_ENTITY_INTERACTION_RANGE;
if (entity instanceof Player player && player.isCreative()) {
range += CREATIVE_ENTITY_BONUS;
}
return range;
}
public static double blockInteractionRange(Player player) {
return DEFAULT_BLOCK_INTERACTION_RANGE + (player.isCreative() ? CREATIVE_BLOCK_BONUS : 0.0D);
}
public static UUID modifierId(ResourceLocation id) {
return UUID.nameUUIDFromBytes(id.toString().getBytes(StandardCharsets.UTF_8));
}
public static AttributeModifier modifier(ResourceLocation id, double amount, AttributeModifier.Operation operation) {
return new AttributeModifier(modifierId(id), id.toString(), amount, operation);
}
public static void addModifier(ImmutableMultimap.Builder<Attribute, AttributeModifier> builder, ResourceLocation id, double amount) {
Attribute attribute = attribute();
if (attribute != null) {
builder.put(attribute, modifier(id, amount, AttributeModifier.Operation.ADDITION));
}
}
public static Multimap<Attribute, AttributeModifier> withMainhandModifier(Multimap<Attribute, AttributeModifier> base, EquipmentSlot slot,
ResourceLocation id, double amount) {
Attribute attribute = attribute();
if (slot != EquipmentSlot.MAINHAND || attribute == null) {
return base;
}
ImmutableMultimap.Builder<Attribute, AttributeModifier> builder = ImmutableMultimap.builder();
builder.putAll(base);
builder.put(attribute, modifier(id, amount, AttributeModifier.Operation.ADDITION));
return builder.build();
}
}
@@ -4,6 +4,7 @@ import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.RandomSource; import net.minecraft.util.RandomSource;
public interface InfinityCompatBridge { public interface InfinityCompatBridge {
@@ -22,15 +23,14 @@ public interface InfinityCompatBridge {
return getRandomDimensionId(random); return getRandomDimensionId(random);
} }
default boolean requestWarp(ServerPlayer player, ResourceLocation dimensionId) { default InfinityWarpResult requestWarp(ServerPlayer player, ResourceLocation dimensionId) {
return false; return InfinityWarpResult.REJECTED;
}
default InfinityWarpResult requestDimensionCreation(MinecraftServer server, ResourceLocation dimensionId) {
return InfinityWarpResult.REJECTED;
} }
/**
* Converts an already-ignited vanilla Nether portal frame at {@code anyPortalBlockPos} into a real, permanent
* Infinite Dimensions portal to {@code dimensionId}, generating the dimension first if it doesn't exist yet.
* Mirrors what Infinity itself does when a written book is thrown into a lit portal.
*/
default boolean createPhysicalPortal(ServerLevel level, BlockPos anyPortalBlockPos, ResourceLocation dimensionId) { default boolean createPhysicalPortal(ServerLevel level, BlockPos anyPortalBlockPos, ResourceLocation dimensionId) {
return false; return false;
} }
@@ -0,0 +1,86 @@
package com.craisinlord.antarchy.compat.infinity;
import com.craisinlord.antarchy.Antarchy;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
public final class InfinityConfigRefresh {
private static final Map<String, Registry<?>> CHECKED_FILES = Map.of(
"mobs.json", BuiltInRegistries.ENTITY_TYPE,
"items.json", BuiltInRegistries.ITEM,
"effects.json", BuiltInRegistries.MOB_EFFECT
);
private static final Set<String> DISABLED_IDS = Set.of("antarchy:paralyzed");
private InfinityConfigRefresh() {
}
public static void refreshIfStale(Path configDir) {
Path modularDir = configDir.resolve("infinity").resolve("modular");
Path invocationLock = modularDir.resolve("invocation.lock");
if (!Files.exists(invocationLock)) {
return;
}
Path antarchyDir = modularDir.resolve(Antarchy.MODID);
List<String> staleIds = new ArrayList<>();
CHECKED_FILES.forEach((fileName, registry) -> collectStaleIds(antarchyDir.resolve(fileName), registry, staleIds));
if (staleIds.isEmpty()) {
return;
}
try {
Files.delete(invocationLock);
Antarchy.LOGGER.info(
"[Antarchy] Infinite Dimensions config lists unregistered or disabled Antarchy content {}; its config will regenerate on next world join",
staleIds
);
} catch (Exception exception) {
Antarchy.LOGGER.warn("[Antarchy] Failed to reset stale Infinite Dimensions config at {}", invocationLock, exception);
}
}
private static void collectStaleIds(Path file, Registry<?> registry, List<String> staleIds) {
if (!Files.exists(file)) {
return;
}
try (Reader reader = Files.newBufferedReader(file, StandardCharsets.UTF_8)) {
JsonElement root = JsonParser.parseReader(reader);
if (!root.isJsonObject() || !root.getAsJsonObject().has("elements")) {
return;
}
for (JsonElement element : root.getAsJsonObject().getAsJsonArray("elements")) {
if (!element.isJsonObject()) {
continue;
}
JsonObject entry = element.getAsJsonObject();
if (!entry.has("key")) {
continue;
}
String key = entry.get("key").getAsString();
ResourceLocation id = ResourceLocation.tryParse(key);
if (id != null && Antarchy.MODID.equals(id.getNamespace()) && !registry.containsKey(id)) {
staleIds.add(key);
} else if (DISABLED_IDS.contains(key) && (!entry.has("weight") || entry.get("weight").getAsDouble() > 0.0D)) {
staleIds.add(key);
}
}
} catch (Exception exception) {
Antarchy.LOGGER.warn("[Antarchy] Failed to read Infinite Dimensions config {}", file, exception);
}
}
}
@@ -1,6 +1,5 @@
package com.craisinlord.antarchy.compat.infinity; package com.craisinlord.antarchy.compat.infinity;
/** Shared result vocabulary for future asynchronous Infinity dimension integrations. */
public enum InfinityWarpResult { public enum InfinityWarpResult {
REJECTED, REJECTED,
PENDING, PENDING,
@@ -2,10 +2,8 @@ package com.craisinlord.antarchy.compat.item;
import java.util.function.Function; import java.util.function.Function;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
/** NBT-backed stand-in for the 1.20.1 port of Minecraft's 1.20.5+ item components. */
public final class AntarchyItemComponent<T> { public final class AntarchyItemComponent<T> {
private final String key; private final String key;
private final Function<CompoundTag, T> reader; private final Function<CompoundTag, T> reader;
@@ -22,14 +20,22 @@ public final class AntarchyItemComponent<T> {
} }
public T get(ItemStack stack) { public T get(ItemStack stack) {
if (!this.has(stack)) {
return null;
}
return this.reader.apply(stack.getTag()); return this.reader.apply(stack.getTag());
} }
public T getOrDefault(ItemStack stack, T fallback) { public T getOrDefault(ItemStack stack, T fallback) {
return this.has(stack) ? this.get(stack) : fallback; T value = this.get(stack);
return value != null ? value : fallback;
} }
public void set(ItemStack stack, T value) { public void set(ItemStack stack, T value) {
if (value == null) {
this.remove(stack);
return;
}
Object encoded = this.writer.apply(value); Object encoded = this.writer.apply(value);
CompoundTag tag = stack.getOrCreateTag(); CompoundTag tag = stack.getOrCreateTag();
if (encoded instanceof Integer integer) tag.putInt(this.key, integer); if (encoded instanceof Integer integer) tag.putInt(this.key, integer);
@@ -49,7 +55,7 @@ public final class AntarchyItemComponent<T> {
return new AntarchyItemComponent<>(key, tag -> tag.getInt(key), value -> value); return new AntarchyItemComponent<>(key, tag -> tag.getInt(key), value -> value);
} }
public static <T> AntarchyItemComponent<T> marker(String key) { public static AntarchyItemComponent<net.minecraft.util.Unit> marker(String key) {
return new AntarchyItemComponent<>(key, tag -> null, value -> true); return new AntarchyItemComponent<>(key, tag -> net.minecraft.util.Unit.INSTANCE, value -> true);
} }
} }
@@ -0,0 +1,17 @@
package com.craisinlord.antarchy.compat.item;
import net.minecraft.world.item.ArmorItem;
public final class ArmorDurability {
private ArmorDurability() {
}
public static int forType(ArmorItem.Type type, int multiplier) {
return switch (type) {
case HELMET -> 11 * multiplier;
case CHESTPLATE -> 16 * multiplier;
case LEGGINGS -> 15 * multiplier;
case BOOTS -> 13 * multiplier;
};
}
}
@@ -0,0 +1,46 @@
package com.craisinlord.antarchy.compat.item;
import com.craisinlord.antarchy.compat.entity.EntityReach;
import com.google.common.collect.ImmutableMultimap;
import java.util.UUID;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.ai.attributes.Attribute;
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.Tier;
public final class WeaponAttributes {
private WeaponAttributes() {
}
public static ImmutableMultimap.Builder<Attribute, AttributeModifier> base(Tier tier, float attackDamage, float attackSpeed) {
ImmutableMultimap.Builder<Attribute, AttributeModifier> builder = ImmutableMultimap.builder();
builder.put(Attributes.ATTACK_DAMAGE, new AttributeModifier(Ids.ATTACK_DAMAGE, "Weapon modifier",
attackDamage + tier.getAttackDamageBonus(), AttributeModifier.Operation.ADDITION));
builder.put(Attributes.ATTACK_SPEED, new AttributeModifier(Ids.ATTACK_SPEED, "Weapon modifier",
attackSpeed, AttributeModifier.Operation.ADDITION));
return builder;
}
public static void add(ImmutableMultimap.Builder<Attribute, AttributeModifier> builder, Attribute attribute, ResourceLocation id, double amount) {
builder.put(attribute, EntityReach.modifier(id, amount, AttributeModifier.Operation.ADDITION));
}
public static UUID baseAttackDamageId() {
return Ids.ATTACK_DAMAGE;
}
public static UUID baseAttackSpeedId() {
return Ids.ATTACK_SPEED;
}
private static final class Ids extends Item {
static final UUID ATTACK_DAMAGE = BASE_ATTACK_DAMAGE_UUID;
static final UUID ATTACK_SPEED = BASE_ATTACK_SPEED_UUID;
private Ids() {
super(new Item.Properties());
}
}
}
@@ -1,93 +0,0 @@
package com.craisinlord.antarchy.compat.network;
import io.netty.buffer.ByteBuf;
import net.minecraft.network.FriendlyByteBuf;
public final class ByteBufCodecs {
private ByteBufCodecs() {
}
public static final StreamCodec<ByteBuf, Integer> VAR_INT = new StreamCodec<>() {
@Override
public Integer decode(ByteBuf buf) {
return ((FriendlyByteBuf) buf).readVarInt();
}
@Override
public void encode(ByteBuf buf, Integer value) {
((FriendlyByteBuf) buf).writeVarInt(value);
}
};
public static final StreamCodec<ByteBuf, Long> VAR_LONG = new StreamCodec<>() {
@Override
public Long decode(ByteBuf buf) {
return ((FriendlyByteBuf) buf).readVarLong();
}
@Override
public void encode(ByteBuf buf, Long value) {
((FriendlyByteBuf) buf).writeVarLong(value);
}
};
public static final StreamCodec<ByteBuf, Boolean> BOOL = new StreamCodec<>() {
@Override
public Boolean decode(ByteBuf buf) {
return ((FriendlyByteBuf) buf).readBoolean();
}
@Override
public void encode(ByteBuf buf, Boolean value) {
((FriendlyByteBuf) buf).writeBoolean(value);
}
};
public static final StreamCodec<ByteBuf, Byte> BYTE = new StreamCodec<>() {
@Override
public Byte decode(ByteBuf buf) {
return ((FriendlyByteBuf) buf).readByte();
}
@Override
public void encode(ByteBuf buf, Byte value) {
((FriendlyByteBuf) buf).writeByte(value);
}
};
public static final StreamCodec<ByteBuf, Float> FLOAT = new StreamCodec<>() {
@Override
public Float decode(ByteBuf buf) {
return ((FriendlyByteBuf) buf).readFloat();
}
@Override
public void encode(ByteBuf buf, Float value) {
((FriendlyByteBuf) buf).writeFloat(value);
}
};
public static final StreamCodec<ByteBuf, Double> DOUBLE = new StreamCodec<>() {
@Override
public Double decode(ByteBuf buf) {
return ((FriendlyByteBuf) buf).readDouble();
}
@Override
public void encode(ByteBuf buf, Double value) {
((FriendlyByteBuf) buf).writeDouble(value);
}
};
public static final StreamCodec<ByteBuf, String> STRING_UTF8 = new StreamCodec<>() {
@Override
public String decode(ByteBuf buf) {
return ((FriendlyByteBuf) buf).readUtf();
}
@Override
public void encode(ByteBuf buf, String value) {
((FriendlyByteBuf) buf).writeUtf(value);
}
};
}
@@ -1,10 +0,0 @@
package com.craisinlord.antarchy.compat.network;
import net.minecraft.resources.ResourceLocation;
public interface CustomPacketPayload {
Type<? extends CustomPacketPayload> type();
record Type<T extends CustomPacketPayload>(ResourceLocation id) {
}
}
@@ -1,204 +0,0 @@
package com.craisinlord.antarchy.compat.network;
import java.util.function.Function;
public interface StreamCodec<B, V> {
V decode(B buf);
void encode(B buf, V value);
default <O> StreamCodec<B, O> map(Function<V, O> to, Function<O, V> from) {
StreamCodec<B, V> self = this;
return new StreamCodec<>() {
@Override
public O decode(B buf) {
return to.apply(self.decode(buf));
}
@Override
public void encode(B buf, O value) {
self.encode(buf, from.apply(value));
}
};
}
static <B, V> StreamCodec<B, V> unit(V value) {
return new StreamCodec<>() {
@Override
public V decode(B buf) {
return value;
}
@Override
public void encode(B buf, V value2) {
}
};
}
static <B, C1, V> StreamCodec<B, V> composite(
StreamCodec<B, C1> codec1, Function<V, C1> getter1,
Function<C1, V> factory) {
return new StreamCodec<>() {
@Override
public V decode(B buf) {
C1 v1 = codec1.decode(buf);
return factory.apply(v1);
}
@Override
public void encode(B buf, V value) {
codec1.encode(buf, getter1.apply(value));
}
};
}
interface Factory2<C1, C2, V> {
V create(C1 c1, C2 c2);
}
static <B, C1, C2, V> StreamCodec<B, V> composite(
StreamCodec<B, C1> codec1, Function<V, C1> getter1,
StreamCodec<B, C2> codec2, Function<V, C2> getter2,
Factory2<C1, C2, V> factory) {
return new StreamCodec<>() {
@Override
public V decode(B buf) {
C1 v1 = codec1.decode(buf);
C2 v2 = codec2.decode(buf);
return factory.create(v1, v2);
}
@Override
public void encode(B buf, V value) {
codec1.encode(buf, getter1.apply(value));
codec2.encode(buf, getter2.apply(value));
}
};
}
interface Factory3<C1, C2, C3, V> {
V create(C1 c1, C2 c2, C3 c3);
}
static <B, C1, C2, C3, V> StreamCodec<B, V> composite(
StreamCodec<B, C1> codec1, Function<V, C1> getter1,
StreamCodec<B, C2> codec2, Function<V, C2> getter2,
StreamCodec<B, C3> codec3, Function<V, C3> getter3,
Factory3<C1, C2, C3, V> factory) {
return new StreamCodec<>() {
@Override
public V decode(B buf) {
C1 v1 = codec1.decode(buf);
C2 v2 = codec2.decode(buf);
C3 v3 = codec3.decode(buf);
return factory.create(v1, v2, v3);
}
@Override
public void encode(B buf, V value) {
codec1.encode(buf, getter1.apply(value));
codec2.encode(buf, getter2.apply(value));
codec3.encode(buf, getter3.apply(value));
}
};
}
interface Factory4<C1, C2, C3, C4, V> {
V create(C1 c1, C2 c2, C3 c3, C4 c4);
}
static <B, C1, C2, C3, C4, V> StreamCodec<B, V> composite(
StreamCodec<B, C1> codec1, Function<V, C1> getter1,
StreamCodec<B, C2> codec2, Function<V, C2> getter2,
StreamCodec<B, C3> codec3, Function<V, C3> getter3,
StreamCodec<B, C4> codec4, Function<V, C4> getter4,
Factory4<C1, C2, C3, C4, V> factory) {
return new StreamCodec<>() {
@Override
public V decode(B buf) {
C1 v1 = codec1.decode(buf);
C2 v2 = codec2.decode(buf);
C3 v3 = codec3.decode(buf);
C4 v4 = codec4.decode(buf);
return factory.create(v1, v2, v3, v4);
}
@Override
public void encode(B buf, V value) {
codec1.encode(buf, getter1.apply(value));
codec2.encode(buf, getter2.apply(value));
codec3.encode(buf, getter3.apply(value));
codec4.encode(buf, getter4.apply(value));
}
};
}
interface Factory5<C1, C2, C3, C4, C5, V> {
V create(C1 c1, C2 c2, C3 c3, C4 c4, C5 c5);
}
static <B, C1, C2, C3, C4, C5, V> StreamCodec<B, V> composite(
StreamCodec<B, C1> codec1, Function<V, C1> getter1,
StreamCodec<B, C2> codec2, Function<V, C2> getter2,
StreamCodec<B, C3> codec3, Function<V, C3> getter3,
StreamCodec<B, C4> codec4, Function<V, C4> getter4,
StreamCodec<B, C5> codec5, Function<V, C5> getter5,
Factory5<C1, C2, C3, C4, C5, V> factory) {
return new StreamCodec<>() {
@Override
public V decode(B buf) {
C1 v1 = codec1.decode(buf);
C2 v2 = codec2.decode(buf);
C3 v3 = codec3.decode(buf);
C4 v4 = codec4.decode(buf);
C5 v5 = codec5.decode(buf);
return factory.create(v1, v2, v3, v4, v5);
}
@Override
public void encode(B buf, V value) {
codec1.encode(buf, getter1.apply(value));
codec2.encode(buf, getter2.apply(value));
codec3.encode(buf, getter3.apply(value));
codec4.encode(buf, getter4.apply(value));
codec5.encode(buf, getter5.apply(value));
}
};
}
interface Factory6<C1, C2, C3, C4, C5, C6, V> {
V create(C1 c1, C2 c2, C3 c3, C4 c4, C5 c5, C6 c6);
}
static <B, C1, C2, C3, C4, C5, C6, V> StreamCodec<B, V> composite(
StreamCodec<B, C1> codec1, Function<V, C1> getter1,
StreamCodec<B, C2> codec2, Function<V, C2> getter2,
StreamCodec<B, C3> codec3, Function<V, C3> getter3,
StreamCodec<B, C4> codec4, Function<V, C4> getter4,
StreamCodec<B, C5> codec5, Function<V, C5> getter5,
StreamCodec<B, C6> codec6, Function<V, C6> getter6,
Factory6<C1, C2, C3, C4, C5, C6, V> factory) {
return new StreamCodec<>() {
@Override
public V decode(B buf) {
C1 v1 = codec1.decode(buf);
C2 v2 = codec2.decode(buf);
C3 v3 = codec3.decode(buf);
C4 v4 = codec4.decode(buf);
C5 v5 = codec5.decode(buf);
C6 v6 = codec6.decode(buf);
return factory.create(v1, v2, v3, v4, v5, v6);
}
@Override
public void encode(B buf, V value) {
codec1.encode(buf, getter1.apply(value));
codec2.encode(buf, getter2.apply(value));
codec3.encode(buf, getter3.apply(value));
codec4.encode(buf, getter4.apply(value));
codec5.encode(buf, getter5.apply(value));
codec6.encode(buf, getter6.apply(value));
}
};
}
}
@@ -9,17 +9,35 @@ import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
/** Shared reflection metadata for presenting the Antarchy settings consistently. */
public final class AntarchyConfigCatalog { public final class AntarchyConfigCatalog {
public enum Section { MOBS, TOOLS, MISC } public enum Section {
public enum ValueType { BOOLEAN, INTEGER, DOUBLE, FLOAT, STRING } MOBS,
TOOLS,
MISC
}
public record Definition(String name, Section section, ValueType valueType, public enum ValueType {
Class<?> setterType, Method getter, Method setter) {} BOOLEAN,
INTEGER,
DOUBLE,
FLOAT,
STRING
}
public record Definition(
String name,
Section section,
ValueType valueType,
Class<?> setterType,
Method getter,
Method setter
) {
}
private static final List<Definition> DEFINITIONS = buildDefinitions(); private static final List<Definition> DEFINITIONS = buildDefinitions();
private AntarchyConfigCatalog() {} private AntarchyConfigCatalog() {
}
public static List<Definition> definitions() { public static List<Definition> definitions() {
return DEFINITIONS; return DEFINITIONS;
@@ -38,8 +56,11 @@ public final class AntarchyConfigCatalog {
.filter(AntarchyConfigCatalog::isPublicStatic) .filter(AntarchyConfigCatalog::isPublicStatic)
.filter(method -> method.getParameterCount() == 0) .filter(method -> method.getParameterCount() == 0)
.filter(method -> method.getReturnType() != Void.TYPE) .filter(method -> method.getReturnType() != Void.TYPE)
.collect(java.util.stream.Collectors.toMap(Method::getName, method -> method, .collect(java.util.stream.Collectors.toMap(
(first, ignored) -> first, LinkedHashMap::new)); Method::getName,
method -> method,
(first, ignored) -> first,
LinkedHashMap::new));
return Arrays.stream(AntarchySettings.class.getMethods()) return Arrays.stream(AntarchySettings.class.getMethods())
.filter(AntarchyConfigCatalog::isPublicStatic) .filter(AntarchyConfigCatalog::isPublicStatic)
@@ -54,18 +75,35 @@ public final class AntarchyConfigCatalog {
private static Definition definitionFor(Method setter, Map<String, Method> getters) { private static Definition definitionFor(Method setter, Map<String, Method> getters) {
String name = decapitalize(setter.getName().substring(3)); String name = decapitalize(setter.getName().substring(3));
Method getter = getters.get(name); Method getter = getters.get(name);
if (getter == null) return null; if (getter == null) {
return null;
}
Class<?> setterType = setter.getParameterTypes()[0]; Class<?> setterType = setter.getParameterTypes()[0];
ValueType valueType = valueTypeFor(setterType, getter.getReturnType()); ValueType valueType = valueTypeFor(setterType, getter.getReturnType());
return valueType == null ? null : new Definition(name, sectionFor(name), valueType, setterType, getter, setter); if (valueType == null) {
return null;
}
return new Definition(name, sectionFor(name), valueType, setterType, getter, setter);
} }
private static ValueType valueTypeFor(Class<?> setterType, Class<?> getterType) { private static ValueType valueTypeFor(Class<?> setterType, Class<?> getterType) {
if (setterType == boolean.class && getterType == boolean.class) return ValueType.BOOLEAN; if (setterType == boolean.class && getterType == boolean.class) {
if (setterType == int.class && getterType == int.class) return ValueType.INTEGER; return ValueType.BOOLEAN;
if (setterType == double.class && getterType == double.class) return ValueType.DOUBLE; }
if (setterType == float.class && getterType == float.class) return ValueType.FLOAT; if (setterType == int.class && getterType == int.class) {
if (setterType == String.class && ResourceKey.class.isAssignableFrom(getterType)) return ValueType.STRING; return ValueType.INTEGER;
}
if (setterType == double.class && getterType == double.class) {
return ValueType.DOUBLE;
}
if (setterType == float.class && getterType == float.class) {
return ValueType.FLOAT;
}
if (setterType == String.class && ResourceKey.class.isAssignableFrom(getterType)) {
return ValueType.STRING;
}
return null; return null;
} }
@@ -75,11 +113,20 @@ public final class AntarchyConfigCatalog {
} }
private static String decapitalize(String value) { private static String decapitalize(String value) {
return value.isEmpty() ? value : Character.toLowerCase(value.charAt(0)) + value.substring(1); if (value.isEmpty()) {
return value;
}
return Character.toLowerCase(value.charAt(0)) + value.substring(1);
} }
private static Section sectionFor(String name) { private static Section sectionFor(String name) {
return isMiscSetting(name) ? Section.MISC : isToolSetting(name) ? Section.TOOLS : Section.MOBS; if (isMiscSetting(name)) {
return Section.MISC;
}
if (isToolSetting(name)) {
return Section.TOOLS;
}
return Section.MOBS;
} }
private static boolean isMiscSetting(String name) { private static boolean isMiscSetting(String name) {
@@ -87,32 +134,66 @@ public final class AntarchyConfigCatalog {
|| name.equals("rainbowAntsLeadToInfinityDimensions") || name.equals("rainbowAntsLeadToInfinityDimensions")
|| name.equals("permanentPortalsEnabled") || name.equals("permanentPortalsEnabled")
|| name.equals("permanentPortalsFlintAndSteelEnabled") || name.equals("permanentPortalsFlintAndSteelEnabled")
|| name.equals("elythiaPortalEnabled") || name.equals("thoraxisPortalEnabled") || name.equals("elythiaPortalEnabled")
|| name.equals("cavarynPortalEnabled") || name.equals("hushweedSporeLifetimeSeconds") || name.equals("thoraxisPortalEnabled")
|| name.equals("elythiaFireflyParticlesEnabled") || name.equals("duplicatorTreeEnabled") || name.equals("cavarynPortalEnabled")
|| name.equals("glowVinesUnderLeaves") || name.equals("swingThroughGrassEnabled") || name.startsWith("portalGunCanFireThrough")
|| name.startsWith("portalGunSeeThrough")
|| name.startsWith("portalGunFancy")
|| name.equals("portalGunCanPortalsResizeWhenCreated")
|| name.equals("portalGunCanPortalProjectilesChunkload")
|| name.equals("portalGunMaxShootDistance")
|| name.equals("portalGunMinFloorExitSpeed")
|| name.equals("portalGunMaxLiveViews")
|| name.equals("portalGunMaxExitSpeed")
|| name.startsWith("portalGunMoon")
|| name.equals("hushweedSporeLifetimeSeconds")
|| name.equals("elythiaFireflyParticlesEnabled")
|| name.equals("duplicatorTreeEnabled")
|| name.equals("glowVinesUnderLeaves")
|| name.equals("swingThroughGrassEnabled")
|| name.equals("fabricKeybindingConflictFixEnabled") || name.equals("fabricKeybindingConflictFixEnabled")
|| name.equals("experimentalSettingsPopupDisabled") || name.equals("unlockAllArchives") || name.equals("experimentalSettingsPopupDisabled")
|| name.equals("entitySpecificFireOverlayEnabled") || name.equals("dreamSandEnabled") || name.equals("unlockAllArchives")
|| name.startsWith("dreamSand") || name.equals("ichorWitherEnabled") || name.equals("entitySpecificFireOverlayEnabled")
|| name.startsWith("diamondMinecart") || name.startsWith("hoverboard"); || name.startsWith("dreamSand")
|| name.equals("ichorWitherEnabled")
|| name.startsWith("diamondMinecart")
|| name.startsWith("hoverboard");
} }
private static boolean isToolSetting(String name) { private static boolean isToolSetting(String name) {
return name.equals("sizeChangingRaysEnabled") || name.startsWith("sizeRay") return name.equals("sizeChangingRaysEnabled")
|| name.equals("shrinkingPotionDelta") || name.equals("growthPotionDelta") || name.startsWith("sizeRay")
|| name.startsWith("ultimate") || name.startsWith("battleAxe") || name.startsWith("temporalTuner")
|| name.startsWith("bigBertha") || name.startsWith("attitudeAdjuster") || name.equals("shrinkingPotionDelta")
|| name.startsWith("scorpionWhip") || name.startsWith("bloodCrystal") || name.equals("growthPotionDelta")
|| name.startsWith("nightmareHelmet") || name.startsWith("nightmareChestplate") || name.startsWith("ultimate")
|| name.startsWith("nightmareLeggings") || name.startsWith("nightmareBoots") || name.startsWith("battleAxe")
|| name.startsWith("nightmareArmorDreadAura") || name.startsWith("primordialArmor") || name.startsWith("bigBertha")
|| name.startsWith("nightmareSword") || name.startsWith("basiliskDagger") || name.startsWith("attitudeAdjuster")
|| name.startsWith("squidzooka") || name.equals("invertProjectilesFromInvertedPlayers") || name.startsWith("scorpionWhip")
|| name.startsWith("gravityGun") || name.startsWith("critterCage") || name.startsWith("bloodCrystal")
|| name.startsWith("nightmareHelmet")
|| name.startsWith("nightmareChestplate")
|| name.startsWith("nightmareLeggings")
|| name.startsWith("nightmareBoots")
|| name.startsWith("nightmareArmorDreadAura")
|| name.startsWith("primordialArmor")
|| name.startsWith("nightmareSword")
|| name.startsWith("basiliskDagger")
|| name.startsWith("squidzooka")
|| name.startsWith("gravityGun")
|| name.startsWith("critterCage")
|| name.equals("potentNyxiteInvertedDurationSeconds") || name.equals("potentNyxiteInvertedDurationSeconds")
|| name.equals("corneaEarNightVisionSeconds") || name.startsWith("american") || name.equals("corneaEarNightVisionSeconds")
|| name.startsWith("mogglesVision") || name.equals("ductTapeRepairPercentPerUse") || name.startsWith("american")
|| name.startsWith("fallenKingCrown"); || name.startsWith("mogglesVision")
|| name.equals("ductTapeRepairPercentPerUse")
|| name.startsWith("fallenKingCrown")
|| name.startsWith("royalArmor")
|| name.startsWith("royalGuardian")
|| name.startsWith("royalAssailant")
|| name.startsWith("royalWeapon");
} }
} }
@@ -17,6 +17,7 @@ public final class AntarchySettings {
private static boolean rainbowAntRequiresReagent = true; private static boolean rainbowAntRequiresReagent = true;
private static boolean rainbowAntRightClickDimension = true; private static boolean rainbowAntRightClickDimension = true;
private static boolean termiteRequiresReagent = false; private static boolean termiteRequiresReagent = false;
private static boolean termitesFearBlockLight = true;
private static boolean termiteRightClickDimension = true; private static boolean termiteRightClickDimension = true;
private static boolean antsStealFromChests = true; private static boolean antsStealFromChests = true;
private static boolean duplicatorTreeEnabled = true; private static boolean duplicatorTreeEnabled = true;
@@ -24,10 +25,13 @@ public final class AntarchySettings {
private static boolean swingThroughGrassEnabled = true; private static boolean swingThroughGrassEnabled = true;
private static boolean fabricKeybindingConflictFixEnabled = true; private static boolean fabricKeybindingConflictFixEnabled = true;
private static boolean experimentalSettingsPopupDisabled = true; private static boolean experimentalSettingsPopupDisabled = true;
private static boolean unlockAllArchives = true;
private static boolean sizeChangingRaysEnabled = true; private static boolean sizeChangingRaysEnabled = true;
private static double sizeRayMinScale = 0.1D; private static double sizeRayMinScale = 0.1D;
private static double sizeRayMaxScale = 10.0D; private static double sizeRayMaxScale = 10.0D;
private static double sizeRayDeltaPerHit = 0.25D; private static double sizeRayDeltaPerHit = 0.25D;
private static double temporalTunerMinRate = 0.1D;
private static double temporalTunerMaxRate = 3.0D;
private static double shrinkingPotionDelta = 0.3D; private static double shrinkingPotionDelta = 0.3D;
private static double growthPotionDelta = 0.5D; private static double growthPotionDelta = 0.5D;
private static double antDanceRadius = 5.0D; private static double antDanceRadius = 5.0D;
@@ -103,6 +107,9 @@ public final class AntarchySettings {
private static int ultimateCrossbowEnchantability = 20; private static int ultimateCrossbowEnchantability = 20;
private static int ultimateMaceEnchantability = 20; private static int ultimateMaceEnchantability = 20;
private static boolean ultimateToolsThreeByThreeEnabled = true; private static boolean ultimateToolsThreeByThreeEnabled = true;
private static boolean ultimateToolsVeinMiningEnabled = true;
private static int ultimateToolsVeinMiningMaxBlocks = 64;
private static int ultimateToolsTreeFellingMaxLogs = 128;
private static boolean ultimateArmorComesEnchanted = true; private static boolean ultimateArmorComesEnchanted = true;
private static int ultimateHelmetArmorValue = 6; private static int ultimateHelmetArmorValue = 6;
private static int ultimateChestplateArmorValue = 11; private static int ultimateChestplateArmorValue = 11;
@@ -152,7 +159,6 @@ public final class AntarchySettings {
private static double rpoLauncherExplosionDamage = 34.0D; private static double rpoLauncherExplosionDamage = 34.0D;
private static double rpoLauncherExplosionRadius = 14.0D; private static double rpoLauncherExplosionRadius = 14.0D;
private static double sizeRayCooldownSeconds = 1.0D; private static double sizeRayCooldownSeconds = 1.0D;
private static boolean invertProjectilesFromInvertedPlayers = false;
private static boolean gravityGunEnabled = true; private static boolean gravityGunEnabled = true;
private static boolean gravityGunBlocksEnabled = true; private static boolean gravityGunBlocksEnabled = true;
private static boolean gravityGunEntitiesEnabled = true; private static boolean gravityGunEntitiesEnabled = true;
@@ -171,11 +177,7 @@ public final class AntarchySettings {
private static double americanBonusSaturation = 1.0D; private static double americanBonusSaturation = 1.0D;
private static int americanRegenerationDurationTicks = 60; private static int americanRegenerationDurationTicks = 60;
private static int americanRegenerationAmplifier = 0; private static int americanRegenerationAmplifier = 0;
private static boolean dreamSandEnabled = true;
private static boolean entitySpecificFireOverlayEnabled = true; private static boolean entitySpecificFireOverlayEnabled = true;
private static double dreamSandJumpVelocityMultiplier = 1.3D;
private static double dreamSandGravityMultiplier = 0.45D;
private static double dreamSandEffectDurationSeconds = 7.0D;
private static double dreamSandFallingBlockGravityMultiplier = 0.4D; private static double dreamSandFallingBlockGravityMultiplier = 0.4D;
private static boolean ichorWitherEnabled = true; private static boolean ichorWitherEnabled = true;
private static int nightmareHelmetArmorValue = 4; private static int nightmareHelmetArmorValue = 4;
@@ -206,6 +208,11 @@ public final class AntarchySettings {
private static int royalGuardianBootsArmorValue = 5; private static int royalGuardianBootsArmorValue = 5;
private static double royalGuardianArmorToughness = 4.0D; private static double royalGuardianArmorToughness = 4.0D;
private static double royalGuardianArmorKnockbackResistance = 0.15D; private static double royalGuardianArmorKnockbackResistance = 0.15D;
private static double royalGuardianHelmetJudgmentBonus = 0.06D;
private static double royalGuardianChestplateJudgmentBonus = 0.08D;
private static double royalGuardianLeggingsJudgmentBonus = 0.07D;
private static double royalGuardianBootsJudgmentBonus = 0.05D;
private static int royalGuardianJudgmentDurationTicks = 160;
private static int royalAssailantHelmetArmorValue = 5; private static int royalAssailantHelmetArmorValue = 5;
private static int royalAssailantChestplateArmorValue = 10; private static int royalAssailantChestplateArmorValue = 10;
private static int royalAssailantLeggingsArmorValue = 8; private static int royalAssailantLeggingsArmorValue = 8;
@@ -217,43 +224,69 @@ public final class AntarchySettings {
private static double royalAssailantLeggingsDoubleDamageChance = 0.07D; private static double royalAssailantLeggingsDoubleDamageChance = 0.07D;
private static double royalAssailantBootsDoubleDamageChance = 0.05D; private static double royalAssailantBootsDoubleDamageChance = 0.05D;
private static double royalGuardianSwordAttackDamage = 111.0D; private static double royalGuardianSwordAttackDamage = 111.0D;
private static double giantFryingPanAttackDamage = 50.0D;
private static int giantFryingPanCookTimeTicks = 200;
private static double royalGuardianSwordAttackSpeed = -2.5D; private static double royalGuardianSwordAttackSpeed = -2.5D;
private static int royalGuardianSwordElementalCooldownTicks = 120;
private static double royalGuardianSwordFirePrimaryDamage = 22.0D;
private static double royalGuardianSwordFireSplashDamage = 14.0D;
private static double royalGuardianSwordFrostSpikeDamage = 9.0D;
private static double royalGuardianSwordStormPrimaryDamage = 16.0D;
private static double royalGuardianSwordStormJumpDamage = 14.0D;
private static int royalGuardianSwordStormMaxJumps = 4;
private static double royalGuardianSwordStormJumpRange = 9.0D;
private static double royalAssailantBattleAxeAttackDamage = 151.0D; private static double royalAssailantBattleAxeAttackDamage = 151.0D;
private static double royalAssailantBattleAxeAttackSpeed = -2.9D; private static double royalAssailantBattleAxeAttackSpeed = -2.9D;
private static double royalWeaponAttackReachBonus = 1.0D; private static double royalWeaponAttackReachBonus = 3.2D;
private static double royalWeaponAttackKnockbackBonus = 1.0D; private static double royalWeaponAttackKnockbackBonus = 1.0D;
private static int royalWeaponDurability = 4608; private static int royalWeaponDurability = 4608;
private static int royalWeaponEnchantability = 30; private static int royalWeaponEnchantability = 30;
private static int royalGuardianShieldDurability = 1008; private static int royalGuardianShieldDurability = 1008;
private static double royalGuardianMusterRange = 16.0D;
private static int royalGuardianMusterDurationTicks = 1200;
private static int royalGuardianMusterCooldownTicks = 500;
private static int royalGuardianMusterMobCap = 3;
private static double royalGuardianMusterDamageReduction = 0.40D;
private static double royalGuardianMusterAttackBonus = 0.50D;
private static double royalGuardianMusterSpeedBonus = 0.25D;
private static double royalGuardianMusterPassiveDamageFloor = 3.0D;
private static double royalGuardianBoundaryRadius = 9.0D;
private static int royalGuardianBoundaryDurationTicks = 120;
private static int royalGuardianBoundaryCooldownTicks = 700;
private static int royalGuardianBoundaryStrengthAmplifier = 1;
private static int royalGuardianBoundaryArrestTicks = 20;
private static int royalGuardianBoundaryDropTicks = 8;
private static int royalGuardianBoundaryProjectileCap = 64;
private static double royalBoltDamage = 6.0D; private static double royalBoltDamage = 6.0D;
private static int royalEggHatchChance = 3; private static int royalEggHatchChance = 3;
private static double princeHealth = 120.0D; private static double princeHealth = 360.0D;
private static double princeAttackDamage = 14.0D; private static double princeAttackDamage = 14.0D;
private static double princeMovementSpeed = 0.28D; private static double princeMovementSpeed = 0.28D;
private static double princeFlyingSpeed = 0.9D; private static double princeFlyingSpeed = 0.9D;
private static double princeArmor = 10.0D; private static double princeArmor = 10.0D;
private static double princeKnockbackResistance = 0.6D; private static double princeKnockbackResistance = 0.6D;
private static double princeFollowRange = 48.0D; private static double princeFollowRange = 48.0D;
private static double princessHealth = 110.0D; private static double princessHealth = 330.0D;
private static double princessAttackDamage = 10.0D; private static double princessAttackDamage = 10.0D;
private static double princessMovementSpeed = 0.28D; private static double princessMovementSpeed = 0.28D;
private static double princessFlyingSpeed = 0.95D; private static double princessFlyingSpeed = 0.95D;
private static double princessArmor = 8.0D; private static double princessArmor = 8.0D;
private static double princessKnockbackResistance = 0.5D; private static double princessKnockbackResistance = 0.5D;
private static double princessFollowRange = 48.0D; private static double princessFollowRange = 48.0D;
private static double kingHealth = 6000.0D; private static double kingHealth = 3400.0D;
private static double queenHealth = 6000.0D; private static double queenHealth = 4300.0D;
private static double kingAttackDamage = 50.0D; private static double kingAttackDamage = 50.0D;
private static double queenAttackDamage = 45.0D; private static double queenAttackDamage = 45.0D;
private static double royalBossSoundVolume = 4.5D; private static double royalBossSoundVolume = 4.5D;
private static double queenBlackHoleRadius = 14.0D; private static double queenBlackHoleRadius = 14.0D;
private static int queenBlackHoleActiveTicks = 120; private static int queenBlackHoleActiveTicks = 120;
private static double queenBlackHolePullStrength = 0.16D; private static double queenBlackHolePullStrength = 0.16D;
private static double queenFinalTimeFieldRadius = 20.0D; private static int queenBlackHoleBlockSuctionCap = 160;
private static double queenFinalTimeFieldRate = 0.05D; private static double axeBlackHoleRadius = 28.0D;
private static int queenFinalTimeFieldDurationTicks = 45; private static int axeBlackHoleActiveTicks = 120;
private static int queenFinalTimeFieldCooldownTicks = 80; private static double axeBlackHolePullStrength = 0.16D;
private static double kingFireballDamage = 32.0D; private static int axeBlackHoleBlockSuctionCap = 160;
private static double kingFireballDamage = 48.0D;
private static double kingFireballRadius = 4.5D; private static double kingFireballRadius = 4.5D;
private static int kingFireballCooldownTicks = 150; private static int kingFireballCooldownTicks = 150;
private static double kingIceballDamage = 18.0D; private static double kingIceballDamage = 18.0D;
@@ -263,14 +296,23 @@ public final class AntarchySettings {
private static int kingIceSpikeCooldownTicks = 240; private static int kingIceSpikeCooldownTicks = 240;
private static int kingElementalTerrainCap = 256; private static int kingElementalTerrainCap = 256;
private static double royalBossArmor = 20.0D; private static double royalBossArmor = 20.0D;
private static double kingArmor = 30.0D;
private static double royalBossFollowRange = 128.0D; private static double royalBossFollowRange = 128.0D;
private static double royalBossMovementSpeed = 0.22D; private static double royalBossMovementSpeed = 0.22D;
private static double royalBossKnockbackResistance = 1.0D; private static double royalBossKnockbackResistance = 1.0D;
private static double royalBossStepHeight = 3.0D; private static double royalBossStepHeight = 3.0D;
private static double royalBossMaxSingleHitDamage = 250.0D; private static double royalBossMaxSingleHitDamage = 250.0D;
private static double royalBossBiteReach = 10.0D; private static double royalBossHitOverflowRate = 0.25D;
private static double royalBossBiteReach = 12.0D;
private static double royalBossBiteDamageMultiplier = 1.6D; private static double royalBossBiteDamageMultiplier = 1.6D;
private static int royalBossBiteCooldownTicks = 45; private static int royalBossBiteCooldownTicks = 45;
private static boolean royalBossMultiplayerScalingEnabled = true;
private static int royalBossScalingMaxPlayers = 4;
private static double royalBossHealthPerAdditionalPlayer = 0.35D;
private static double royalBossDamagePerAdditionalPlayer = 0.10D;
private static double royalBoundaryRadius = 192.0D;
private static double royalBoundaryWarningRadius = 160.0D;
private static int royalBoundaryGraceTicks = 60;
private static boolean basiliskPetrifyingGazeEnabled = true; private static boolean basiliskPetrifyingGazeEnabled = true;
private static int basiliskSpawnMaxLightLevel = 5; private static int basiliskSpawnMaxLightLevel = 5;
private static double basiliskHealth = 320.0D; private static double basiliskHealth = 320.0D;
@@ -379,19 +421,19 @@ public final class AntarchySettings {
private static double bedBugAttackDamage = 4.0D; private static double bedBugAttackDamage = 4.0D;
private static double bedBugMovementSpeed = 0.24D; private static double bedBugMovementSpeed = 0.24D;
private static double bedBugArmor = 2.0D; private static double bedBugArmor = 2.0D;
private static double jumpyBugHealth = 100.0D; private static double springbugHealth = 100.0D;
private static double jumpyBugPounceDamage = 12.0D; private static double springbugPounceDamage = 12.0D;
private static double jumpyBugCamouflageAlpha = 0.18D; private static double springbugCamouflageAlpha = 0.18D;
private static double brutalflyArmor = 10.0D; private static double brutalflyArmor = 10.0D;
private static double brutalflyArmorToughness = 5.0D; private static double brutalflyArmorToughness = 5.0D;
private static double brutalflyKnockbackResistance = 0.7D; private static double brutalflyKnockbackResistance = 0.7D;
private static double brutalflyMovementSpeed = 0.34D; private static double brutalflyMovementSpeed = 0.34D;
private static double brutalflyFlyingSpeed = 0.55D; private static double brutalflyFlyingSpeed = 0.55D;
private static double cloudSharkHealth = 40.0D; private static double stratosharkHealth = 40.0D;
private static double cloudSharkAttackDamage = 5.0D; private static double stratosharkAttackDamage = 5.0D;
private static double cloudSharkMovementSpeed = 0.34D; private static double stratosharkMovementSpeed = 0.34D;
private static double cloudSharkFlyingSpeed = 0.5D; private static double stratosharkFlyingSpeed = 0.5D;
private static double cloudSharkKnockbackResistance = 0.2D; private static double stratosharkKnockbackResistance = 0.2D;
private static double krakenMovementSpeed = 0.24D; private static double krakenMovementSpeed = 0.24D;
private static double krakenFlyingSpeed = 0.24D; private static double krakenFlyingSpeed = 0.24D;
private static double krakenKnockbackResistance = 0.8D; private static double krakenKnockbackResistance = 0.8D;
@@ -446,10 +488,10 @@ public final class AntarchySettings {
private static double molewormHealth = 8.0D; private static double molewormHealth = 8.0D;
private static double molewormAttackDamage = 1.0D; private static double molewormAttackDamage = 1.0D;
private static double molewormMovementSpeed = 0.25D; private static double molewormMovementSpeed = 0.25D;
private static double triffidHealth = 160.0D; private static double flytrapHealth = 160.0D;
private static double triffidAttackDamage = 10.0D; private static double flytrapAttackDamage = 10.0D;
private static double triffidGrabDamage = 15.0D; private static double flytrapGrabDamage = 15.0D;
private static int triffidSweepHitCooldownTicks = 10; private static int flytrapSweepHitCooldownTicks = 10;
private static double molevoreHealth = 140.0D; private static double molevoreHealth = 140.0D;
private static double molevoreAttackDamage = 10.0D; private static double molevoreAttackDamage = 10.0D;
private static double molevoreMovementSpeed = 0.27D; private static double molevoreMovementSpeed = 0.27D;
@@ -463,9 +505,6 @@ public final class AntarchySettings {
private static double molevoreBreakRange = 1.8D; private static double molevoreBreakRange = 1.8D;
private static double molevoreBreakVerticalRange = 2.2D; private static double molevoreBreakVerticalRange = 2.2D;
private static double molevoreBreakHalfWidth = 1.1D; private static double molevoreBreakHalfWidth = 1.1D;
private static double jumpyBugLatchDamage = 2.0D;
private static double waterCannonCooldownSeconds = 4.0D;
private static double toreterrorRangedWaterBombChance = 0.35D;
private static double nightmareHealth = 380.0D; private static double nightmareHealth = 380.0D;
private static double nightmareAttackDamage = 16.0D; private static double nightmareAttackDamage = 16.0D;
private static double nightmareMovementSpeed = 0.28D; private static double nightmareMovementSpeed = 0.28D;
@@ -509,22 +548,34 @@ public final class AntarchySettings {
private static boolean elythiaPortalEnabled = true; private static boolean elythiaPortalEnabled = true;
private static boolean thoraxisPortalEnabled = true; private static boolean thoraxisPortalEnabled = true;
private static boolean cavarynPortalEnabled = true; private static boolean cavarynPortalEnabled = true;
private static boolean portalGunCanFireThroughGlass = false;
private static boolean portalGunCanFireThroughLiquid = false;
private static boolean portalGunCanPortalsResizeWhenCreated = true;
private static boolean portalGunCanPortalProjectilesChunkload = true;
private static boolean portalGunSeeThroughPortals = true;
private static boolean portalGunFancyPortals = true;
private static int portalGunMaxShootDistance = 10000;
private static double portalGunMinFloorExitSpeed = 0.6D;
private static int portalGunMaxLiveViews = 8;
private static double portalGunMaxExitSpeed = 0.0D;
private static boolean portalGunMoonPullsBlocks = true;
private static int portalGunMoonPortalSeconds = 10;
private static int portalGunMoonBlockCap = 500;
private static boolean elythiaFireflyParticlesEnabled = true; private static boolean elythiaFireflyParticlesEnabled = true;
private static int bloodCrystalArmorShieldRechargeTicks = 600; private static int bloodCrystalArmorShieldRechargeTicks = 600;
private static int bloodCrystalAppleShieldCount = 2; private static int bloodCrystalAppleShieldCount = 2;
private static int bloodCrystalAppleDurationTicks = 2400; private static int bloodCrystalAppleDurationTicks = 2400;
private static int bloodCrystalAppleShieldRechargeTicks = 600; private static int bloodCrystalAppleShieldRechargeTicks = 600;
private static int bloodCrystalHardMaxShields = 10; private static int bloodCrystalHardMaxShields = 10;
// Armor stats (iron defense, gold durability, 0 toughness by default)
private static int bloodCrystalHelmetDefense = 3; private static int bloodCrystalHelmetDefense = 3;
private static int bloodCrystalChestplateDefense = 7; private static int bloodCrystalChestplateDefense = 7;
private static int bloodCrystalLeggingsDefense = 6; private static int bloodCrystalLeggingsDefense = 6;
private static int bloodCrystalBootsDefense = 3; private static int bloodCrystalBootsDefense = 3;
private static double bloodCrystalArmorToughness = 2.0D; private static double bloodCrystalArmorToughness = 2.0D;
private static int bloodCrystalHelmetDurability = 77; private static int bloodCrystalHelmetDurability = 92;
private static int bloodCrystalChestplateDurability = 112; private static int bloodCrystalChestplateDurability = 134;
private static int bloodCrystalLeggingsDurability = 105; private static int bloodCrystalLeggingsDurability = 126;
private static int bloodCrystalBootsDurability = 91; private static int bloodCrystalBootsDurability = 109;
private static double toreterrorHealth = 450.0D; private static double toreterrorHealth = 450.0D;
private static double toreterrorJumpAttackDamage = 14.0D; private static double toreterrorJumpAttackDamage = 14.0D;
private static double toreterrorJumpAttackKnockback = 2.5D; private static double toreterrorJumpAttackKnockback = 2.5D;
@@ -535,19 +586,20 @@ public final class AntarchySettings {
private static int waterBombLifetimeTicks = 120; private static int waterBombLifetimeTicks = 120;
private static double waterBombGravity = 0.12D; private static double waterBombGravity = 0.12D;
private static double waterBombKnockback = 1.2D; private static double waterBombKnockback = 1.2D;
private static double creepingHorrorHealth = 15.0D; private static double crawlingBlightHealth = 15.0D;
private static double creepingHorrorAttackDamage = 6.0D; private static double crawlingBlightAttackDamage = 6.0D;
private static double lurkingTerrorHealth = 15.0D; private static double skulkingFrightHealth = 15.0D;
private static double lurkingTerrorAttackDamage = 6.0D; private static double skulkingFrightAttackDamage = 6.0D;
private static double manticoreHealth = 40.0D; private static double manticoreHealth = 60.0D;
private static double manticoreAttackDamage = 7.0D; private static double manticoreAttackDamage = 11.0D;
private static int manticoreStingPoisonTicks = 100; private static int manticoreStingPoisonTicks = 100;
private static int queenManticoreCap = 15; private static int queenManticoreCap = 15;
private static int queenManticoreSummonCooldownTicks = 600; private static int queenManticoreSummonCooldownTicks = 800;
private static int queenManticoreSummonCount = 3; private static int queenManticoreSummonCount = 2;
private static double queenManticoreSummonRange = 24.0D; private static double queenManticoreSummonRange = 24.0D;
private static double queenBeamDamage = 45.0D; private static double queenBeamDamage = 45.0D;
private static double queenBeamRange = 100.0D; private static double queenBeamRange = 100.0D;
private static double queenBeamMinimumRange = 22.0D;
private static int queenBeamDurationTicks = 30; private static int queenBeamDurationTicks = 30;
private static int queenBeamWindupTicks = 20; private static int queenBeamWindupTicks = 20;
private static int queenBeamTravelTicks = 12; private static int queenBeamTravelTicks = 12;
@@ -555,8 +607,13 @@ public final class AntarchySettings {
private static double queenBeamTracking = 0.1D; private static double queenBeamTracking = 0.1D;
private static double queenBeamTerrainRadius = 5.0D; private static double queenBeamTerrainRadius = 5.0D;
private static int queenBeamTerrainCap = 192; private static int queenBeamTerrainCap = 192;
private static int queenBeamPhaseOneCap = 1;
private static int queenBeamPhaseTwoCap = 2;
private static int queenBeamPhaseThreeCap = 3;
private static double queenBeamPhaseThreeMaxVolleyChance = 0.2D;
private static double kingBeamDamage = 50.0D; private static double kingBeamDamage = 50.0D;
private static double kingBeamRange = 100.0D; private static double kingBeamRange = 100.0D;
private static double kingBeamMinimumRange = 32.0D;
private static int kingBeamDurationTicks = 30; private static int kingBeamDurationTicks = 30;
private static int kingBeamWindupTicks = 20; private static int kingBeamWindupTicks = 20;
private static int kingBeamTravelTicks = 12; private static int kingBeamTravelTicks = 12;
@@ -564,7 +621,7 @@ public final class AntarchySettings {
private static double kingBeamTracking = 0.1D; private static double kingBeamTracking = 0.1D;
private static double kingBeamTerrainRadius = 5.0D; private static double kingBeamTerrainRadius = 5.0D;
private static int kingBeamTerrainCap = 192; private static int kingBeamTerrainCap = 192;
private static int royalDecreeCooldownTicks = 1200; private static int royalDecreeCooldownTicks = 700;
private static int kingRoyalMusterCooldownTicks = 500; private static int kingRoyalMusterCooldownTicks = 500;
private static int kingRoyalMusterWindupTicks = 30; private static int kingRoyalMusterWindupTicks = 30;
private static int kingRoyalMusterDurationTicks = 600; private static int kingRoyalMusterDurationTicks = 600;
@@ -588,7 +645,7 @@ public final class AntarchySettings {
private static double glimmerHealth = 20.0D; private static double glimmerHealth = 20.0D;
private static double lucidArmorToughness = 2.0D; private static double lucidArmorToughness = 2.0D;
private static double triffidArmorToughness = 3.0D; private static double flytrapArmorToughness = 3.0D;
private static double basiliskArmorToughness = 5.0D; private static double basiliskArmorToughness = 5.0D;
private static double nightmareMobArmorToughness = 5.0D; private static double nightmareMobArmorToughness = 5.0D;
private static double alphaMantisArmorToughness = 4.0D; private static double alphaMantisArmorToughness = 4.0D;
@@ -663,6 +720,10 @@ public final class AntarchySettings {
return termiteRequiresReagent; return termiteRequiresReagent;
} }
public static boolean termitesFearBlockLight() {
return termitesFearBlockLight;
}
public static boolean antsStealFromChests() { public static boolean antsStealFromChests() {
return antsStealFromChests; return antsStealFromChests;
} }
@@ -687,6 +748,10 @@ public final class AntarchySettings {
return experimentalSettingsPopupDisabled; return experimentalSettingsPopupDisabled;
} }
public static boolean unlockAllArchives() {
return unlockAllArchives;
}
public static boolean sizeChangingRaysEnabled() { public static boolean sizeChangingRaysEnabled() {
return sizeChangingRaysEnabled; return sizeChangingRaysEnabled;
} }
@@ -703,6 +768,14 @@ public final class AntarchySettings {
return sizeRayDeltaPerHit; return sizeRayDeltaPerHit;
} }
public static double temporalTunerMinRate() {
return temporalTunerMinRate;
}
public static double temporalTunerMaxRate() {
return temporalTunerMaxRate;
}
public static double shrinkingPotionDelta() { public static double shrinkingPotionDelta() {
return shrinkingPotionDelta; return shrinkingPotionDelta;
} }
@@ -905,6 +978,18 @@ public final class AntarchySettings {
return ultimateToolsThreeByThreeEnabled; return ultimateToolsThreeByThreeEnabled;
} }
public static boolean ultimateToolsVeinMiningEnabled() {
return ultimateToolsVeinMiningEnabled;
}
public static int ultimateToolsVeinMiningMaxBlocks() {
return ultimateToolsVeinMiningMaxBlocks;
}
public static int ultimateToolsTreeFellingMaxLogs() {
return ultimateToolsTreeFellingMaxLogs;
}
public static boolean ultimateArmorComesEnchanted() { public static boolean ultimateArmorComesEnchanted() {
return ultimateArmorComesEnchanted; return ultimateArmorComesEnchanted;
} }
@@ -1140,10 +1225,6 @@ public final class AntarchySettings {
return sizeRayCooldownSeconds; return sizeRayCooldownSeconds;
} }
public static boolean invertProjectilesFromInvertedPlayers() {
return invertProjectilesFromInvertedPlayers;
}
public static boolean gravityGunEnabled() { public static boolean gravityGunEnabled() {
return gravityGunEnabled; return gravityGunEnabled;
} }
@@ -1240,11 +1321,76 @@ public final class AntarchySettings {
cavarynPortalEnabled = value; cavarynPortalEnabled = value;
} }
public static void setPortalGunCanFireThroughGlass(boolean value) {
portalGunCanFireThroughGlass = value;
}
public static void setPortalGunCanFireThroughLiquid(boolean value) {
portalGunCanFireThroughLiquid = value;
}
public static void setPortalGunCanPortalsResizeWhenCreated(boolean value) {
portalGunCanPortalsResizeWhenCreated = value;
}
public static void setPortalGunCanPortalProjectilesChunkload(boolean value) {
portalGunCanPortalProjectilesChunkload = value;
}
public static void setPortalGunSeeThroughPortals(boolean value) {
portalGunSeeThroughPortals = value;
}
public static void setPortalGunFancyPortals(boolean value) {
portalGunFancyPortals = value;
}
public static void setPortalGunMaxShootDistance(int value) {
portalGunMaxShootDistance = Math.max(1, value);
}
public static void setPortalGunMaxLiveViews(int value) {
portalGunMaxLiveViews = Math.max(0, Math.min(32, value));
}
public static void setPortalGunMinFloorExitSpeed(double value) {
portalGunMinFloorExitSpeed = Math.max(0.0D, Math.min(4.0D, value));
}
public static void setPortalGunMoonPullsBlocks(boolean value) {
portalGunMoonPullsBlocks = value;
}
public static void setPortalGunMoonPortalSeconds(int value) {
portalGunMoonPortalSeconds = Math.max(1, Math.min(120, value));
}
public static void setPortalGunMoonBlockCap(int value) {
portalGunMoonBlockCap = Math.max(0, Math.min(2000, value));
}
public static void setPortalGunMaxExitSpeed(double value) {
portalGunMaxExitSpeed = Math.max(0.0D, Math.min(100.0D, value));
}
public static boolean permanentPortalsEnabled() { return permanentPortalsEnabled; } public static boolean permanentPortalsEnabled() { return permanentPortalsEnabled; }
public static boolean permanentPortalsFlintAndSteelEnabled() { return permanentPortalsFlintAndSteelEnabled; } public static boolean permanentPortalsFlintAndSteelEnabled() { return permanentPortalsFlintAndSteelEnabled; }
public static boolean elythiaPortalEnabled() { return elythiaPortalEnabled; } public static boolean elythiaPortalEnabled() { return elythiaPortalEnabled; }
public static boolean thoraxisPortalEnabled() { return thoraxisPortalEnabled; } public static boolean thoraxisPortalEnabled() { return thoraxisPortalEnabled; }
public static boolean cavarynPortalEnabled() { return cavarynPortalEnabled; } public static boolean cavarynPortalEnabled() { return cavarynPortalEnabled; }
public static boolean portalGunCanFireThroughGlass() { return portalGunCanFireThroughGlass; }
public static boolean portalGunCanFireThroughLiquid() { return portalGunCanFireThroughLiquid; }
public static boolean portalGunCanPortalsResizeWhenCreated() { return portalGunCanPortalsResizeWhenCreated; }
public static boolean portalGunCanPortalProjectilesChunkload() { return portalGunCanPortalProjectilesChunkload; }
public static boolean portalGunSeeThroughPortals() { return portalGunSeeThroughPortals; }
public static boolean portalGunFancyPortals() { return portalGunFancyPortals; }
public static int portalGunMaxShootDistance() { return portalGunMaxShootDistance; }
public static double portalGunMinFloorExitSpeed() { return portalGunMinFloorExitSpeed; }
public static int portalGunMaxLiveViews() { return portalGunMaxLiveViews; }
public static double portalGunMaxExitSpeed() { return portalGunMaxExitSpeed; }
public static boolean portalGunMoonPullsBlocks() { return portalGunMoonPullsBlocks; }
public static int portalGunMoonPortalSeconds() { return portalGunMoonPortalSeconds; }
public static int portalGunMoonBlockCap() { return portalGunMoonBlockCap; }
public static void setBrownAntRequiresReagent(boolean value) { public static void setBrownAntRequiresReagent(boolean value) {
brownAntRequiresReagent = value; brownAntRequiresReagent = value;
@@ -1262,6 +1408,10 @@ public final class AntarchySettings {
termiteRequiresReagent = value; termiteRequiresReagent = value;
} }
public static void setTermitesFearBlockLight(boolean value) {
termitesFearBlockLight = value;
}
public static void setAntsStealFromChests(boolean value) { public static void setAntsStealFromChests(boolean value) {
antsStealFromChests = value; antsStealFromChests = value;
} }
@@ -1286,6 +1436,10 @@ public final class AntarchySettings {
experimentalSettingsPopupDisabled = value; experimentalSettingsPopupDisabled = value;
} }
public static void setUnlockAllArchives(boolean value) {
unlockAllArchives = value;
}
public static void setSizeChangingRaysEnabled(boolean value) { public static void setSizeChangingRaysEnabled(boolean value) {
sizeChangingRaysEnabled = value; sizeChangingRaysEnabled = value;
} }
@@ -1302,6 +1456,14 @@ public final class AntarchySettings {
sizeRayDeltaPerHit = value; sizeRayDeltaPerHit = value;
} }
public static void setTemporalTunerMinRate(double value) {
temporalTunerMinRate = value;
}
public static void setTemporalTunerMaxRate(double value) {
temporalTunerMaxRate = value;
}
public static void setShrinkingPotionDelta(double value) { public static void setShrinkingPotionDelta(double value) {
shrinkingPotionDelta = value; shrinkingPotionDelta = value;
} }
@@ -1478,6 +1640,18 @@ public final class AntarchySettings {
ultimateToolsThreeByThreeEnabled = value; ultimateToolsThreeByThreeEnabled = value;
} }
public static void setUltimateToolsVeinMiningEnabled(boolean value) {
ultimateToolsVeinMiningEnabled = value;
}
public static void setUltimateToolsVeinMiningMaxBlocks(int value) {
ultimateToolsVeinMiningMaxBlocks = value;
}
public static void setUltimateToolsTreeFellingMaxLogs(int value) {
ultimateToolsTreeFellingMaxLogs = value;
}
public static void setUltimateArmorComesEnchanted(boolean value) { public static void setUltimateArmorComesEnchanted(boolean value) {
ultimateArmorComesEnchanted = value; ultimateArmorComesEnchanted = value;
} }
@@ -1662,10 +1836,6 @@ public final class AntarchySettings {
sizeRayCooldownSeconds = value; sizeRayCooldownSeconds = value;
} }
public static void setInvertProjectilesFromInvertedPlayers(boolean value) {
invertProjectilesFromInvertedPlayers = value;
}
public static void setGravityGunEnabled(boolean value) { public static void setGravityGunEnabled(boolean value) {
gravityGunEnabled = value; gravityGunEnabled = value;
} }
@@ -1770,46 +1940,14 @@ public final class AntarchySettings {
americanRegenerationAmplifier = value; americanRegenerationAmplifier = value;
} }
public static boolean dreamSandEnabled() {
return dreamSandEnabled;
}
public static boolean entitySpecificFireOverlayEnabled() { public static boolean entitySpecificFireOverlayEnabled() {
return entitySpecificFireOverlayEnabled; return entitySpecificFireOverlayEnabled;
} }
public static void setDreamSandEnabled(boolean value) {
dreamSandEnabled = value;
}
public static void setEntitySpecificFireOverlayEnabled(boolean value) { public static void setEntitySpecificFireOverlayEnabled(boolean value) {
entitySpecificFireOverlayEnabled = value; entitySpecificFireOverlayEnabled = value;
} }
public static double dreamSandJumpVelocityMultiplier() {
return dreamSandJumpVelocityMultiplier;
}
public static void setDreamSandJumpVelocityMultiplier(double value) {
dreamSandJumpVelocityMultiplier = value;
}
public static double dreamSandGravityMultiplier() {
return dreamSandGravityMultiplier;
}
public static void setDreamSandGravityMultiplier(double value) {
dreamSandGravityMultiplier = value;
}
public static double dreamSandEffectDurationSeconds() {
return dreamSandEffectDurationSeconds;
}
public static void setDreamSandEffectDurationSeconds(double value) {
dreamSandEffectDurationSeconds = value;
}
public static double dreamSandFallingBlockGravityMultiplier() { public static double dreamSandFallingBlockGravityMultiplier() {
return dreamSandFallingBlockGravityMultiplier; return dreamSandFallingBlockGravityMultiplier;
} }
@@ -1895,6 +2033,17 @@ public final class AntarchySettings {
public static double royalGuardianArmorKnockbackResistance() { return royalGuardianArmorKnockbackResistance; } public static double royalGuardianArmorKnockbackResistance() { return royalGuardianArmorKnockbackResistance; }
public static void setRoyalGuardianArmorKnockbackResistance(double v) { royalGuardianArmorKnockbackResistance = v; } public static void setRoyalGuardianArmorKnockbackResistance(double v) { royalGuardianArmorKnockbackResistance = v; }
public static double royalGuardianHelmetJudgmentBonus() { return royalGuardianHelmetJudgmentBonus; }
public static void setRoyalGuardianHelmetJudgmentBonus(double v) { royalGuardianHelmetJudgmentBonus = v; }
public static double royalGuardianChestplateJudgmentBonus() { return royalGuardianChestplateJudgmentBonus; }
public static void setRoyalGuardianChestplateJudgmentBonus(double v) { royalGuardianChestplateJudgmentBonus = v; }
public static double royalGuardianLeggingsJudgmentBonus() { return royalGuardianLeggingsJudgmentBonus; }
public static void setRoyalGuardianLeggingsJudgmentBonus(double v) { royalGuardianLeggingsJudgmentBonus = v; }
public static double royalGuardianBootsJudgmentBonus() { return royalGuardianBootsJudgmentBonus; }
public static void setRoyalGuardianBootsJudgmentBonus(double v) { royalGuardianBootsJudgmentBonus = v; }
public static int royalGuardianJudgmentDurationTicks() { return royalGuardianJudgmentDurationTicks; }
public static void setRoyalGuardianJudgmentDurationTicks(int v) { royalGuardianJudgmentDurationTicks = v; }
public static int royalAssailantHelmetArmorValue() { return royalAssailantHelmetArmorValue; } public static int royalAssailantHelmetArmorValue() { return royalAssailantHelmetArmorValue; }
public static void setRoyalAssailantHelmetArmorValue(int v) { royalAssailantHelmetArmorValue = v; } public static void setRoyalAssailantHelmetArmorValue(int v) { royalAssailantHelmetArmorValue = v; }
@@ -1927,10 +2076,31 @@ public final class AntarchySettings {
public static double royalGuardianSwordAttackDamage() { return royalGuardianSwordAttackDamage; } public static double royalGuardianSwordAttackDamage() { return royalGuardianSwordAttackDamage; }
public static void setRoyalGuardianSwordAttackDamage(double v) { royalGuardianSwordAttackDamage = v; } public static void setRoyalGuardianSwordAttackDamage(double v) { royalGuardianSwordAttackDamage = v; }
public static double giantFryingPanAttackDamage() { return giantFryingPanAttackDamage; }
public static void setGiantFryingPanAttackDamage(double v) { giantFryingPanAttackDamage = v; }
public static int giantFryingPanCookTimeTicks() { return giantFryingPanCookTimeTicks; }
public static void setGiantFryingPanCookTimeTicks(int v) { giantFryingPanCookTimeTicks = v; }
public static double royalGuardianSwordAttackSpeed() { return royalGuardianSwordAttackSpeed; } public static double royalGuardianSwordAttackSpeed() { return royalGuardianSwordAttackSpeed; }
public static void setRoyalGuardianSwordAttackSpeed(double v) { royalGuardianSwordAttackSpeed = v; } public static void setRoyalGuardianSwordAttackSpeed(double v) { royalGuardianSwordAttackSpeed = v; }
public static int royalGuardianSwordElementalCooldownTicks() { return royalGuardianSwordElementalCooldownTicks; }
public static void setRoyalGuardianSwordElementalCooldownTicks(int v) { royalGuardianSwordElementalCooldownTicks = v; }
public static double royalGuardianSwordFirePrimaryDamage() { return royalGuardianSwordFirePrimaryDamage; }
public static void setRoyalGuardianSwordFirePrimaryDamage(double v) { royalGuardianSwordFirePrimaryDamage = v; }
public static double royalGuardianSwordFireSplashDamage() { return royalGuardianSwordFireSplashDamage; }
public static void setRoyalGuardianSwordFireSplashDamage(double v) { royalGuardianSwordFireSplashDamage = v; }
public static double royalGuardianSwordFrostSpikeDamage() { return royalGuardianSwordFrostSpikeDamage; }
public static void setRoyalGuardianSwordFrostSpikeDamage(double v) { royalGuardianSwordFrostSpikeDamage = v; }
public static double royalGuardianSwordStormPrimaryDamage() { return royalGuardianSwordStormPrimaryDamage; }
public static void setRoyalGuardianSwordStormPrimaryDamage(double v) { royalGuardianSwordStormPrimaryDamage = v; }
public static double royalGuardianSwordStormJumpDamage() { return royalGuardianSwordStormJumpDamage; }
public static void setRoyalGuardianSwordStormJumpDamage(double v) { royalGuardianSwordStormJumpDamage = v; }
public static int royalGuardianSwordStormMaxJumps() { return royalGuardianSwordStormMaxJumps; }
public static void setRoyalGuardianSwordStormMaxJumps(int v) { royalGuardianSwordStormMaxJumps = v; }
public static double royalGuardianSwordStormJumpRange() { return royalGuardianSwordStormJumpRange; }
public static void setRoyalGuardianSwordStormJumpRange(double v) { royalGuardianSwordStormJumpRange = v; }
public static double royalAssailantBattleAxeAttackDamage() { return royalAssailantBattleAxeAttackDamage; } public static double royalAssailantBattleAxeAttackDamage() { return royalAssailantBattleAxeAttackDamage; }
public static void setRoyalAssailantBattleAxeAttackDamage(double v) { royalAssailantBattleAxeAttackDamage = v; } public static void setRoyalAssailantBattleAxeAttackDamage(double v) { royalAssailantBattleAxeAttackDamage = v; }
@@ -1952,6 +2122,37 @@ public final class AntarchySettings {
public static int royalGuardianShieldDurability() { return royalGuardianShieldDurability; } public static int royalGuardianShieldDurability() { return royalGuardianShieldDurability; }
public static void setRoyalGuardianShieldDurability(int v) { royalGuardianShieldDurability = v; } public static void setRoyalGuardianShieldDurability(int v) { royalGuardianShieldDurability = v; }
public static double royalGuardianMusterRange() { return royalGuardianMusterRange; }
public static void setRoyalGuardianMusterRange(double v) { royalGuardianMusterRange = v; }
public static int royalGuardianMusterDurationTicks() { return royalGuardianMusterDurationTicks; }
public static void setRoyalGuardianMusterDurationTicks(int v) { royalGuardianMusterDurationTicks = v; }
public static int royalGuardianMusterCooldownTicks() { return royalGuardianMusterCooldownTicks; }
public static void setRoyalGuardianMusterCooldownTicks(int v) { royalGuardianMusterCooldownTicks = v; }
public static int royalGuardianMusterMobCap() { return royalGuardianMusterMobCap; }
public static void setRoyalGuardianMusterMobCap(int v) { royalGuardianMusterMobCap = v; }
public static double royalGuardianMusterDamageReduction() { return royalGuardianMusterDamageReduction; }
public static void setRoyalGuardianMusterDamageReduction(double v) { royalGuardianMusterDamageReduction = v; }
public static double royalGuardianMusterAttackBonus() { return royalGuardianMusterAttackBonus; }
public static void setRoyalGuardianMusterAttackBonus(double v) { royalGuardianMusterAttackBonus = v; }
public static double royalGuardianMusterSpeedBonus() { return royalGuardianMusterSpeedBonus; }
public static void setRoyalGuardianMusterSpeedBonus(double v) { royalGuardianMusterSpeedBonus = v; }
public static double royalGuardianMusterPassiveDamageFloor() { return royalGuardianMusterPassiveDamageFloor; }
public static void setRoyalGuardianMusterPassiveDamageFloor(double v) { royalGuardianMusterPassiveDamageFloor = v; }
public static double royalGuardianBoundaryRadius() { return royalGuardianBoundaryRadius; }
public static void setRoyalGuardianBoundaryRadius(double v) { royalGuardianBoundaryRadius = v; }
public static int royalGuardianBoundaryDurationTicks() { return royalGuardianBoundaryDurationTicks; }
public static void setRoyalGuardianBoundaryDurationTicks(int v) { royalGuardianBoundaryDurationTicks = v; }
public static int royalGuardianBoundaryCooldownTicks() { return royalGuardianBoundaryCooldownTicks; }
public static void setRoyalGuardianBoundaryCooldownTicks(int v) { royalGuardianBoundaryCooldownTicks = v; }
public static int royalGuardianBoundaryStrengthAmplifier() { return royalGuardianBoundaryStrengthAmplifier; }
public static void setRoyalGuardianBoundaryStrengthAmplifier(int v) { royalGuardianBoundaryStrengthAmplifier = v; }
public static int royalGuardianBoundaryArrestTicks() { return royalGuardianBoundaryArrestTicks; }
public static void setRoyalGuardianBoundaryArrestTicks(int v) { royalGuardianBoundaryArrestTicks = v; }
public static int royalGuardianBoundaryDropTicks() { return royalGuardianBoundaryDropTicks; }
public static void setRoyalGuardianBoundaryDropTicks(int v) { royalGuardianBoundaryDropTicks = v; }
public static int royalGuardianBoundaryProjectileCap() { return royalGuardianBoundaryProjectileCap; }
public static void setRoyalGuardianBoundaryProjectileCap(int v) { royalGuardianBoundaryProjectileCap = v; }
public static double royalBoltDamage() { return royalBoltDamage; } public static double royalBoltDamage() { return royalBoltDamage; }
public static void setRoyalBoltDamage(double v) { royalBoltDamage = v; } public static void setRoyalBoltDamage(double v) { royalBoltDamage = v; }
@@ -2007,14 +2208,16 @@ public final class AntarchySettings {
public static void setQueenBlackHoleActiveTicks(int v) { queenBlackHoleActiveTicks = v; } public static void setQueenBlackHoleActiveTicks(int v) { queenBlackHoleActiveTicks = v; }
public static double queenBlackHolePullStrength() { return queenBlackHolePullStrength; } public static double queenBlackHolePullStrength() { return queenBlackHolePullStrength; }
public static void setQueenBlackHolePullStrength(double v) { queenBlackHolePullStrength = v; } public static void setQueenBlackHolePullStrength(double v) { queenBlackHolePullStrength = v; }
public static double queenFinalTimeFieldRadius() { return queenFinalTimeFieldRadius; } public static int queenBlackHoleBlockSuctionCap() { return queenBlackHoleBlockSuctionCap; }
public static void setQueenFinalTimeFieldRadius(double v) { queenFinalTimeFieldRadius = v; } public static void setQueenBlackHoleBlockSuctionCap(int v) { queenBlackHoleBlockSuctionCap = v; }
public static double queenFinalTimeFieldRate() { return queenFinalTimeFieldRate; } public static double axeBlackHoleRadius() { return axeBlackHoleRadius; }
public static void setQueenFinalTimeFieldRate(double v) { queenFinalTimeFieldRate = v; } public static void setAxeBlackHoleRadius(double v) { axeBlackHoleRadius = v; }
public static int queenFinalTimeFieldDurationTicks() { return queenFinalTimeFieldDurationTicks; } public static int axeBlackHoleActiveTicks() { return axeBlackHoleActiveTicks; }
public static void setQueenFinalTimeFieldDurationTicks(int v) { queenFinalTimeFieldDurationTicks = v; } public static void setAxeBlackHoleActiveTicks(int v) { axeBlackHoleActiveTicks = v; }
public static int queenFinalTimeFieldCooldownTicks() { return queenFinalTimeFieldCooldownTicks; } public static double axeBlackHolePullStrength() { return axeBlackHolePullStrength; }
public static void setQueenFinalTimeFieldCooldownTicks(int v) { queenFinalTimeFieldCooldownTicks = v; } public static void setAxeBlackHolePullStrength(double v) { axeBlackHolePullStrength = v; }
public static int axeBlackHoleBlockSuctionCap() { return axeBlackHoleBlockSuctionCap; }
public static void setAxeBlackHoleBlockSuctionCap(int v) { axeBlackHoleBlockSuctionCap = v; }
public static double kingFireballDamage() { return kingFireballDamage; } public static double kingFireballDamage() { return kingFireballDamage; }
public static void setKingFireballDamage(double v) { kingFireballDamage = v; } public static void setKingFireballDamage(double v) { kingFireballDamage = v; }
public static double kingFireballRadius() { return kingFireballRadius; } public static double kingFireballRadius() { return kingFireballRadius; }
@@ -2036,6 +2239,8 @@ public final class AntarchySettings {
public static double royalBossArmor() { return royalBossArmor; } public static double royalBossArmor() { return royalBossArmor; }
public static void setRoyalBossArmor(double v) { royalBossArmor = v; } public static void setRoyalBossArmor(double v) { royalBossArmor = v; }
public static double kingArmor() { return kingArmor; }
public static void setKingArmor(double v) { kingArmor = v; }
public static double royalBossFollowRange() { return royalBossFollowRange; } public static double royalBossFollowRange() { return royalBossFollowRange; }
public static void setRoyalBossFollowRange(double v) { royalBossFollowRange = v; } public static void setRoyalBossFollowRange(double v) { royalBossFollowRange = v; }
@@ -2052,6 +2257,9 @@ public final class AntarchySettings {
public static double royalBossMaxSingleHitDamage() { return royalBossMaxSingleHitDamage; } public static double royalBossMaxSingleHitDamage() { return royalBossMaxSingleHitDamage; }
public static void setRoyalBossMaxSingleHitDamage(double v) { royalBossMaxSingleHitDamage = v; } public static void setRoyalBossMaxSingleHitDamage(double v) { royalBossMaxSingleHitDamage = v; }
public static double royalBossHitOverflowRate() { return royalBossHitOverflowRate; }
public static void setRoyalBossHitOverflowRate(double v) { royalBossHitOverflowRate = v; }
public static double royalBossBiteReach() { return royalBossBiteReach; } public static double royalBossBiteReach() { return royalBossBiteReach; }
public static void setRoyalBossBiteReach(double v) { royalBossBiteReach = v; } public static void setRoyalBossBiteReach(double v) { royalBossBiteReach = v; }
@@ -2060,6 +2268,20 @@ public final class AntarchySettings {
public static int royalBossBiteCooldownTicks() { return royalBossBiteCooldownTicks; } public static int royalBossBiteCooldownTicks() { return royalBossBiteCooldownTicks; }
public static void setRoyalBossBiteCooldownTicks(int v) { royalBossBiteCooldownTicks = v; } public static void setRoyalBossBiteCooldownTicks(int v) { royalBossBiteCooldownTicks = v; }
public static boolean royalBossMultiplayerScalingEnabled() { return royalBossMultiplayerScalingEnabled; }
public static void setRoyalBossMultiplayerScalingEnabled(boolean v) { royalBossMultiplayerScalingEnabled = v; }
public static int royalBossScalingMaxPlayers() { return royalBossScalingMaxPlayers; }
public static void setRoyalBossScalingMaxPlayers(int v) { royalBossScalingMaxPlayers = v; }
public static double royalBossHealthPerAdditionalPlayer() { return royalBossHealthPerAdditionalPlayer; }
public static void setRoyalBossHealthPerAdditionalPlayer(double v) { royalBossHealthPerAdditionalPlayer = v; }
public static double royalBossDamagePerAdditionalPlayer() { return royalBossDamagePerAdditionalPlayer; }
public static void setRoyalBossDamagePerAdditionalPlayer(double v) { royalBossDamagePerAdditionalPlayer = v; }
public static double royalBoundaryRadius() { return royalBoundaryRadius; }
public static void setRoyalBoundaryRadius(double v) { royalBoundaryRadius = v; }
public static double royalBoundaryWarningRadius() { return royalBoundaryWarningRadius; }
public static void setRoyalBoundaryWarningRadius(double v) { royalBoundaryWarningRadius = v; }
public static int royalBoundaryGraceTicks() { return royalBoundaryGraceTicks; }
public static void setRoyalBoundaryGraceTicks(int v) { royalBoundaryGraceTicks = v; }
public static double nightmareSwordBaseDamage() { return nightmareSwordBaseDamage; } public static double nightmareSwordBaseDamage() { return nightmareSwordBaseDamage; }
public static void setNightmareSwordBaseDamage(double v) { nightmareSwordBaseDamage = v; } public static void setNightmareSwordBaseDamage(double v) { nightmareSwordBaseDamage = v; }
@@ -2307,7 +2529,6 @@ public final class AntarchySettings {
public static int reverieDuplicationCooldownTicks() { return reverieDuplicationCooldownTicks; } public static int reverieDuplicationCooldownTicks() { return reverieDuplicationCooldownTicks; }
public static void setReverieDuplicationCooldownTicks(int v){ reverieDuplicationCooldownTicks = v; } public static void setReverieDuplicationCooldownTicks(int v){ reverieDuplicationCooldownTicks = v; }
// Hardcoded AI tuning — getters only, no config wiring
public static double reveriePreferredFollowMinDistance() { return reveriePreferredFollowMinDistance; } public static double reveriePreferredFollowMinDistance() { return reveriePreferredFollowMinDistance; }
public static double reveriePreferredFollowMaxDistance() { return reveriePreferredFollowMaxDistance; } public static double reveriePreferredFollowMaxDistance() { return reveriePreferredFollowMaxDistance; }
public static double reverieCatchUpDistance() { return reverieCatchUpDistance; } public static double reverieCatchUpDistance() { return reverieCatchUpDistance; }
@@ -2454,14 +2675,14 @@ public final class AntarchySettings {
public static double bedBugArmor() { return bedBugArmor; } public static double bedBugArmor() { return bedBugArmor; }
public static void setBedBugArmor(double value) { bedBugArmor = value; } public static void setBedBugArmor(double value) { bedBugArmor = value; }
public static double jumpyBugHealth() { return jumpyBugHealth; } public static double springbugHealth() { return springbugHealth; }
public static void setJumpyBugHealth(double value) { jumpyBugHealth = value; } public static void setSpringbugHealth(double value) { springbugHealth = value; }
public static double jumpyBugPounceDamage() { return jumpyBugPounceDamage; } public static double springbugPounceDamage() { return springbugPounceDamage; }
public static void setJumpyBugPounceDamage(double value) { jumpyBugPounceDamage = value; } public static void setSpringbugPounceDamage(double value) { springbugPounceDamage = value; }
public static double jumpyBugCamouflageAlpha() { return jumpyBugCamouflageAlpha; } public static double springbugCamouflageAlpha() { return springbugCamouflageAlpha; }
public static void setJumpyBugCamouflageAlpha(double value) { jumpyBugCamouflageAlpha = value; } public static void setSpringbugCamouflageAlpha(double value) { springbugCamouflageAlpha = value; }
public static double brutalflyArmor() { return brutalflyArmor; } public static double brutalflyArmor() { return brutalflyArmor; }
public static void setBrutalflyArmor(double value) { brutalflyArmor = value; } public static void setBrutalflyArmor(double value) { brutalflyArmor = value; }
@@ -2478,20 +2699,20 @@ public final class AntarchySettings {
public static double brutalflyFlyingSpeed() { return brutalflyFlyingSpeed; } public static double brutalflyFlyingSpeed() { return brutalflyFlyingSpeed; }
public static void setBrutalflyFlyingSpeed(double value) { brutalflyFlyingSpeed = value; } public static void setBrutalflyFlyingSpeed(double value) { brutalflyFlyingSpeed = value; }
public static double cloudSharkHealth() { return cloudSharkHealth; } public static double stratosharkHealth() { return stratosharkHealth; }
public static void setCloudSharkHealth(double value) { cloudSharkHealth = value; } public static void setStratosharkHealth(double value) { stratosharkHealth = value; }
public static double cloudSharkAttackDamage() { return cloudSharkAttackDamage; } public static double stratosharkAttackDamage() { return stratosharkAttackDamage; }
public static void setCloudSharkAttackDamage(double value) { cloudSharkAttackDamage = value; } public static void setStratosharkAttackDamage(double value) { stratosharkAttackDamage = value; }
public static double cloudSharkMovementSpeed() { return cloudSharkMovementSpeed; } public static double stratosharkMovementSpeed() { return stratosharkMovementSpeed; }
public static void setCloudSharkMovementSpeed(double value) { cloudSharkMovementSpeed = value; } public static void setStratosharkMovementSpeed(double value) { stratosharkMovementSpeed = value; }
public static double cloudSharkFlyingSpeed() { return cloudSharkFlyingSpeed; } public static double stratosharkFlyingSpeed() { return stratosharkFlyingSpeed; }
public static void setCloudSharkFlyingSpeed(double value) { cloudSharkFlyingSpeed = value; } public static void setStratosharkFlyingSpeed(double value) { stratosharkFlyingSpeed = value; }
public static double cloudSharkKnockbackResistance() { return cloudSharkKnockbackResistance; } public static double stratosharkKnockbackResistance() { return stratosharkKnockbackResistance; }
public static void setCloudSharkKnockbackResistance(double value) { cloudSharkKnockbackResistance = value; } public static void setStratosharkKnockbackResistance(double value) { stratosharkKnockbackResistance = value; }
public static double krakenMovementSpeed() { return krakenMovementSpeed; } public static double krakenMovementSpeed() { return krakenMovementSpeed; }
public static void setKrakenMovementSpeed(double value) { krakenMovementSpeed = value; } public static void setKrakenMovementSpeed(double value) { krakenMovementSpeed = value; }
@@ -2655,17 +2876,17 @@ public final class AntarchySettings {
public static double molewormMovementSpeed() { return molewormMovementSpeed; } public static double molewormMovementSpeed() { return molewormMovementSpeed; }
public static void setMolewormMovementSpeed(double value) { molewormMovementSpeed = value; } public static void setMolewormMovementSpeed(double value) { molewormMovementSpeed = value; }
public static double triffidHealth() { return triffidHealth; } public static double flytrapHealth() { return flytrapHealth; }
public static void setTriffidHealth(double value) { triffidHealth = value; } public static void setFlytrapHealth(double value) { flytrapHealth = value; }
public static double triffidAttackDamage() { return triffidAttackDamage; } public static double flytrapAttackDamage() { return flytrapAttackDamage; }
public static void setTriffidAttackDamage(double value) { triffidAttackDamage = value; } public static void setFlytrapAttackDamage(double value) { flytrapAttackDamage = value; }
public static double triffidGrabDamage() { return triffidGrabDamage; } public static double flytrapGrabDamage() { return flytrapGrabDamage; }
public static void setTriffidGrabDamage(double value) { triffidGrabDamage = value; } public static void setFlytrapGrabDamage(double value) { flytrapGrabDamage = value; }
public static int triffidSweepHitCooldownTicks() { return triffidSweepHitCooldownTicks; } public static int flytrapSweepHitCooldownTicks() { return flytrapSweepHitCooldownTicks; }
public static void setTriffidSweepHitCooldownTicks(int value) { triffidSweepHitCooldownTicks = value; } public static void setFlytrapSweepHitCooldownTicks(int value) { flytrapSweepHitCooldownTicks = value; }
public static double molevoreHealth() { return molevoreHealth; } public static double molevoreHealth() { return molevoreHealth; }
public static void setMolevoreHealth(double value) { molevoreHealth = value; } public static void setMolevoreHealth(double value) { molevoreHealth = value; }
@@ -2673,21 +2894,6 @@ public final class AntarchySettings {
public static double molevoreAttackDamage() { return molevoreAttackDamage; } public static double molevoreAttackDamage() { return molevoreAttackDamage; }
public static void setMolevoreAttackDamage(double value) { molevoreAttackDamage = value; } public static void setMolevoreAttackDamage(double value) { molevoreAttackDamage = value; }
public static double molevoreMovementSpeed() { return molevoreMovementSpeed; }
public static void setMolevoreMovementSpeed(double value) { molevoreMovementSpeed = value; }
public static double molevoreArmor() { return molevoreArmor; }
public static void setMolevoreArmor(double value) { molevoreArmor = value; }
public static double molevoreKnockbackResistance() { return molevoreKnockbackResistance; }
public static void setMolevoreKnockbackResistance(double value) { molevoreKnockbackResistance = value; }
public static double molevoreFollowRange() { return molevoreFollowRange; }
public static void setMolevoreFollowRange(double value) { molevoreFollowRange = value; }
public static int molevoreXpReward() { return molevoreXpReward; }
public static void setMolevoreXpReward(int value) { molevoreXpReward = value; }
public static int molevoreSpinTicks() { return molevoreSpinTicks; } public static int molevoreSpinTicks() { return molevoreSpinTicks; }
public static void setMolevoreSpinTicks(int value) { molevoreSpinTicks = value; } public static void setMolevoreSpinTicks(int value) { molevoreSpinTicks = value; }
@@ -2839,14 +3045,14 @@ public final class AntarchySettings {
public static double waterBombKnockback() { return waterBombKnockback; } public static double waterBombKnockback() { return waterBombKnockback; }
public static void setWaterBombKnockback(double v) { waterBombKnockback = v; } public static void setWaterBombKnockback(double v) { waterBombKnockback = v; }
public static double creepingHorrorHealth() { return creepingHorrorHealth; } public static double crawlingBlightHealth() { return crawlingBlightHealth; }
public static void setCreepingHorrorHealth(double v) { creepingHorrorHealth = v; } public static void setCrawlingBlightHealth(double v) { crawlingBlightHealth = v; }
public static double creepingHorrorAttackDamage() { return creepingHorrorAttackDamage; } public static double crawlingBlightAttackDamage() { return crawlingBlightAttackDamage; }
public static void setCreepingHorrorAttackDamage(double v) { creepingHorrorAttackDamage = v; } public static void setCrawlingBlightAttackDamage(double v) { crawlingBlightAttackDamage = v; }
public static double lurkingTerrorHealth() { return lurkingTerrorHealth; } public static double skulkingFrightHealth() { return skulkingFrightHealth; }
public static void setLurkingTerrorHealth(double v) { lurkingTerrorHealth = v; } public static void setSkulkingFrightHealth(double v) { skulkingFrightHealth = v; }
public static double lurkingTerrorAttackDamage() { return lurkingTerrorAttackDamage; } public static double skulkingFrightAttackDamage() { return skulkingFrightAttackDamage; }
public static void setLurkingTerrorAttackDamage(double v) { lurkingTerrorAttackDamage = v; } public static void setSkulkingFrightAttackDamage(double v) { skulkingFrightAttackDamage = v; }
public static double manticoreHealth() { return manticoreHealth; } public static double manticoreHealth() { return manticoreHealth; }
public static void setManticoreHealth(double v) { manticoreHealth = v; } public static void setManticoreHealth(double v) { manticoreHealth = v; }
public static double manticoreAttackDamage() { return manticoreAttackDamage; } public static double manticoreAttackDamage() { return manticoreAttackDamage; }
@@ -2865,6 +3071,8 @@ public final class AntarchySettings {
public static void setQueenBeamDamage(double v) { queenBeamDamage = v; } public static void setQueenBeamDamage(double v) { queenBeamDamage = v; }
public static double queenBeamRange() { return queenBeamRange; } public static double queenBeamRange() { return queenBeamRange; }
public static void setQueenBeamRange(double v) { queenBeamRange = v; } 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 int queenBeamDurationTicks() { return queenBeamDurationTicks; }
public static void setQueenBeamDurationTicks(int v) { queenBeamDurationTicks = v; } public static void setQueenBeamDurationTicks(int v) { queenBeamDurationTicks = v; }
public static int queenBeamWindupTicks() { return queenBeamWindupTicks; } public static int queenBeamWindupTicks() { return queenBeamWindupTicks; }
@@ -2879,10 +3087,20 @@ public final class AntarchySettings {
public static void setQueenBeamTerrainRadius(double v) { queenBeamTerrainRadius = v; } public static void setQueenBeamTerrainRadius(double v) { queenBeamTerrainRadius = v; }
public static int queenBeamTerrainCap() { return queenBeamTerrainCap; } public static int queenBeamTerrainCap() { return queenBeamTerrainCap; }
public static void setQueenBeamTerrainCap(int v) { queenBeamTerrainCap = v; } public static void setQueenBeamTerrainCap(int v) { queenBeamTerrainCap = v; }
public static int queenBeamPhaseOneCap() { return queenBeamPhaseOneCap; }
public static void setQueenBeamPhaseOneCap(int v) { queenBeamPhaseOneCap = v; }
public static int queenBeamPhaseTwoCap() { return queenBeamPhaseTwoCap; }
public static void setQueenBeamPhaseTwoCap(int v) { queenBeamPhaseTwoCap = v; }
public static int queenBeamPhaseThreeCap() { return queenBeamPhaseThreeCap; }
public static void setQueenBeamPhaseThreeCap(int v) { queenBeamPhaseThreeCap = v; }
public static double queenBeamPhaseThreeMaxVolleyChance() { return queenBeamPhaseThreeMaxVolleyChance; }
public static void setQueenBeamPhaseThreeMaxVolleyChance(double v) { queenBeamPhaseThreeMaxVolleyChance = v; }
public static double kingBeamDamage() { return kingBeamDamage; } public static double kingBeamDamage() { return kingBeamDamage; }
public static void setKingBeamDamage(double v) { kingBeamDamage = v; } public static void setKingBeamDamage(double v) { kingBeamDamage = v; }
public static double kingBeamRange() { return kingBeamRange; } public static double kingBeamRange() { return kingBeamRange; }
public static void setKingBeamRange(double v) { kingBeamRange = v; } 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 int kingBeamDurationTicks() { return kingBeamDurationTicks; }
public static void setKingBeamDurationTicks(int v) { kingBeamDurationTicks = v; } public static void setKingBeamDurationTicks(int v) { kingBeamDurationTicks = v; }
public static int kingBeamWindupTicks() { return kingBeamWindupTicks; } public static int kingBeamWindupTicks() { return kingBeamWindupTicks; }
@@ -2943,7 +3161,7 @@ public final class AntarchySettings {
public static void setGlimmerHealth(double v) { glimmerHealth = v; } public static void setGlimmerHealth(double v) { glimmerHealth = v; }
public static double lucidArmorToughness() { return lucidArmorToughness; } public static double lucidArmorToughness() { return lucidArmorToughness; }
public static double triffidArmorToughness() { return triffidArmorToughness; } public static double flytrapArmorToughness() { return flytrapArmorToughness; }
public static double basiliskArmorToughness() { return basiliskArmorToughness; } public static double basiliskArmorToughness() { return basiliskArmorToughness; }
public static double nightmareMobArmorToughness() { return nightmareMobArmorToughness; } public static double nightmareMobArmorToughness() { return nightmareMobArmorToughness; }
public static double alphaMantisArmorToughness() { return alphaMantisArmorToughness; } public static double alphaMantisArmorToughness() { return alphaMantisArmorToughness; }
@@ -2958,10 +3176,4 @@ public final class AntarchySettings {
public static int bossMagicWardDurationTicks() { return bossMagicWardDurationTicks; } public static int bossMagicWardDurationTicks() { return bossMagicWardDurationTicks; }
public static int bossMagicWardTriggerBreaches() { return bossMagicWardTriggerBreaches; } public static int bossMagicWardTriggerBreaches() { return bossMagicWardTriggerBreaches; }
public static java.util.List<String> magicBurstDamageNamespaces() { return magicBurstDamageNamespaces; } public static java.util.List<String> magicBurstDamageNamespaces() { return magicBurstDamageNamespaces; }
public static double jumpyBugLatchDamage() { return jumpyBugLatchDamage; }
public static void setJumpyBugLatchDamage(double value) { jumpyBugLatchDamage = value; }
public static double waterCannonCooldownSeconds() { return waterCannonCooldownSeconds; }
public static void setWaterCannonCooldownSeconds(double value) { waterCannonCooldownSeconds = value; }
public static double toreterrorRangedWaterBombChance() { return toreterrorRangedWaterBombChance; }
public static void setToreterrorRangedWaterBombChance(double value) { toreterrorRangedWaterBombChance = value; }
} }
@@ -6,31 +6,32 @@ import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
public final class ConfigResetGuard { public final class ConfigResetGuard {
public static final int RESET_GENERATION = 6; public static final int RESET_GENERATION = 9;
private static final String MARKER_FILE_NAME = ".config_generation"; private static final String MARKER_FILE_NAME = ".config_generation";
private ConfigResetGuard() { private ConfigResetGuard() {
} }
public static void wipeIfNeeded(Path configDir, Path... configFiles) { public static void migrateIfNeeded(Path configDir, Path... configFiles) {
Path markerPath = configDir.resolve(MARKER_FILE_NAME); Path markerPath = configDir.resolve(MARKER_FILE_NAME);
if (readGeneration(markerPath) >= RESET_GENERATION) { if (readGeneration(markerPath) >= RESET_GENERATION) {
return; return;
} }
for (Path configFile : configFiles) { for (Path configFile : configFiles) {
try { if (Files.exists(configFile)) {
if (Files.deleteIfExists(configFile)) { Antarchy.LOGGER.info("Preserving config file {} during config migration (config generation {})", configFile, RESET_GENERATION);
Antarchy.LOGGER.info("Reset config file {} to defaults (config generation {})", configFile, RESET_GENERATION);
}
} catch (IOException e) {
Antarchy.LOGGER.warn("Failed to delete config file {} during config reset", configFile, e);
} }
} }
writeGeneration(markerPath); writeGeneration(markerPath);
} }
@Deprecated
public static void wipeIfNeeded(Path configDir, Path... configFiles) {
migrateIfNeeded(configDir, configFiles);
}
private static int readGeneration(Path markerPath) { private static int readGeneration(Path markerPath) {
if (!Files.exists(markerPath)) { if (!Files.exists(markerPath)) {
return 0; return 0;
@@ -0,0 +1,199 @@
package com.craisinlord.antarchy.content;
import net.minecraft.world.item.ItemStack;
import net.minecraft.client.player.LocalPlayer;
import java.util.UUID;
import com.craisinlord.anthology.portal.client.PortalClientHooks;
import com.craisinlord.anthology.portal.PortalSettings;
import com.craisinlord.anthology.portal.PortalHooks;
import com.craisinlord.anthology.portal.PortalEntity;
import com.craisinlord.antarchy.content.portalgun.PortalGunProjectileEntity;
import com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity;
import com.craisinlord.antarchy.content.item.PortalGunItem;
import com.craisinlord.antarchy.content.client.renderer.PortalGunMoonViewRenderer;
import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.item.BigBerthaItem;
import com.craisinlord.antarchy.content.client.HerculesBeetleImpactShakeClientState;
import com.craisinlord.anthology.shake.client.CameraShake;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.effect.RoyalEffectEligibility;
import com.craisinlord.antarchy.content.enchantment.AntarchyEnchantments;
import com.craisinlord.antarchy.content.entity.BedBugEntity;
import com.craisinlord.antarchy.content.entity.portal.DimensionalTearEntity;
import com.craisinlord.antarchy.content.entity.royal.QueenEntity;
import com.craisinlord.antarchy.content.entity.royal.RoyalBlackHoleEntity;
import com.craisinlord.antarchy.content.fluid.AntarchyFluidChecks;
import com.craisinlord.antarchy.content.item.TemporalTunerAccess;
import com.craisinlord.antarchy.content.item.TemporalTunerItem;
import com.craisinlord.antarchy.content.worldgen.thoraxis.ThoraxisUndersideManager;
import com.craisinlord.anthology.effect.AnthologyEffects;
import com.craisinlord.anthology.gravity.GravityApi;
import com.craisinlord.anthology.gravity.GravityHooks;
import com.craisinlord.anthology.time.TimeDilationApi;
import com.craisinlord.anthology.time.TimeDilationFieldEntity;
import com.craisinlord.anthology.time.TimeDilationHooks;
import com.craisinlord.anthology.time.TimeDilationMath;
import com.craisinlord.anthology.time.client.ContractionAfterimages;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.effect.MobEffectInstance;
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;
public final class AntarchyAnthologyHooks {
private AntarchyAnthologyHooks() {
}
public static void register() {
GravityHooks.addInvertedRegion(ThoraxisUndersideManager::isInUnderside);
GravityHooks.addInvertedFluid(AntarchyFluidChecks::isAntiwater);
GravityHooks.addLoadListener(AntarchyAnthologyHooks::clearStaleUndersideInversion);
TimeDilationHooks.addTrackedPredicate(entity -> entity instanceof Player player && TemporalTunerItem.isAvailable(player));
TimeDilationHooks.addRateSource(AntarchyAnthologyHooks::temporalTunerRate);
TimeDilationHooks.addFieldExclusion(AntarchyAnthologyHooks::excludedFromField);
TimeDilationHooks.addChronosphereLevelSource(AntarchyEnchantments::chronosphereLevel);
PortalHooks.setSettings(new AntarchyPortalSettings());
PortalHooks.addTransitExclusion(entity -> entity instanceof PortalGunProjectileEntity);
}
public static void registerClient() {
PortalClientHooks.registerCustomView(portal -> portal instanceof PortalGunPortalEntity gunPortal && gunPortal.isMoonPortal(), PortalGunMoonViewRenderer::render);
PortalClientHooks.setOutlinePolicy(AntarchyAnthologyHooks::outlinesPortal);
CameraShake.addStrengthSource(cameraPos -> HerculesBeetleImpactShakeClientState.getTicks() / 25.0F * 2.0F);
CameraShake.addStrengthSource(cameraPos -> BigBerthaItem.clientShakeTicks / 25.0F * 2.0F);
ContractionAfterimages.addActivator(living -> living instanceof Player player
&& TemporalTunerItem.isAvailable(player)
&& TimeDilationApi.getRate(living) > 1.0D);
}
private static boolean outlinesPortal(PortalEntity portal, LocalPlayer viewer) {
if (!(portal instanceof PortalGunPortalEntity gunPortal) || gunPortal.getOwnerId() == null) {
return false;
}
UUID owner = gunPortal.getOwnerId();
return owner.equals(viewer.getUUID())
|| owner.equals(heldGunOwner(viewer.getMainHandItem(), viewer.getUUID()))
|| owner.equals(heldGunOwner(viewer.getOffhandItem(), viewer.getUUID()));
}
private static UUID heldGunOwner(ItemStack stack, UUID fallback) {
return stack.getItem() instanceof PortalGunItem ? PortalGunItem.getPortalOwnerId(stack, fallback) : null;
}
private static final class AntarchyPortalSettings implements PortalSettings {
@Override
public boolean seeThroughEnabled() {
return AntarchySettings.portalGunSeeThroughPortals();
}
@Override
public int maxLiveViews() {
return AntarchySettings.portalGunMaxLiveViews();
}
@Override
public double minFloorExitSpeed() {
return AntarchySettings.portalGunMinFloorExitSpeed();
}
@Override
public double maxExitSpeed() {
return AntarchySettings.portalGunMaxExitSpeed();
}
@Override
public boolean fancySurfaces() {
return AntarchySettings.portalGunFancyPortals();
}
}
private static double temporalTunerRate(Entity entity) {
if (!(entity instanceof Player player) || !(player instanceof TemporalTunerAccess access)) {
return TimeDilationMath.NORMAL_RATE;
}
if (TemporalTunerItem.isAvailable(player)) {
return TemporalTunerItem.getRate(player);
}
access.antarchy$setTemporalTunerRate(TimeDilationMath.NORMAL_RATE);
TemporalTunerItem.syncTooltipRate(player, TimeDilationMath.NORMAL_RATE);
return TimeDilationMath.NORMAL_RATE;
}
private static boolean excludedFromField(TimeDilationFieldEntity field, Entity entity) {
if (!field.isOwnerAnchored() && entity instanceof RoyalBlackHoleEntity) {
return true;
}
if (!(field.owner() instanceof QueenEntity)) {
return false;
}
if (entity instanceof LivingEntity living && !RoyalEffectEligibility.canApplyDilated(living)) {
return true;
}
return !field.isOwnerAnchored() && entity.getType().is(AntarchyTags.Entities.QUEEN_DOES_NOT_ATTACK);
}
private static void clearStaleUndersideInversion(Entity entity) {
if (!(entity instanceof Mob mob)
|| !GravityApi.isGravityInverted(mob)
|| !GravityApi.isGravityForced(mob)) {
return;
}
MobEffectInstance invertedEffect = mob.getEffect(AnthologyEffects.inverted());
boolean aboveUndersideExit = ThoraxisUndersideManager.isAboveUndersideExit(mob);
int nearbyDimensionalTears = countNearbyDimensionalTears(mob);
if (invertedEffect != null
&& invertedEffect.isAmbient()
&& !invertedEffect.isVisible()
&& aboveUndersideExit) {
clearInversion(mob);
Antarchy.LOGGER.warn(
"[antarchy-gravity] cleared stale underside inversion from loaded mob type={} uuid={} pos=({}, {}, {}) dim={} effectDuration={} nearbyDimensionalTears={}",
mob.getType(), mob.getUUID(), mob.getX(), mob.getY(), mob.getZ(),
mob.level() != null ? mob.level().dimension().location() : "?",
invertedEffect.getDuration(), nearbyDimensionalTears
);
return;
}
if (invertedEffect != null
&& mob instanceof BedBugEntity
&& aboveUndersideExit
&& ThoraxisUndersideManager.isThoraxis(mob.level())) {
clearInversion(mob);
Antarchy.LOGGER.warn(
"[antarchy-gravity] cleared loaded inverted bed bug above underside exit type={} uuid={} pos=({}, {}, {}) dim={} effectDuration={} effectAmbient={} effectVisible={} nearbyDimensionalTears={}",
mob.getType(), mob.getUUID(), mob.getX(), mob.getY(), mob.getZ(),
mob.level() != null ? mob.level().dimension().location() : "?",
invertedEffect.getDuration(), invertedEffect.isAmbient(), invertedEffect.isVisible(), nearbyDimensionalTears
);
return;
}
Antarchy.LOGGER.info(
"[antarchy-gravity] loaded inverted mob type={} uuid={} pos=({}, {}, {}) dim={} hasInvertedEffect={} effectDuration={} effectAmbient={} effectVisible={} aboveUndersideExit={} nearbyDimensionalTears={}",
mob.getType(), mob.getUUID(), mob.getX(), mob.getY(), mob.getZ(),
mob.level() != null ? mob.level().dimension().location() : "?",
invertedEffect != null,
invertedEffect != null ? invertedEffect.getDuration() : -1,
invertedEffect != null && invertedEffect.isAmbient(),
invertedEffect != null && invertedEffect.isVisible(),
aboveUndersideExit,
nearbyDimensionalTears
);
}
private static void clearInversion(Mob mob) {
mob.removeEffect(AnthologyEffects.inverted());
GravityApi.resetGravityState(mob);
}
private static int countNearbyDimensionalTears(Mob mob) {
if (!(mob.level() instanceof ServerLevel serverLevel)) {
return -1;
}
return serverLevel.getEntitiesOfClass(
DimensionalTearEntity.class,
mob.getBoundingBox().inflate(48.0D),
Entity::isAlive
).size();
}
}
@@ -10,9 +10,9 @@ import com.craisinlord.antarchy.content.entity.HerculesBeetleEntity;
import com.craisinlord.antarchy.content.entity.HushProjectileEntity; import com.craisinlord.antarchy.content.entity.HushProjectileEntity;
import com.craisinlord.antarchy.content.entity.StinkBugEntity; import com.craisinlord.antarchy.content.entity.StinkBugEntity;
import com.craisinlord.antarchy.content.entity.WaterBombEntity; import com.craisinlord.antarchy.content.entity.WaterBombEntity;
import com.craisinlord.antarchy.content.entity.TriffidEntity; import com.craisinlord.antarchy.content.entity.FlytrapEntity;
import com.craisinlord.antarchy.content.entity.CreepingHorrorEntity; import com.craisinlord.antarchy.content.entity.CrawlingBlightEntity;
import com.craisinlord.antarchy.content.entity.LurkingTerrorEntity; import com.craisinlord.antarchy.content.entity.SkulkingFrightEntity;
import com.craisinlord.antarchy.content.entity.ToreterrorEntity; import com.craisinlord.antarchy.content.entity.ToreterrorEntity;
import com.craisinlord.antarchy.content.entity.WaspEntity; import com.craisinlord.antarchy.content.entity.WaspEntity;
import com.craisinlord.antarchy.content.entity.brutalfly.BrutalflyEntity; import com.craisinlord.antarchy.content.entity.brutalfly.BrutalflyEntity;
@@ -33,7 +33,6 @@ import com.craisinlord.antarchy.content.entity.lucid.LucidEntity;
import com.craisinlord.antarchy.content.entity.vortex.VortexChargeProjectileEntity; import com.craisinlord.antarchy.content.entity.vortex.VortexChargeProjectileEntity;
import com.craisinlord.antarchy.content.entity.vortex.VortexEntity; import com.craisinlord.antarchy.content.entity.vortex.VortexEntity;
import com.craisinlord.antarchy.content.entity.vortex.WindVortexEntity; import com.craisinlord.antarchy.content.entity.vortex.WindVortexEntity;
import com.craisinlord.antarchy.content.time.TimeDilationFieldEntity;
import com.craisinlord.antarchy.content.entity.nightmare.NightmareEntity; import com.craisinlord.antarchy.content.entity.nightmare.NightmareEntity;
import com.craisinlord.antarchy.content.entity.nightmare.NightmareBiteEntity; import com.craisinlord.antarchy.content.entity.nightmare.NightmareBiteEntity;
import com.craisinlord.antarchy.content.entity.nightmare.NightmarePortalEntity; import com.craisinlord.antarchy.content.entity.nightmare.NightmarePortalEntity;
@@ -99,8 +98,6 @@ public final class AntarchyObjects {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<EntityType<VortexChargeProjectileEntity>> VORTEX_CHARGE_PROJECTILE = (Supplier<EntityType<VortexChargeProjectileEntity>>) UNBOUND; public static Supplier<EntityType<VortexChargeProjectileEntity>> VORTEX_CHARGE_PROJECTILE = (Supplier<EntityType<VortexChargeProjectileEntity>>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<EntityType<TimeDilationFieldEntity>> TIME_DILATION_FIELD = (Supplier<EntityType<TimeDilationFieldEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalBlackHoleEntity>> ROYAL_BLACK_HOLE = (Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalBlackHoleEntity>>) UNBOUND; public static Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalBlackHoleEntity>> ROYAL_BLACK_HOLE = (Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalBlackHoleEntity>>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalAssailantBlackHoleEntity>> ROYAL_ASSAILANT_BLACK_HOLE = (Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalAssailantBlackHoleEntity>>) UNBOUND; public static Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalAssailantBlackHoleEntity>> ROYAL_ASSAILANT_BLACK_HOLE = (Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalAssailantBlackHoleEntity>>) UNBOUND;
@@ -127,7 +124,7 @@ public final class AntarchyObjects {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<EntityType<ReverieEntity>> REVERIE = (Supplier<EntityType<ReverieEntity>>) UNBOUND; public static Supplier<EntityType<ReverieEntity>> REVERIE = (Supplier<EntityType<ReverieEntity>>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<EntityType<TriffidEntity>> TRIFFID = (Supplier<EntityType<TriffidEntity>>) UNBOUND; public static Supplier<EntityType<FlytrapEntity>> FLYTRAP = (Supplier<EntityType<FlytrapEntity>>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<EntityType<BrutalflyEntity>> BRUTALFLY = (Supplier<EntityType<BrutalflyEntity>>) UNBOUND; public static Supplier<EntityType<BrutalflyEntity>> BRUTALFLY = (Supplier<EntityType<BrutalflyEntity>>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -139,9 +136,9 @@ public final class AntarchyObjects {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<EntityType<WaterBombEntity>> WATER_BOMB = (Supplier<EntityType<WaterBombEntity>>) UNBOUND; public static Supplier<EntityType<WaterBombEntity>> WATER_BOMB = (Supplier<EntityType<WaterBombEntity>>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<EntityType<CreepingHorrorEntity>> CREEPING_HORROR = (Supplier<EntityType<CreepingHorrorEntity>>) UNBOUND; public static Supplier<EntityType<CrawlingBlightEntity>> CRAWLING_BLIGHT = (Supplier<EntityType<CrawlingBlightEntity>>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<EntityType<LurkingTerrorEntity>> LURKING_TERROR = (Supplier<EntityType<LurkingTerrorEntity>>) UNBOUND; public static Supplier<EntityType<SkulkingFrightEntity>> SKULKING_FRIGHT = (Supplier<EntityType<SkulkingFrightEntity>>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<EntityType<com.craisinlord.antarchy.content.entity.ManticoreEntity>> MANTICORE = (Supplier<EntityType<com.craisinlord.antarchy.content.entity.ManticoreEntity>>) UNBOUND; public static Supplier<EntityType<com.craisinlord.antarchy.content.entity.ManticoreEntity>> MANTICORE = (Supplier<EntityType<com.craisinlord.antarchy.content.entity.ManticoreEntity>>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -215,6 +212,8 @@ public final class AntarchyObjects {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<MenuType<com.craisinlord.antarchy.content.menu.RoyalJudgmentMenu>> ROYAL_JUDGMENT_MENU = (Supplier<MenuType<com.craisinlord.antarchy.content.menu.RoyalJudgmentMenu>>) UNBOUND; public static Supplier<MenuType<com.craisinlord.antarchy.content.menu.RoyalJudgmentMenu>> ROYAL_JUDGMENT_MENU = (Supplier<MenuType<com.craisinlord.antarchy.content.menu.RoyalJudgmentMenu>>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<MenuType<com.craisinlord.antarchy.content.menu.GiantFryingPanMenu>> GIANT_FRYING_PAN_MENU = (Supplier<MenuType<com.craisinlord.antarchy.content.menu.GiantFryingPanMenu>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<net.minecraft.world.item.Item> CHEEP_ITEM = (Supplier<net.minecraft.world.item.Item>) UNBOUND; public static Supplier<net.minecraft.world.item.Item> CHEEP_ITEM = (Supplier<net.minecraft.world.item.Item>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<Block> DUPLICATOR_LOG = (Supplier<Block>) UNBOUND; public static Supplier<Block> DUPLICATOR_LOG = (Supplier<Block>) UNBOUND;
@@ -267,7 +266,7 @@ public final class AntarchyObjects {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<Block> CLOUD_BLOCK = (Supplier<Block>) UNBOUND; public static Supplier<Block> CLOUD_BLOCK = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<Block> TRIFFID_GOO_BLOCK = (Supplier<Block>) UNBOUND; public static Supplier<Block> FLYTRAP_GOO_BLOCK = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<Block> PALE_NYXITE = (Supplier<Block>) UNBOUND; public static Supplier<Block> PALE_NYXITE = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -314,6 +313,7 @@ public final class AntarchyObjects {
public static Supplier<Holder<Attribute>> DOUBLE_DAMAGE_CHANCE = (Supplier<Holder<Attribute>>) UNBOUND; public static Supplier<Holder<Attribute>> DOUBLE_DAMAGE_CHANCE = (Supplier<Holder<Attribute>>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<Holder<Attribute>> BLOODGLASS_MAX_HEARTS = (Supplier<Holder<Attribute>>) UNBOUND; public static Supplier<Holder<Attribute>> BLOODGLASS_MAX_HEARTS = (Supplier<Holder<Attribute>>) UNBOUND;
public static Supplier<Attribute> ENTITY_REACH = () -> null;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<MobEffect> BLOODGLASS_WARD = (Supplier<MobEffect>) UNBOUND; public static Supplier<MobEffect> BLOODGLASS_WARD = (Supplier<MobEffect>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -324,9 +324,11 @@ public final class AntarchyObjects {
public static Supplier<MobEffect> STINKY_EFFECT = (Supplier<MobEffect>) UNBOUND; public static Supplier<MobEffect> STINKY_EFFECT = (Supplier<MobEffect>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<MobEffect> GLIMMERING_EFFECT = (Supplier<MobEffect>) UNBOUND; public static Supplier<MobEffect> GLIMMERING_EFFECT = (Supplier<MobEffect>) UNBOUND;
public static Supplier<MobEffect> DILATED_EFFECT = (Supplier<MobEffect>) UNBOUND; public static Supplier<MobEffect> ROYAL_VITALITY_PENALTY_EFFECT = (Supplier<MobEffect>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<MobEffect> CONTRACTED_EFFECT = (Supplier<MobEffect>) UNBOUND; public static Supplier<MobEffect> BLEEDING_EFFECT = (Supplier<MobEffect>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<MobEffect> BLOOD_MOON_EFFECT = (Supplier<MobEffect>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<Fluid> LUMEN = (Supplier<Fluid>) UNBOUND; public static Supplier<Fluid> LUMEN = (Supplier<Fluid>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -352,9 +354,9 @@ public final class AntarchyObjects {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<Block> BED_BUG_EGG = (Supplier<Block>) UNBOUND; public static Supplier<Block> BED_BUG_EGG = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<Block> CREEPING_HORROR_EGGS = (Supplier<Block>) UNBOUND; public static Supplier<Block> CRAWLING_BLIGHT_EGGS = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<Block> LURKING_TERROR_EGGS = (Supplier<Block>) UNBOUND; public static Supplier<Block> SKULKING_FRIGHT_EGGS = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<Block> WASP_NEST = (Supplier<Block>) UNBOUND; public static Supplier<Block> WASP_NEST = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -400,6 +402,8 @@ public final class AntarchyObjects {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<SimpleParticleType> STINKY_GAS = (Supplier<SimpleParticleType>) UNBOUND; public static Supplier<SimpleParticleType> STINKY_GAS = (Supplier<SimpleParticleType>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<SimpleParticleType> BUG_SPRAY_PARTICLE = (Supplier<SimpleParticleType>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<SimpleParticleType> NIGHTMARE_FIRE_FLAME = (Supplier<SimpleParticleType>) UNBOUND; public static Supplier<SimpleParticleType> NIGHTMARE_FIRE_FLAME = (Supplier<SimpleParticleType>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<SimpleParticleType> STINKY_FLY = (Supplier<SimpleParticleType>) UNBOUND; public static Supplier<SimpleParticleType> STINKY_FLY = (Supplier<SimpleParticleType>) UNBOUND;
@@ -432,11 +436,6 @@ public final class AntarchyObjects {
private AntarchyObjects() { private AntarchyObjects() {
} }
/** Compatibility entry point for loader registries that bind the expanded 1.21 object set. */
public static void bind(Supplier<?>... ignored) {
// Loader-specific registrations populate the fields through the explicit setters below.
}
public static void bind( public static void bind(
Supplier<EntityType<EasterBunnyEntity>> easterBunny, Supplier<EntityType<EasterBunnyEntity>> easterBunny,
Supplier<EntityType<FlyingSquirrelEntity>> flyingSquirrel, Supplier<EntityType<FlyingSquirrelEntity>> flyingSquirrel,
@@ -451,14 +450,14 @@ public final class AntarchyObjects {
Supplier<EntityType<CaterpillarEntity>> caterpillar, Supplier<EntityType<CaterpillarEntity>> caterpillar,
Supplier<EntityType<ButterflyEntity>> butterfly, Supplier<EntityType<ButterflyEntity>> butterfly,
Supplier<EntityType<ReverieEntity>> reverie, Supplier<EntityType<ReverieEntity>> reverie,
Supplier<EntityType<TriffidEntity>> triffid, Supplier<EntityType<FlytrapEntity>> flytrap,
Supplier<EntityType<BrutalflyEntity>> brutalfly, Supplier<EntityType<BrutalflyEntity>> brutalfly,
Supplier<EntityType<BrutalflyOrbEntity>> brutalflyOrb, Supplier<EntityType<BrutalflyOrbEntity>> brutalflyOrb,
Supplier<EntityType<HushProjectileEntity>> hushProjectile, Supplier<EntityType<HushProjectileEntity>> hushProjectile,
Supplier<EntityType<ToreterrorEntity>> toreterror, Supplier<EntityType<ToreterrorEntity>> toreterror,
Supplier<EntityType<WaterBombEntity>> waterBomb, Supplier<EntityType<WaterBombEntity>> waterBomb,
Supplier<EntityType<CreepingHorrorEntity>> creepingHorror, Supplier<EntityType<CrawlingBlightEntity>> crawlingBlight,
Supplier<EntityType<LurkingTerrorEntity>> lurkingTerror, Supplier<EntityType<SkulkingFrightEntity>> skulkingFright,
Supplier<EntityType<StinkBugEntity>> stinkBug, Supplier<EntityType<StinkBugEntity>> stinkBug,
Supplier<EntityType<com.craisinlord.antarchy.content.entity.CheepEntity>> cheep, Supplier<EntityType<com.craisinlord.antarchy.content.entity.CheepEntity>> cheep,
Supplier<EntityType<com.craisinlord.antarchy.content.entity.DorrieEntity>> dorrie, Supplier<EntityType<com.craisinlord.antarchy.content.entity.DorrieEntity>> dorrie,
@@ -487,7 +486,7 @@ public final class AntarchyObjects {
Supplier<Block> shellstoneBrickSlab, Supplier<Block> shellstoneBrickSlab,
Supplier<Block> shellstoneBrickWall, Supplier<Block> shellstoneBrickWall,
Supplier<Block> cloudBlock, Supplier<Block> cloudBlock,
Supplier<Block> triffidGooBlock, Supplier<Block> flytrapGooBlock,
Supplier<Block> paleNyxite, Supplier<Block> paleNyxite,
Supplier<Block> nyxiteSpike, Supplier<Block> nyxiteSpike,
Supplier<Block> chitinBlock, Supplier<Block> chitinBlock,
@@ -519,8 +518,8 @@ public final class AntarchyObjects {
Supplier<Block> orangeMilkweed, Supplier<Block> orangeMilkweed,
Supplier<Block> pinkMilkweed, Supplier<Block> pinkMilkweed,
Supplier<Block> bedBugEggs, Supplier<Block> bedBugEggs,
Supplier<Block> creepingHorrorEggs, Supplier<Block> crawlingBlightEggs,
Supplier<Block> lurkingTerrorEggs, Supplier<Block> skulkingFrightEggs,
Supplier<Block> waspNest, Supplier<Block> waspNest,
Supplier<Block> hushweed, Supplier<Block> hushweed,
Supplier<Block> squirrelNestBlock, Supplier<Block> squirrelNestBlock,
@@ -552,14 +551,14 @@ public final class AntarchyObjects {
CATERPILLAR = caterpillar; CATERPILLAR = caterpillar;
BUTTERFLY = butterfly; BUTTERFLY = butterfly;
REVERIE = reverie; REVERIE = reverie;
TRIFFID = triffid; FLYTRAP = flytrap;
BRUTALFLY = brutalfly; BRUTALFLY = brutalfly;
BRUTALFLY_ORB = brutalflyOrb; BRUTALFLY_ORB = brutalflyOrb;
HUSH_PROJECTILE = hushProjectile; HUSH_PROJECTILE = hushProjectile;
TORETERROR = toreterror; TORETERROR = toreterror;
WATER_BOMB = waterBomb; WATER_BOMB = waterBomb;
CREEPING_HORROR = creepingHorror; CRAWLING_BLIGHT = crawlingBlight;
LURKING_TERROR = lurkingTerror; SKULKING_FRIGHT = skulkingFright;
STINK_BUG = stinkBug; STINK_BUG = stinkBug;
CHEEP = cheep; CHEEP = cheep;
DORRIE = dorrie; DORRIE = dorrie;
@@ -588,7 +587,7 @@ public final class AntarchyObjects {
SHELLSTONE_BRICK_SLAB = shellstoneBrickSlab; SHELLSTONE_BRICK_SLAB = shellstoneBrickSlab;
SHELLSTONE_BRICK_WALL = shellstoneBrickWall; SHELLSTONE_BRICK_WALL = shellstoneBrickWall;
CLOUD_BLOCK = cloudBlock; CLOUD_BLOCK = cloudBlock;
TRIFFID_GOO_BLOCK = triffidGooBlock; FLYTRAP_GOO_BLOCK = flytrapGooBlock;
PALE_NYXITE = paleNyxite; PALE_NYXITE = paleNyxite;
NYXITE_SPIKE = nyxiteSpike; NYXITE_SPIKE = nyxiteSpike;
CHITIN_BLOCK = chitinBlock; CHITIN_BLOCK = chitinBlock;
@@ -620,8 +619,8 @@ public final class AntarchyObjects {
ORANGE_MILKWEED = orangeMilkweed; ORANGE_MILKWEED = orangeMilkweed;
PINK_MILKWEED = pinkMilkweed; PINK_MILKWEED = pinkMilkweed;
BED_BUG_EGG = bedBugEggs; BED_BUG_EGG = bedBugEggs;
CREEPING_HORROR_EGGS = creepingHorrorEggs; CRAWLING_BLIGHT_EGGS = crawlingBlightEggs;
LURKING_TERROR_EGGS = lurkingTerrorEggs; SKULKING_FRIGHT_EGGS = skulkingFrightEggs;
WASP_NEST = waspNest; WASP_NEST = waspNest;
HUSHWEED = hushweed; HUSHWEED = hushweed;
SQUIRREL_NEST_BLOCK = squirrelNestBlock; SQUIRREL_NEST_BLOCK = squirrelNestBlock;
@@ -649,6 +648,10 @@ public final class AntarchyObjects {
OCTOPUS_BOMB = supplier; OCTOPUS_BOMB = supplier;
} }
public static void setBugSprayParticle(Supplier<SimpleParticleType> supplier) {
BUG_SPRAY_PARTICLE = supplier;
}
public static void setTentacle(Supplier<EntityType<TentacleEntity>> supplier) { public static void setTentacle(Supplier<EntityType<TentacleEntity>> supplier) {
TENTACLE = supplier; TENTACLE = supplier;
} }
@@ -695,10 +698,6 @@ public final class AntarchyObjects {
VORTEX_CHARGE_PROJECTILE = supplier; VORTEX_CHARGE_PROJECTILE = supplier;
} }
public static void setTimeDilationField(Supplier<EntityType<TimeDilationFieldEntity>> supplier) {
TIME_DILATION_FIELD = supplier;
}
public static void setRoyalBlackHole(Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalBlackHoleEntity>> supplier) { public static void setRoyalBlackHole(Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalBlackHoleEntity>> supplier) {
ROYAL_BLACK_HOLE = supplier; ROYAL_BLACK_HOLE = supplier;
} }
@@ -823,12 +822,16 @@ public final class AntarchyObjects {
GLIMMERING_EFFECT = supplier; GLIMMERING_EFFECT = supplier;
} }
public static void setDilatedEffect(Supplier<MobEffect> supplier) { public static void setRoyalVitalityPenaltyEffect(Supplier<MobEffect> supplier) {
DILATED_EFFECT = supplier; ROYAL_VITALITY_PENALTY_EFFECT = supplier;
} }
public static void setContractedEffect(Supplier<MobEffect> supplier) { public static void setBleedingEffect(Supplier<MobEffect> supplier) {
CONTRACTED_EFFECT = supplier; BLEEDING_EFFECT = supplier;
}
public static void setBloodMoonEffect(Supplier<MobEffect> supplier) {
BLOOD_MOON_EFFECT = supplier;
} }
public static void setElka(Supplier<EntityType<com.craisinlord.antarchy.content.entity.ElkaEntity>> supplier) { public static void setElka(Supplier<EntityType<com.craisinlord.antarchy.content.entity.ElkaEntity>> supplier) {
@@ -907,6 +910,10 @@ public final class AntarchyObjects {
LUCID_BOLT_IMPACT_LARGE = supplier; LUCID_BOLT_IMPACT_LARGE = supplier;
} }
public static void setEntityReach(Supplier<Attribute> supplier) {
ENTITY_REACH = supplier;
}
public static void setPeachLeavesParticle(Supplier<SimpleParticleType> supplier) { public static void setPeachLeavesParticle(Supplier<SimpleParticleType> supplier) {
PEACH_LEAVES_PARTICLE = supplier; PEACH_LEAVES_PARTICLE = supplier;
} }
@@ -923,6 +930,10 @@ public final class AntarchyObjects {
ROYAL_JUDGMENT_MENU = supplier; ROYAL_JUDGMENT_MENU = supplier;
} }
public static void setGiantFryingPanMenu(Supplier<MenuType<com.craisinlord.antarchy.content.menu.GiantFryingPanMenu>> supplier) {
GIANT_FRYING_PAN_MENU = supplier;
}
public static void setAmericanComponent(Supplier<AntarchyItemComponent<net.minecraft.util.Unit>> supplier) { public static void setAmericanComponent(Supplier<AntarchyItemComponent<net.minecraft.util.Unit>> supplier) {
AMERICAN_COMPONENT = supplier.get(); AMERICAN_COMPONENT = supplier.get();
} }
@@ -26,11 +26,11 @@ public final class AntarchySoundEvents {
public static Supplier<SoundEvent> ANT_BITE = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> ANT_BITE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> ANT_GATHER = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> ANT_GATHER = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> ANT_NEST = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> ANT_NEST = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> CLOUD_SHARK_BITE = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> STRATOSHARK_BITE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> CLOUD_SHARK_IDLE = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> STRATOSHARK_IDLE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> CLOUD_SHARK_HURT = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> STRATOSHARK_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> CLOUD_SHARK_DEATH = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> STRATOSHARK_DEATH = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> CLOUD_SHARK_FLY = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> STRATOSHARK_FLY = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> CATERPILLAR_IDLE = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> CATERPILLAR_IDLE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> CATERPILLAR_HURT = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> CATERPILLAR_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> CATERPILLAR_CRAWL = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> CATERPILLAR_CRAWL = (Supplier<SoundEvent>) UNBOUND;
@@ -94,16 +94,20 @@ public final class AntarchySoundEvents {
public static Supplier<SoundEvent> NIGHTMARE_DEATH = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> NIGHTMARE_DEATH = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> NIGHTMARE_BITE = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> NIGHTMARE_BITE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> NIGHTMARE_FLAP = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> NIGHTMARE_FLAP = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> TRIFFID_ATTACK = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> FLYTRAP_ATTACK = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> TRIFFID_GRAB = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> FLYTRAP_GRAB = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> TRIFFID_HURT = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> FLYTRAP_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> TRIFFID_DEATH = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> FLYTRAP_DEATH = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> TRIFFID_HISS = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> FLYTRAP_HISS = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> TRIFFID_GROWL = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> FLYTRAP_GROWL = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> MANTIS_AMBIENT = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> MANTIS_AMBIENT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> MANTIS_HURT = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> MANTIS_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> MANTIS_ATTACK = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> MANTIS_ATTACK = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> MANTIS_FLY_LOOP = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> MANTIS_FLY_LOOP = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> MANTICORE_IDLE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> MANTICORE_WALK = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> MANTICORE_FLY = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> MANTICORE_BITE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> GRAVITY_GUN_PICKUP = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> GRAVITY_GUN_PICKUP = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> GRAVITY_GUN_DROP = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> GRAVITY_GUN_DROP = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> GRAVITY_GUN_HOLD_LOOP = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> GRAVITY_GUN_HOLD_LOOP = (Supplier<SoundEvent>) UNBOUND;
@@ -148,13 +152,13 @@ public final class AntarchySoundEvents {
public static Supplier<SoundEvent> STINK_BUG_IDLE = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> STINK_BUG_IDLE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> CAVARYN_HEARTBEAT = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> CAVARYN_HEARTBEAT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> ROLLY_POLLY_IDLE = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> ROLLY_POLLY_IDLE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> CREEPING_HORROR_GROWL = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> CRAWLING_BLIGHT_GROWL = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> CREEPING_HORROR_HURT = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> CRAWLING_BLIGHT_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> CREEPING_HORROR_BITE = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> CRAWLING_BLIGHT_BITE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> LURKING_TERROR_SNARL = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> SKULKING_FRIGHT_SNARL = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> LURKING_TERROR_HURT = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> SKULKING_FRIGHT_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> LURKING_TERROR_BITE = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> SKULKING_FRIGHT_BITE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> LURKING_TERROR_FLY_LOOP = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> SKULKING_FRIGHT_FLY_LOOP = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> DUCT_TAPE_USE = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> DUCT_TAPE_USE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> HERCULES_BEETLE_IDLE = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> HERCULES_BEETLE_IDLE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> HERCULES_BEETLE_HURT = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> HERCULES_BEETLE_HURT = (Supplier<SoundEvent>) UNBOUND;
@@ -162,10 +166,10 @@ public final class AntarchySoundEvents {
public static Supplier<SoundEvent> HERCULES_BEETLE_CRY = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> HERCULES_BEETLE_CRY = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> HERCULES_BEETLE_CHARGE_START = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> HERCULES_BEETLE_CHARGE_START = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> HERCULES_BEETLE_KNOCKED_DOWN = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> HERCULES_BEETLE_KNOCKED_DOWN = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> JUMPY_BUG_IDLE = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> SPRINGBUG_IDLE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> SPIT_BUG_IDLE = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> SPIT_BUG_IDLE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> JUMPY_BUG_HURT = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> SPRINGBUG_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> JUMPY_BUG_JUMP = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> SPRINGBUG_JUMP = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> SPIT_BUG_HURT = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> SPIT_BUG_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> SPIT_BUG_SPIT = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> SPIT_BUG_SPIT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> BRUTALFLY_SPIT = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> BRUTALFLY_SPIT = (Supplier<SoundEvent>) UNBOUND;
@@ -196,6 +200,7 @@ public final class AntarchySoundEvents {
public static Supplier<SoundEvent> QUEEN_ROAR = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> QUEEN_ROAR = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> KING_BEAM_SHOOT = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> KING_BEAM_SHOOT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> KING_FIREBALL_SHOOT = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> KING_FIREBALL_SHOOT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> KING_ICE_SPIKES = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> KING_DECREE_CAST = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> KING_DECREE_CAST = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> QUEEN_BEAM_SHOOT = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> QUEEN_BEAM_SHOOT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> QUEEN_BEAM_START = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> QUEEN_BEAM_START = (Supplier<SoundEvent>) UNBOUND;
@@ -216,6 +221,12 @@ public final class AntarchySoundEvents {
public static Supplier<SoundEvent> PRINCESS_SHOOT = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> PRINCESS_SHOOT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> PRINCESS_FLY = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> PRINCESS_FLY = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> PRINCESS_STEP = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> PRINCESS_STEP = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> KING_DECREE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> KING_SUCCESS = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> KING_JUDGEMENT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> HOVERBOARD_MOUNT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> HOVERBOARD_DISMOUNT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> HOVERBOARD_IDLE = (Supplier<SoundEvent>) UNBOUND;
private AntarchySoundEvents() { private AntarchySoundEvents() {
} }
@@ -238,11 +249,11 @@ public final class AntarchySoundEvents {
Supplier<SoundEvent> antBite, Supplier<SoundEvent> antBite,
Supplier<SoundEvent> antGather, Supplier<SoundEvent> antGather,
Supplier<SoundEvent> antNest, Supplier<SoundEvent> antNest,
Supplier<SoundEvent> cloudSharkBite, Supplier<SoundEvent> stratosharkBite,
Supplier<SoundEvent> cloudSharkIdle, Supplier<SoundEvent> stratosharkIdle,
Supplier<SoundEvent> cloudSharkHurt, Supplier<SoundEvent> stratosharkHurt,
Supplier<SoundEvent> cloudSharkDeath, Supplier<SoundEvent> stratosharkDeath,
Supplier<SoundEvent> cloudSharkFly, Supplier<SoundEvent> stratosharkFly,
Supplier<SoundEvent> caterpillarIdle, Supplier<SoundEvent> caterpillarIdle,
Supplier<SoundEvent> caterpillarHurt, Supplier<SoundEvent> caterpillarHurt,
Supplier<SoundEvent> caterpillarCrawl, Supplier<SoundEvent> caterpillarCrawl,
@@ -302,16 +313,20 @@ public final class AntarchySoundEvents {
Supplier<SoundEvent> nightmareDeath, Supplier<SoundEvent> nightmareDeath,
Supplier<SoundEvent> nightmareBite, Supplier<SoundEvent> nightmareBite,
Supplier<SoundEvent> nightmareFlap, Supplier<SoundEvent> nightmareFlap,
Supplier<SoundEvent> triffidAttack, Supplier<SoundEvent> flytrapAttack,
Supplier<SoundEvent> triffidGrab, Supplier<SoundEvent> flytrapGrab,
Supplier<SoundEvent> triffidHurt, Supplier<SoundEvent> flytrapHurt,
Supplier<SoundEvent> triffidDeath, Supplier<SoundEvent> flytrapDeath,
Supplier<SoundEvent> triffidHiss, Supplier<SoundEvent> flytrapHiss,
Supplier<SoundEvent> triffidGrowl, Supplier<SoundEvent> flytrapGrowl,
Supplier<SoundEvent> mantisAmbient, Supplier<SoundEvent> mantisAmbient,
Supplier<SoundEvent> mantisHurt, Supplier<SoundEvent> mantisHurt,
Supplier<SoundEvent> mantisAttack, Supplier<SoundEvent> mantisAttack,
Supplier<SoundEvent> mantisFlyLoop, Supplier<SoundEvent> mantisFlyLoop,
Supplier<SoundEvent> manticoreIdle,
Supplier<SoundEvent> manticoreWalk,
Supplier<SoundEvent> manticoreFly,
Supplier<SoundEvent> manticoreBite,
Supplier<SoundEvent> gravityGunPickup, Supplier<SoundEvent> gravityGunPickup,
Supplier<SoundEvent> gravityGunDrop, Supplier<SoundEvent> gravityGunDrop,
Supplier<SoundEvent> gravityGunHoldLoop, Supplier<SoundEvent> gravityGunHoldLoop,
@@ -356,13 +371,13 @@ public final class AntarchySoundEvents {
Supplier<SoundEvent> stinkBugIdle, Supplier<SoundEvent> stinkBugIdle,
Supplier<SoundEvent> cavarynHeartbeat, Supplier<SoundEvent> cavarynHeartbeat,
Supplier<SoundEvent> rollyPollyIdle, Supplier<SoundEvent> rollyPollyIdle,
Supplier<SoundEvent> creepingHorrorGrowl, Supplier<SoundEvent> crawlingBlightGrowl,
Supplier<SoundEvent> creepingHorrorHurt, Supplier<SoundEvent> crawlingBlightHurt,
Supplier<SoundEvent> creepingHorrorBite, Supplier<SoundEvent> crawlingBlightBite,
Supplier<SoundEvent> lurkingTerrorSnarl, Supplier<SoundEvent> skulkingFrightSnarl,
Supplier<SoundEvent> lurkingTerrorHurt, Supplier<SoundEvent> skulkingFrightHurt,
Supplier<SoundEvent> lurkingTerrorBite, Supplier<SoundEvent> skulkingFrightBite,
Supplier<SoundEvent> lurkingTerrorFlyLoop, Supplier<SoundEvent> skulkingFrightFlyLoop,
Supplier<SoundEvent> ductTapeUse, Supplier<SoundEvent> ductTapeUse,
Supplier<SoundEvent> herculesBeetleIdle, Supplier<SoundEvent> herculesBeetleIdle,
Supplier<SoundEvent> herculesBeetleHurt, Supplier<SoundEvent> herculesBeetleHurt,
@@ -370,10 +385,10 @@ public final class AntarchySoundEvents {
Supplier<SoundEvent> herculesBeetleCry, Supplier<SoundEvent> herculesBeetleCry,
Supplier<SoundEvent> herculesBeetleChargeStart, Supplier<SoundEvent> herculesBeetleChargeStart,
Supplier<SoundEvent> herculesBeetleKnockedDown, Supplier<SoundEvent> herculesBeetleKnockedDown,
Supplier<SoundEvent> jumpyBugIdle, Supplier<SoundEvent> springbugIdle,
Supplier<SoundEvent> spitBugIdle, Supplier<SoundEvent> spitBugIdle,
Supplier<SoundEvent> jumpyBugHurt, Supplier<SoundEvent> springbugHurt,
Supplier<SoundEvent> jumpyBugJump, Supplier<SoundEvent> springbugJump,
Supplier<SoundEvent> spitBugHurt, Supplier<SoundEvent> spitBugHurt,
Supplier<SoundEvent> spitBugSpit, Supplier<SoundEvent> spitBugSpit,
Supplier<SoundEvent> brutalflySpit, Supplier<SoundEvent> brutalflySpit,
@@ -404,6 +419,7 @@ public final class AntarchySoundEvents {
Supplier<SoundEvent> queenRoar, Supplier<SoundEvent> queenRoar,
Supplier<SoundEvent> kingBeamShoot, Supplier<SoundEvent> kingBeamShoot,
Supplier<SoundEvent> kingFireballShoot, Supplier<SoundEvent> kingFireballShoot,
Supplier<SoundEvent> kingIceSpikes,
Supplier<SoundEvent> kingDecreeCast, Supplier<SoundEvent> kingDecreeCast,
Supplier<SoundEvent> queenBeamShoot, Supplier<SoundEvent> queenBeamShoot,
Supplier<SoundEvent> queenBeamStart, Supplier<SoundEvent> queenBeamStart,
@@ -423,7 +439,10 @@ public final class AntarchySoundEvents {
Supplier<SoundEvent> princessBite, Supplier<SoundEvent> princessBite,
Supplier<SoundEvent> princessShoot, Supplier<SoundEvent> princessShoot,
Supplier<SoundEvent> princessFly, Supplier<SoundEvent> princessFly,
Supplier<SoundEvent> princessStep Supplier<SoundEvent> princessStep,
Supplier<SoundEvent> kingDecree,
Supplier<SoundEvent> kingSuccess,
Supplier<SoundEvent> kingJudgement
) { ) {
SQUIDZOOKA_FIRE = squidzookaFire; SQUIDZOOKA_FIRE = squidzookaFire;
SHRINK_RAY_CHARGE = shrinkRayCharge; SHRINK_RAY_CHARGE = shrinkRayCharge;
@@ -439,11 +458,11 @@ public final class AntarchySoundEvents {
ANT_BITE = antBite; ANT_BITE = antBite;
ANT_GATHER = antGather; ANT_GATHER = antGather;
ANT_NEST = antNest; ANT_NEST = antNest;
CLOUD_SHARK_BITE = cloudSharkBite; STRATOSHARK_BITE = stratosharkBite;
CLOUD_SHARK_IDLE = cloudSharkIdle; STRATOSHARK_IDLE = stratosharkIdle;
CLOUD_SHARK_HURT = cloudSharkHurt; STRATOSHARK_HURT = stratosharkHurt;
CLOUD_SHARK_DEATH = cloudSharkDeath; STRATOSHARK_DEATH = stratosharkDeath;
CLOUD_SHARK_FLY = cloudSharkFly; STRATOSHARK_FLY = stratosharkFly;
CATERPILLAR_IDLE = caterpillarIdle; CATERPILLAR_IDLE = caterpillarIdle;
CATERPILLAR_HURT = caterpillarHurt; CATERPILLAR_HURT = caterpillarHurt;
CATERPILLAR_CRAWL = caterpillarCrawl; CATERPILLAR_CRAWL = caterpillarCrawl;
@@ -503,16 +522,20 @@ public final class AntarchySoundEvents {
NIGHTMARE_DEATH = nightmareDeath; NIGHTMARE_DEATH = nightmareDeath;
NIGHTMARE_BITE = nightmareBite; NIGHTMARE_BITE = nightmareBite;
NIGHTMARE_FLAP = nightmareFlap; NIGHTMARE_FLAP = nightmareFlap;
TRIFFID_ATTACK = triffidAttack; FLYTRAP_ATTACK = flytrapAttack;
TRIFFID_GRAB = triffidGrab; FLYTRAP_GRAB = flytrapGrab;
TRIFFID_HURT = triffidHurt; FLYTRAP_HURT = flytrapHurt;
TRIFFID_DEATH = triffidDeath; FLYTRAP_DEATH = flytrapDeath;
TRIFFID_HISS = triffidHiss; FLYTRAP_HISS = flytrapHiss;
TRIFFID_GROWL = triffidGrowl; FLYTRAP_GROWL = flytrapGrowl;
MANTIS_AMBIENT = mantisAmbient; MANTIS_AMBIENT = mantisAmbient;
MANTIS_HURT = mantisHurt; MANTIS_HURT = mantisHurt;
MANTIS_ATTACK = mantisAttack; MANTIS_ATTACK = mantisAttack;
MANTIS_FLY_LOOP = mantisFlyLoop; MANTIS_FLY_LOOP = mantisFlyLoop;
MANTICORE_IDLE = manticoreIdle;
MANTICORE_WALK = manticoreWalk;
MANTICORE_FLY = manticoreFly;
MANTICORE_BITE = manticoreBite;
GRAVITY_GUN_PICKUP = gravityGunPickup; GRAVITY_GUN_PICKUP = gravityGunPickup;
GRAVITY_GUN_DROP = gravityGunDrop; GRAVITY_GUN_DROP = gravityGunDrop;
GRAVITY_GUN_HOLD_LOOP = gravityGunHoldLoop; GRAVITY_GUN_HOLD_LOOP = gravityGunHoldLoop;
@@ -557,13 +580,13 @@ public final class AntarchySoundEvents {
STINK_BUG_IDLE = stinkBugIdle; STINK_BUG_IDLE = stinkBugIdle;
CAVARYN_HEARTBEAT = cavarynHeartbeat; CAVARYN_HEARTBEAT = cavarynHeartbeat;
ROLLY_POLLY_IDLE = rollyPollyIdle; ROLLY_POLLY_IDLE = rollyPollyIdle;
CREEPING_HORROR_GROWL = creepingHorrorGrowl; CRAWLING_BLIGHT_GROWL = crawlingBlightGrowl;
CREEPING_HORROR_HURT = creepingHorrorHurt; CRAWLING_BLIGHT_HURT = crawlingBlightHurt;
CREEPING_HORROR_BITE = creepingHorrorBite; CRAWLING_BLIGHT_BITE = crawlingBlightBite;
LURKING_TERROR_SNARL = lurkingTerrorSnarl; SKULKING_FRIGHT_SNARL = skulkingFrightSnarl;
LURKING_TERROR_HURT = lurkingTerrorHurt; SKULKING_FRIGHT_HURT = skulkingFrightHurt;
LURKING_TERROR_BITE = lurkingTerrorBite; SKULKING_FRIGHT_BITE = skulkingFrightBite;
LURKING_TERROR_FLY_LOOP = lurkingTerrorFlyLoop; SKULKING_FRIGHT_FLY_LOOP = skulkingFrightFlyLoop;
DUCT_TAPE_USE = ductTapeUse; DUCT_TAPE_USE = ductTapeUse;
HERCULES_BEETLE_IDLE = herculesBeetleIdle; HERCULES_BEETLE_IDLE = herculesBeetleIdle;
HERCULES_BEETLE_HURT = herculesBeetleHurt; HERCULES_BEETLE_HURT = herculesBeetleHurt;
@@ -571,10 +594,10 @@ public final class AntarchySoundEvents {
HERCULES_BEETLE_CRY = herculesBeetleCry; HERCULES_BEETLE_CRY = herculesBeetleCry;
HERCULES_BEETLE_CHARGE_START = herculesBeetleChargeStart; HERCULES_BEETLE_CHARGE_START = herculesBeetleChargeStart;
HERCULES_BEETLE_KNOCKED_DOWN = herculesBeetleKnockedDown; HERCULES_BEETLE_KNOCKED_DOWN = herculesBeetleKnockedDown;
JUMPY_BUG_IDLE = jumpyBugIdle; SPRINGBUG_IDLE = springbugIdle;
SPIT_BUG_IDLE = spitBugIdle; SPIT_BUG_IDLE = spitBugIdle;
JUMPY_BUG_HURT = jumpyBugHurt; SPRINGBUG_HURT = springbugHurt;
JUMPY_BUG_JUMP = jumpyBugJump; SPRINGBUG_JUMP = springbugJump;
SPIT_BUG_HURT = spitBugHurt; SPIT_BUG_HURT = spitBugHurt;
SPIT_BUG_SPIT = spitBugSpit; SPIT_BUG_SPIT = spitBugSpit;
BRUTALFLY_SPIT = brutalflySpit; BRUTALFLY_SPIT = brutalflySpit;
@@ -605,6 +628,7 @@ public final class AntarchySoundEvents {
QUEEN_ROAR = queenRoar; QUEEN_ROAR = queenRoar;
KING_BEAM_SHOOT = kingBeamShoot; KING_BEAM_SHOOT = kingBeamShoot;
KING_FIREBALL_SHOOT = kingFireballShoot; KING_FIREBALL_SHOOT = kingFireballShoot;
KING_ICE_SPIKES = kingIceSpikes;
KING_DECREE_CAST = kingDecreeCast; KING_DECREE_CAST = kingDecreeCast;
QUEEN_BEAM_SHOOT = queenBeamShoot; QUEEN_BEAM_SHOOT = queenBeamShoot;
QUEEN_BEAM_START = queenBeamStart; QUEEN_BEAM_START = queenBeamStart;
@@ -625,6 +649,9 @@ public final class AntarchySoundEvents {
PRINCESS_SHOOT = princessShoot; PRINCESS_SHOOT = princessShoot;
PRINCESS_FLY = princessFly; PRINCESS_FLY = princessFly;
PRINCESS_STEP = princessStep; PRINCESS_STEP = princessStep;
KING_DECREE = kingDecree;
KING_SUCCESS = kingSuccess;
KING_JUDGEMENT = kingJudgement;
} }
public static void bindDimensionalTearSounds( public static void bindDimensionalTearSounds(
@@ -638,4 +665,10 @@ public final class AntarchySoundEvents {
DIMENSIONAL_TEAR_CREATURE_LEAVES = dimensionalTearCreatureLeaves; DIMENSIONAL_TEAR_CREATURE_LEAVES = dimensionalTearCreatureLeaves;
DIMENSIONAL_TEAR_CLOSE = dimensionalTearClose; DIMENSIONAL_TEAR_CLOSE = dimensionalTearClose;
} }
public static void bindHoverboardSounds(Supplier<SoundEvent> mount, Supplier<SoundEvent> dismount, Supplier<SoundEvent> idle) {
HOVERBOARD_MOUNT = mount;
HOVERBOARD_DISMOUNT = dismount;
HOVERBOARD_IDLE = idle;
}
} }
@@ -1,5 +1,6 @@
package com.craisinlord.antarchy.content; package com.craisinlord.antarchy.content;
import com.craisinlord.anthology.time.TimeDilationTags;
import com.craisinlord.antarchy.Antarchy; import com.craisinlord.antarchy.Antarchy;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
@@ -10,6 +11,7 @@ import net.minecraft.world.entity.EntityType;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.dimension.DimensionType;
import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.Fluid;
public final class AntarchyTags { public final class AntarchyTags {
@@ -23,6 +25,7 @@ public final class AntarchyTags {
public static final class Blocks { public static final class Blocks {
public static final TagKey<Block> DUPLICATOR_TREE_BLACKLIST = TagKey.create(Registries.BLOCK, id("duplicator_tree_blacklist")); public static final TagKey<Block> DUPLICATOR_TREE_BLACKLIST = TagKey.create(Registries.BLOCK, id("duplicator_tree_blacklist"));
public static final TagKey<Block> GRAVITY_GUN_BLACKLIST = TagKey.create(Registries.BLOCK, id("gravity_gun_blacklist")); public static final TagKey<Block> GRAVITY_GUN_BLACKLIST = TagKey.create(Registries.BLOCK, id("gravity_gun_blacklist"));
public static final TagKey<Block> QUEEN_GRABBABLE_BLOCKS = TagKey.create(Registries.BLOCK, id("queen_grabbable_blocks"));
public static final TagKey<Block> DREAM_FIRE_BASE_BLOCKS = TagKey.create(Registries.BLOCK, id("dream_fire_base_blocks")); public static final TagKey<Block> DREAM_FIRE_BASE_BLOCKS = TagKey.create(Registries.BLOCK, id("dream_fire_base_blocks"));
public static final TagKey<Block> POTENT_NYXITE_ACTIVATION_BLOCKS = TagKey.create(Registries.BLOCK, id("potent_nyxite_activation_blocks")); public static final TagKey<Block> POTENT_NYXITE_ACTIVATION_BLOCKS = TagKey.create(Registries.BLOCK, id("potent_nyxite_activation_blocks"));
public static final TagKey<Block> CORNEA_STALK_PLANTABLE = TagKey.create(Registries.BLOCK, id("cornea_stalk_plantable")); public static final TagKey<Block> CORNEA_STALK_PLANTABLE = TagKey.create(Registries.BLOCK, id("cornea_stalk_plantable"));
@@ -43,8 +46,8 @@ public final class AntarchyTags {
public static final TagKey<Block> BLUESTONE_COMPONENTS = TagKey.create(Registries.BLOCK, id("bluestone_components")); public static final TagKey<Block> BLUESTONE_COMPONENTS = TagKey.create(Registries.BLOCK, id("bluestone_components"));
public static final TagKey<Block> BLUESTONE_CONNECTABLE = TagKey.create(Registries.BLOCK, id("bluestone_connectable")); public static final TagKey<Block> BLUESTONE_CONNECTABLE = TagKey.create(Registries.BLOCK, id("bluestone_connectable"));
public static final TagKey<Block> ANTIMETAL_INVERSION_BLOCKS = TagKey.create(Registries.BLOCK, id("antimetal_inversion_blocks")); public static final TagKey<Block> ANTIMETAL_INVERSION_BLOCKS = TagKey.create(Registries.BLOCK, id("antimetal_inversion_blocks"));
public static final TagKey<Block> LUCID_ANCHOR_BASE_BLOCKS = TagKey.create(Registries.BLOCK, id("lucid_anchor_base_blocks"));
public static final TagKey<Block> TIGER_EYE_CAMOUFLAGE_BLACKLIST = TagKey.create(Registries.BLOCK, id("tiger_eye_camouflage_blacklist")); public static final TagKey<Block> TIGER_EYE_CAMOUFLAGE_BLACKLIST = TagKey.create(Registries.BLOCK, id("tiger_eye_camouflage_blacklist"));
public static final TagKey<Block> LUCID_ANCHOR_BASE_BLOCKS = TagKey.create(Registries.BLOCK, id("lucid_anchor_base_blocks"));
public static final TagKey<Block> NYXIUM = TagKey.create(Registries.BLOCK, id("nyxium")); public static final TagKey<Block> NYXIUM = TagKey.create(Registries.BLOCK, id("nyxium"));
private Blocks() { private Blocks() {
@@ -54,6 +57,8 @@ public final class AntarchyTags {
public static final class DamageType { public static final class DamageType {
public static final TagKey<net.minecraft.world.damagesource.DamageType> BYPASSES_BLOODGLASS = public static final TagKey<net.minecraft.world.damagesource.DamageType> BYPASSES_BLOODGLASS =
TagKey.create(net.minecraft.core.registries.Registries.DAMAGE_TYPE, new ResourceLocation("antarchy", "bypasses_bloodglass")); TagKey.create(net.minecraft.core.registries.Registries.DAMAGE_TYPE, new ResourceLocation("antarchy", "bypasses_bloodglass"));
public static final TagKey<net.minecraft.world.damagesource.DamageType> ANTARCHY_MAGIC_BURST =
TagKey.create(net.minecraft.core.registries.Registries.DAMAGE_TYPE, new ResourceLocation("antarchy", "antarchy_magic_burst"));
private DamageType() { private DamageType() {
} }
@@ -61,28 +66,32 @@ public final class AntarchyTags {
public static final class Entities { public static final class Entities {
public static final TagKey<EntityType<?>> BASILISK_PREY = TagKey.create(Registries.ENTITY_TYPE, id("basilisk_prey")); public static final TagKey<EntityType<?>> BASILISK_PREY = TagKey.create(Registries.ENTITY_TYPE, id("basilisk_prey"));
public static final TagKey<EntityType<?>> SPELL_RESISTANT_BOSS = TagKey.create(Registries.ENTITY_TYPE, id("spell_resistant_boss"));
public static final TagKey<EntityType<?>> DREAM_SAND_LOW_GRAVITY_BLACKLIST = TagKey.create(Registries.ENTITY_TYPE, id("dream_sand_low_gravity_blacklist")); public static final TagKey<EntityType<?>> DREAM_SAND_LOW_GRAVITY_BLACKLIST = TagKey.create(Registries.ENTITY_TYPE, id("dream_sand_low_gravity_blacklist"));
public static final TagKey<EntityType<?>> GRAVITY_GUN_BLACKLIST = TagKey.create(Registries.ENTITY_TYPE, id("gravity_gun_blacklist")); public static final TagKey<EntityType<?>> GRAVITY_GUN_BLACKLIST = TagKey.create(Registries.ENTITY_TYPE, id("gravity_gun_blacklist"));
public static final TagKey<EntityType<?>> INVERTED_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("inverted_immune")); public static final TagKey<EntityType<?>> INVERTED_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("inverted_immune"));
public static final TagKey<EntityType<?>> LUCID_BOLT_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("lucid_bolt_immune")); public static final TagKey<EntityType<?>> LUCID_BOLT_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("lucid_bolt_immune"));
public static final TagKey<EntityType<?>> WIND_VORTEX_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("wind_vortex_immune"));
public static final TagKey<EntityType<?>> DUCT_TAPE_STICK_BLACKLIST = TagKey.create(Registries.ENTITY_TYPE, id("duct_tape_stick_blacklist")); public static final TagKey<EntityType<?>> DUCT_TAPE_STICK_BLACKLIST = TagKey.create(Registries.ENTITY_TYPE, id("duct_tape_stick_blacklist"));
public static final TagKey<EntityType<?>> NIGHTMARE_NO_ATTACK = TagKey.create(Registries.ENTITY_TYPE, id("nightmare_no_attack")); public static final TagKey<EntityType<?>> NIGHTMARE_NO_ATTACK = TagKey.create(Registries.ENTITY_TYPE, id("nightmare_no_attack"));
public static final TagKey<EntityType<?>> SIZE_CHANGING_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("size_changing_immune")); public static final TagKey<EntityType<?>> SIZE_CHANGING_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("size_changing_immune"));
public static final TagKey<EntityType<?>> CRITTER_CAGE_BLACKLIST = TagKey.create(Registries.ENTITY_TYPE, id("critter_cage_blacklist")); public static final TagKey<EntityType<?>> CRITTER_CAGE_BLACKLIST = TagKey.create(Registries.ENTITY_TYPE, id("critter_cage_blacklist"));
public static final TagKey<EntityType<?>> PARALYSIS_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("paralysis_immune")); public static final TagKey<EntityType<?>> PARALYSIS_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("paralysis_immune"));
public static final TagKey<EntityType<?>> UNDERSIDE_CEILING_SPAWNERS = TagKey.create(Registries.ENTITY_TYPE, id("underside_ceiling_spawners"));
public static final TagKey<EntityType<?>> UNDERSIDE_CEILING_SHORT_GAP = TagKey.create(Registries.ENTITY_TYPE, id("underside_ceiling_short_gap"));
public static final TagKey<EntityType<?>> HUSHWEED_TARGETS = TagKey.create(Registries.ENTITY_TYPE, id("hushweed_targets")); public static final TagKey<EntityType<?>> HUSHWEED_TARGETS = TagKey.create(Registries.ENTITY_TYPE, id("hushweed_targets"));
public static final TagKey<EntityType<?>> TRIFFID_PREY = TagKey.create(Registries.ENTITY_TYPE, id("triffid_prey")); public static final TagKey<EntityType<?>> FLYTRAP_PREY = TagKey.create(Registries.ENTITY_TYPE, id("flytrap_prey"));
public static final TagKey<EntityType<?>> STINKY_REPELLED_HOSTILES = TagKey.create(Registries.ENTITY_TYPE, id("stinky_repelled_hostiles")); public static final TagKey<EntityType<?>> STINKY_REPELLED_HOSTILES = TagKey.create(Registries.ENTITY_TYPE, id("stinky_repelled_hostiles"));
public static final TagKey<EntityType<?>> SCORPION_WHIP_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("scorpion_whip_immune")); public static final TagKey<EntityType<?>> SCORPION_WHIP_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("scorpion_whip_immune"));
public static final TagKey<EntityType<?>> SCORPION_WHIP_BLACKLIST = TagKey.create(Registries.ENTITY_TYPE, id("scorpion_whip_blacklist")); public static final TagKey<EntityType<?>> SCORPION_WHIP_BLACKLIST = TagKey.create(Registries.ENTITY_TYPE, id("scorpion_whip_blacklist"));
public static final TagKey<EntityType<?>> LUCID_ANCHOR_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("lucid_anchor_immune"));
public static final TagKey<EntityType<?>> TIGER_EYE_DETECTION_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("tiger_eye_detection_immune")); public static final TagKey<EntityType<?>> TIGER_EYE_DETECTION_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("tiger_eye_detection_immune"));
public static final TagKey<EntityType<?>> LUCID_ANCHOR_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("lucid_anchor_immune"));
public static final TagKey<EntityType<?>> DIMENSIONAL_TEAR_COMMON_SPAWNS = TagKey.create(Registries.ENTITY_TYPE, id("dimensional_tear_common_spawns")); public static final TagKey<EntityType<?>> DIMENSIONAL_TEAR_COMMON_SPAWNS = TagKey.create(Registries.ENTITY_TYPE, id("dimensional_tear_common_spawns"));
public static final TagKey<EntityType<?>> DIMENSIONAL_TEAR_RARE_SPAWNS = TagKey.create(Registries.ENTITY_TYPE, id("dimensional_tear_rare_spawns")); public static final TagKey<EntityType<?>> DIMENSIONAL_TEAR_RARE_SPAWNS = TagKey.create(Registries.ENTITY_TYPE, id("dimensional_tear_rare_spawns"));
public static final TagKey<EntityType<?>> TIME_DILATION_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("time_dilation_immune")); public static final TagKey<EntityType<?>> TIME_DILATION_IMMUNE = TimeDilationTags.TIME_DILATION_IMMUNE;
public static final TagKey<EntityType<?>> QUEEN_DOES_NOT_ATTACK = TagKey.create(Registries.ENTITY_TYPE, id("queen_does_not_attack"));
public static final TagKey<EntityType<?>> COMMANDED_BLACKLIST = TagKey.create(Registries.ENTITY_TYPE, id("commanded_blacklist")); public static final TagKey<EntityType<?>> COMMANDED_BLACKLIST = TagKey.create(Registries.ENTITY_TYPE, id("commanded_blacklist"));
public static final TagKey<EntityType<?>> DILATED_BLACKLIST = TagKey.create(Registries.ENTITY_TYPE, id("dilated_blacklist")); public static final TagKey<EntityType<?>> DILATED_BLACKLIST = TagKey.create(Registries.ENTITY_TYPE, id("dilated_blacklist"));
public static final TagKey<EntityType<?>> WIND_VORTEX_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("wind_vortex_immune"));
private Entities() { private Entities() {
} }
@@ -124,6 +133,7 @@ public final class AntarchyTags {
public static final TagKey<Item> GLIMMER_AUGMENT_ELKA = TagKey.create(Registries.ITEM, id("glimmer_augment_elka")); public static final TagKey<Item> GLIMMER_AUGMENT_ELKA = TagKey.create(Registries.ITEM, id("glimmer_augment_elka"));
public static final TagKey<Item> HFCS_CANNOT_AMERICANIZE = TagKey.create(Registries.ITEM, id("hfcs_cannot_americanize")); public static final TagKey<Item> HFCS_CANNOT_AMERICANIZE = TagKey.create(Registries.ITEM, id("hfcs_cannot_americanize"));
public static final TagKey<Item> TIGER_EYE_ARMOR = TagKey.create(Registries.ITEM, id("tigers_eye_armor")); public static final TagKey<Item> TIGER_EYE_ARMOR = TagKey.create(Registries.ITEM, id("tigers_eye_armor"));
public static final TagKey<Item> BIG_BERTHA_INGREDIENT = TagKey.create(Registries.ITEM, id("big_bertha_ingredient"));
private Items() { private Items() {
} }
@@ -148,4 +158,11 @@ public final class AntarchyTags {
private Biomes() { private Biomes() {
} }
} }
public static final class DimensionTypes {
public static final TagKey<DimensionType> NO_MANTIS_CLIMB = TagKey.create(Registries.DIMENSION_TYPE, id("no_mantis_climb"));
private DimensionTypes() {
}
}
} }
@@ -0,0 +1,132 @@
package com.craisinlord.antarchy.content.advancement;
import com.craisinlord.antarchy.mixins.CriteriaTriggersAccessor;
import com.google.gson.JsonObject;
import java.util.Optional;
import java.util.function.BiConsumer;
import net.minecraft.advancements.CriterionTrigger;
import net.minecraft.advancements.critereon.AbstractCriterionTriggerInstance;
import net.minecraft.advancements.critereon.ContextAwarePredicate;
import net.minecraft.advancements.critereon.DeserializationContext;
import net.minecraft.advancements.critereon.SerializationContext;
import net.minecraft.advancements.critereon.SimpleCriterionTrigger;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.GsonHelper;
public final class AntarchyAdvancementTriggers {
private static final CrossedGravityThroat CROSSING = new CrossedGravityThroat(new ResourceLocation("antarchy", "crossed_gravity_throat"));
private static final HordePhaseChanged HORDE_PHASE = new HordePhaseChanged(new ResourceLocation("antarchy", "horde_phase_changed"));
private static final TamedGlimmer TAMED_GLIMMER = new TamedGlimmer(new ResourceLocation("antarchy", "tamed_glimmer"));
private AntarchyAdvancementTriggers() {
}
public static void register() {
register((id, trigger) -> CriteriaTriggersAccessor.antarchy$register(trigger));
}
public static void register(BiConsumer<ResourceLocation, CriterionTrigger<?>> registrar) {
registrar.accept(CROSSING.getId(), CROSSING);
registrar.accept(HORDE_PHASE.getId(), HORDE_PHASE);
registrar.accept(TAMED_GLIMMER.getId(), TAMED_GLIMMER);
}
public static void crossedGravityThroat(ServerPlayer player, String direction) {
CROSSING.fire(player, direction);
}
public static void hordePhaseChanged(ServerPlayer player, String phase) {
HORDE_PHASE.fire(player, phase);
}
public static void tamedGlimmer(ServerPlayer player, String variant) {
TAMED_GLIMMER.fire(player, variant);
}
private static Optional<String> optionalString(JsonObject json, String key) {
return json.has(key) ? Optional.of(GsonHelper.getAsString(json, key)) : Optional.empty();
}
private static final class EventInstance extends AbstractCriterionTriggerInstance {
private final Optional<String> direction;
private final Optional<String> phase;
private final Optional<String> variant;
private EventInstance(ResourceLocation id, ContextAwarePredicate player, Optional<String> direction, Optional<String> phase, Optional<String> variant) {
super(id, player);
this.direction = direction;
this.phase = phase;
this.variant = variant;
}
Optional<String> direction() {
return this.direction;
}
Optional<String> phase() {
return this.phase;
}
Optional<String> variant() {
return this.variant;
}
@Override
public JsonObject serializeToJson(SerializationContext context) {
JsonObject json = super.serializeToJson(context);
this.direction.ifPresent(value -> json.addProperty("direction", value));
this.phase.ifPresent(value -> json.addProperty("phase", value));
this.variant.ifPresent(value -> json.addProperty("variant", value));
return json;
}
}
private abstract static class EventTrigger extends SimpleCriterionTrigger<EventInstance> {
private final ResourceLocation id;
EventTrigger(ResourceLocation id) {
this.id = id;
}
@Override
public ResourceLocation getId() {
return this.id;
}
@Override
protected EventInstance createInstance(JsonObject json, ContextAwarePredicate player, DeserializationContext context) {
return new EventInstance(this.id, player, optionalString(json, "direction"), optionalString(json, "phase"), optionalString(json, "variant"));
}
}
private static final class CrossedGravityThroat extends EventTrigger {
CrossedGravityThroat(ResourceLocation id) {
super(id);
}
private void fire(ServerPlayer player, String direction) {
trigger(player, instance -> instance.direction().map(direction::equals).orElse(true));
}
}
private static final class HordePhaseChanged extends EventTrigger {
HordePhaseChanged(ResourceLocation id) {
super(id);
}
private void fire(ServerPlayer player, String phase) {
trigger(player, instance -> instance.phase().map(phase::equals).orElse(true));
}
}
private static final class TamedGlimmer extends EventTrigger {
TamedGlimmer(ResourceLocation id) {
super(id);
}
private void fire(ServerPlayer player, String variant) {
trigger(player, instance -> instance.variant().map(variant::equals).orElse(true));
}
}
}
@@ -85,7 +85,7 @@ public final class AntDimensionPortalBlock extends Block {
if (level.isClientSide() || !entity.isAlive() || !entity.canChangeDimensions() || entity.isOnPortalCooldown()) { if (level.isClientSide() || !entity.isAlive() || !entity.canChangeDimensions() || entity.isOnPortalCooldown()) {
return; return;
} }
if (!(level instanceof ServerLevel serverLevel)) { if (!(level instanceof ServerLevel)) {
return; return;
} }
@@ -0,0 +1,52 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.block.entity.AntNestBlockEntity;
import com.craisinlord.antarchy.content.entity.ant.BaseAntEntity;
import java.util.List;
import java.util.function.Supplier;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraft.world.level.BlockGetter;
public final class AntTrapBlock extends AntNestBlock {
private static final VoxelShape SHAPE = Block.box(3.0D, 0.0D, 3.0D, 13.0D, 5.0D, 13.0D);
public AntTrapBlock(Supplier<List<EntityType<? extends BaseAntEntity>>> antTypesSupplier,
Supplier<? extends BlockEntityType<AntNestBlockEntity>> blockEntityTypeSupplier,
BlockBehaviour.Properties properties) {
super(antTypesSupplier, blockEntityTypeSupplier, 10, false, false, properties);
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return SHAPE;
}
@Override
public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
if (!state.is(newState.getBlock()) && level instanceof ServerLevel serverLevel
&& level.getBlockEntity(pos) instanceof AntNestBlockEntity trap) {
trap.releaseAll(serverLevel);
}
super.onRemove(state, level, pos, newState, movedByPiston);
}
@Override
public void playerDestroy(Level level, Player player, BlockPos pos, BlockState state, BlockEntity blockEntity, ItemStack stack) {
if (blockEntity instanceof AntNestBlockEntity trap && level instanceof ServerLevel serverLevel) {
trap.releaseAll(serverLevel);
}
super.playerDestroy(level, player, pos, state, blockEntity, stack);
}
}
@@ -12,6 +12,8 @@ import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
public class AntigravelBlock extends Block { public class AntigravelBlock extends Block {
private static final int SETTLE_DELAY = 2;
public AntigravelBlock(BlockBehaviour.Properties properties) { public AntigravelBlock(BlockBehaviour.Properties properties) {
super(properties); super(properties);
} }
@@ -20,13 +22,13 @@ public class AntigravelBlock extends Block {
public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) { public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) {
super.onPlace(state, level, pos, oldState, movedByPiston); super.onPlace(state, level, pos, oldState, movedByPiston);
if (!level.isClientSide) { if (!level.isClientSide) {
level.scheduleTick(pos, this, 2); level.scheduleTick(pos, this, SETTLE_DELAY);
} }
} }
@Override @Override
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) { public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) {
level.scheduleTick(pos, this, 2); level.scheduleTick(pos, this, SETTLE_DELAY);
return super.updateShape(state, direction, neighborState, level, pos, neighborPos); return super.updateShape(state, direction, neighborState, level, pos, neighborPos);
} }
@@ -38,8 +40,9 @@ public class AntigravelBlock extends Block {
BlockPos abovePos = pos.above(); BlockPos abovePos = pos.above();
BlockState above = level.getBlockState(abovePos); BlockState above = level.getBlockState(abovePos);
boolean passable = above.isAir() || above.getCollisionShape(level, abovePos).isEmpty(); boolean passable = above.isAir() || above.getCollisionShape(level, abovePos).isEmpty();
if (passable) { if (!passable) {
UpwardFallingBlockEntity.fallUp(level, pos, state); return;
} }
UpwardFallingBlockEntity.fallUp(level, pos, state, false);
} }
} }
@@ -1,7 +1,7 @@
package com.craisinlord.antarchy.content.block; package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.entity.UpwardFallingBlockEntity; import com.craisinlord.antarchy.content.entity.UpwardFallingBlockEntity;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi; import com.craisinlord.anthology.gravity.GravityApi;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
@@ -64,7 +64,7 @@ public class AntimetalScaffoldingBlock extends ScaffoldingBlock {
public BlockState getStateForPlacement(BlockPlaceContext context) { public BlockState getStateForPlacement(BlockPlaceContext context) {
BlockPos pos = context.getClickedPos(); BlockPos pos = context.getClickedPos();
Level level = context.getLevel(); Level level = context.getLevel();
boolean inverted = context.getPlayer() != null && AntarchyGravityApi.isGravityInverted(context.getPlayer()); boolean inverted = context.getPlayer() != null && GravityApi.isGravityInverted(context.getPlayer());
int distance = getDistance(level, pos, inverted); int distance = getDistance(level, pos, inverted);
if (inverted && distance >= 7) { if (inverted && distance >= 7) {
return null; return null;
@@ -31,7 +31,7 @@ import net.minecraft.util.RandomSource;
import net.minecraft.world.ticks.TickPriority; import net.minecraft.world.ticks.TickPriority;
import org.joml.Vector3f; import org.joml.Vector3f;
public class BluestoneComparatorBlock extends ComparatorBlock { public class BluestoneComparatorBlock extends ComparatorBlock implements BluestoneSignalSource {
private static final VoxelShape SHAPE = Block.box(0.0D, 14.0D, 0.0D, 16.0D, 16.0D, 16.0D); private static final VoxelShape SHAPE = Block.box(0.0D, 14.0D, 0.0D, 16.0D, 16.0D, 16.0D);
private static final DustParticleOptions BLUESTONE_PARTICLE = new DustParticleOptions(new Vector3f(0.18F, 0.54F, 1.0F), 1.0F); private static final DustParticleOptions BLUESTONE_PARTICLE = new DustParticleOptions(new Vector3f(0.18F, 0.54F, 1.0F), 1.0F);
private final Supplier<? extends BlockEntityType<BluestoneComparatorBlockEntity>> blockEntityTypeSupplier; private final Supplier<? extends BlockEntityType<BluestoneComparatorBlockEntity>> blockEntityTypeSupplier;
@@ -127,6 +127,11 @@ public class BluestoneComparatorBlock extends ComparatorBlock {
return true; return true;
} }
@Override
public int getBluestoneSignal(LevelReader level, BlockPos pos, BlockState state, Direction direction) {
return level == null ? 0 : state.getSignal(level, pos, direction);
}
@Override @Override
public void checkTickOnNeighbor(Level level, BlockPos pos, BlockState state) { public void checkTickOnNeighbor(Level level, BlockPos pos, BlockState state) {
if (level.getBlockTicks().willTickThisTick(pos, this)) { if (level.getBlockTicks().willTickThisTick(pos, this)) {
@@ -19,7 +19,7 @@ import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraft.util.RandomSource; import net.minecraft.util.RandomSource;
import org.joml.Vector3f; import org.joml.Vector3f;
public class BluestoneRepeaterBlock extends RepeaterBlock { public class BluestoneRepeaterBlock extends RepeaterBlock implements BluestoneSignalSource {
private static final VoxelShape SHAPE = Block.box(0.0D, 14.0D, 0.0D, 16.0D, 16.0D, 16.0D); private static final VoxelShape SHAPE = Block.box(0.0D, 14.0D, 0.0D, 16.0D, 16.0D, 16.0D);
private static final DustParticleOptions BLUESTONE_PARTICLE = new DustParticleOptions(new Vector3f(0.18F, 0.54F, 1.0F), 1.0F); private static final DustParticleOptions BLUESTONE_PARTICLE = new DustParticleOptions(new Vector3f(0.18F, 0.54F, 1.0F), 1.0F);
@@ -95,6 +95,11 @@ public class BluestoneRepeaterBlock extends RepeaterBlock {
return true; return true;
} }
@Override
public int getBluestoneSignal(LevelReader level, BlockPos pos, BlockState state, Direction direction) {
return level == null ? 0 : state.getSignal(level, pos, direction);
}
@Override @Override
public void animateTick(BlockState state, net.minecraft.world.level.Level level, BlockPos pos, RandomSource random) { public void animateTick(BlockState state, net.minecraft.world.level.Level level, BlockPos pos, RandomSource random) {
if (!state.getValue(POWERED)) { if (!state.getValue(POWERED)) {
@@ -1,11 +1,11 @@
package com.craisinlord.antarchy.content.block; package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.entity.royal.KingEntity;
import java.util.Optional; import java.util.Optional;
import java.util.function.Supplier; import java.util.function.Supplier;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
@@ -40,7 +40,8 @@ public final class CloudBlock extends Block implements BucketPickup {
public VoxelShape getCollisionShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) { public VoxelShape getCollisionShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
if (context instanceof EntityCollisionContext ecc) { if (context instanceof EntityCollisionContext ecc) {
Entity entity = ecc.getEntity(); Entity entity = ecc.getEntity();
if (entity instanceof net.minecraft.world.entity.LivingEntity le && le.isShiftKeyDown()) { if (entity instanceof KingEntity
|| entity instanceof net.minecraft.world.entity.LivingEntity le && le.isShiftKeyDown()) {
return EMPTY; return EMPTY;
} }
} }
@@ -73,6 +74,9 @@ public final class CloudBlock extends Block implements BucketPickup {
} }
public void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) { public void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) {
if (entity instanceof KingEntity) {
return;
}
Vec3 motion = entity.getDeltaMovement(); Vec3 motion = entity.getDeltaMovement();
double slowedY = motion.y < 0.0D ? Math.max(motion.y * 0.4D, -0.08D) : motion.y; double slowedY = motion.y < 0.0D ? Math.max(motion.y * 0.4D, -0.08D) : motion.y;
entity.setDeltaMovement(motion.x * 0.92D, slowedY, motion.z * 0.92D); entity.setDeltaMovement(motion.x * 0.92D, slowedY, motion.z * 0.92D);
@@ -0,0 +1,244 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.entity.CrawlingBlightEntity;
import com.craisinlord.antarchy.content.block.AmberMossBlock;
import com.craisinlord.antarchy.content.block.SkulkingFrightEggBlock;
import com.craisinlord.antarchy.content.horde.CavarynHordeManager;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.tags.BlockTags;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.ambient.Bat;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.IntegerProperty;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class CrawlingBlightEggBlock extends Block {
public static final IntegerProperty HATCH = BlockStateProperties.HATCH;
public static final IntegerProperty EGGS = BlockStateProperties.EGGS;
private static final float PANIC_HATCH_CHANCE = 0.25F;
private static final double HORDE_ACCELERATION_RADIUS = 5.0D;
private static final int MAX_HATCH = 2;
private static final int MAX_EGGS = 4;
private static final VoxelShape SINGLE_SHAPE = Block.box(3.0D, 0.0D, 3.0D, 13.0D, 7.0D, 13.0D);
private static final VoxelShape MULTI_SHAPE = Block.box(1.0D, 0.0D, 1.0D, 15.0D, 7.0D, 15.0D);
public CrawlingBlightEggBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any().setValue(HATCH, 0).setValue(EGGS, 1));
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return state.getValue(EGGS) > 1 ? MULTI_SHAPE : SINGLE_SHAPE;
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return level.getBlockState(pos.below()).isFaceSturdy(level, pos.below(), Direction.UP);
}
@Override
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) {
return state.canSurvive(level, pos) ? super.updateShape(state, direction, neighborState, level, pos, neighborPos) : Blocks.AIR.defaultBlockState();
}
@Override
public boolean canBeReplaced(BlockState state, BlockPlaceContext context) {
return !context.isSecondaryUseActive()
&& context.getItemInHand().is(this.asItem())
&& state.getValue(EGGS) < MAX_EGGS;
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
BlockState existingState = context.getLevel().getBlockState(context.getClickedPos());
if (existingState.is(this)) {
return existingState.setValue(EGGS, Math.min(MAX_EGGS, existingState.getValue(EGGS) + 1));
}
return this.defaultBlockState();
}
@Override
public boolean isRandomlyTicking(BlockState state) {
return true;
}
@Override
public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (!this.shouldUpdateHatchLevel(level, pos)) {
return;
}
int hatch = state.getValue(HATCH);
if (hatch < MAX_HATCH) {
level.setBlock(pos, state.setValue(HATCH, hatch + 1), 2);
level.playSound(null, pos, SoundEvents.TURTLE_EGG_CRACK, SoundSource.BLOCKS, 0.7F, 0.95F + random.nextFloat() * 0.1F);
return;
}
this.hatchEggs(level, pos, state, random, state.getValue(EGGS));
}
@Override
public void stepOn(Level level, BlockPos pos, BlockState state, Entity entity) {
if (entity instanceof Player && !entity.isSteppingCarefully() && this.destroyEgg(level, state, pos, entity, 100)) {
if (level instanceof ServerLevel serverLevel) {
panicHatchNearby(serverLevel, pos);
}
}
super.stepOn(level, pos, state, entity);
}
@Override
public void fallOn(Level level, BlockState state, BlockPos pos, Entity entity, float fallDistance) {
this.destroyEgg(level, state, pos, entity, 3);
super.fallOn(level, state, pos, entity, fallDistance);
}
@Override
public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean isMoving) {
if (hasHatchSupport(level, pos) && !level.isClientSide) {
level.levelEvent(2012, pos, 15);
}
}
@Override
public void playerDestroy(Level level, Player player, BlockPos pos, BlockState state, BlockEntity blockEntity, net.minecraft.world.item.ItemStack stack) {
super.playerDestroy(level, player, pos, state, blockEntity, stack);
this.decreaseEggs(level, pos, state);
}
private static void panicHatchNearby(ServerLevel level, BlockPos origin) {
int radius = 6;
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
for (int dx = -radius; dx <= radius; dx++) {
for (int dy = -radius; dy <= radius; dy++) {
for (int dz = -radius; dz <= radius; dz++) {
if (dx == 0 && dy == 0 && dz == 0) continue;
mutable.set(origin.getX() + dx, origin.getY() + dy, origin.getZ() + dz);
BlockState nearby = level.getBlockState(mutable);
BlockPos immutable = mutable.immutable();
if (nearby.getBlock() instanceof CrawlingBlightEggBlock b) {
b.hatchPanickedEggs(level, immutable, nearby, level.random);
} else if (nearby.getBlock() instanceof SkulkingFrightEggBlock b) {
b.hatchPanickedEggs(level, immutable, nearby, level.random);
}
}
}
}
}
@Override
public void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(HATCH, EGGS);
}
public static boolean hasHatchSupport(BlockGetter level, BlockPos pos) {
return isSupportedGround(level, pos.below());
}
public static boolean isSupportedGround(BlockGetter level, BlockPos pos) {
return level.getBlockState(pos).is(BlockTags.SAND) || level.getBlockState(pos).blocksMotion();
}
private boolean destroyEgg(Level level, BlockState state, BlockPos pos, Entity entity, int chance) {
if (level.isClientSide || !this.canDestroyEgg(level, entity) || level.random.nextInt(chance) != 0) {
return false;
}
level.playSound(null, pos, SoundEvents.TURTLE_EGG_BREAK, SoundSource.BLOCKS, 0.7F, 0.9F + level.random.nextFloat() * 0.2F);
this.decreaseEggs(level, pos, state);
return true;
}
void hatchPanickedEggs(ServerLevel level, BlockPos pos, BlockState state, RandomSource random) {
int hatchedEggs = rollPanickedEggs(state.getValue(EGGS), random);
if (hatchedEggs <= 0) {
return;
}
this.hatchEggs(level, pos, state, random, hatchedEggs);
}
void hatchEggs(ServerLevel level, BlockPos pos, BlockState state, RandomSource random, int eggsToHatch) {
if (eggsToHatch >= state.getValue(EGGS)) {
level.removeBlock(pos, false);
} else {
level.setBlock(pos, state.setValue(EGGS, state.getValue(EGGS) - eggsToHatch), 2);
}
level.playSound(null, pos, SoundEvents.TURTLE_EGG_HATCH, SoundSource.BLOCKS, 0.75F, 0.95F + random.nextFloat() * 0.1F);
for (int i = 0; i < eggsToHatch; i++) {
CrawlingBlightEntity entity = AntarchyObjects.CRAWLING_BLIGHT.get().create(level);
if (entity == null) {
continue;
}
double spawnX = pos.getX() + 0.25D + random.nextDouble() * 0.5D;
double spawnZ = pos.getZ() + 0.25D + random.nextDouble() * 0.5D;
entity.moveTo(spawnX, pos.getY() + 0.1D, spawnZ, random.nextFloat() * 360.0F, 0.0F);
level.addFreshEntity(entity);
}
}
public void hatchWithNucleus(ServerLevel level, BlockPos pos, BlockState state) {
this.hatchEggs(level, pos, state, level.random, state.getValue(EGGS));
}
private static int rollPanickedEggs(int eggs, RandomSource random) {
int hatchedEggs = 0;
for (int i = 0; i < eggs; i++) {
if (random.nextFloat() < PANIC_HATCH_CHANCE) {
hatchedEggs++;
}
}
return hatchedEggs;
}
private void decreaseEggs(Level level, BlockPos pos, BlockState state) {
int eggs = state.getValue(EGGS);
if (eggs <= 1) {
level.destroyBlock(pos, false);
return;
}
level.setBlock(pos, state.setValue(EGGS, eggs - 1), 2);
}
private boolean shouldUpdateHatchLevel(Level level, BlockPos pos) {
if (level instanceof ServerLevel serverLevel
&& CavarynHordeManager.shouldAccelerateNearbyEggHatching(serverLevel, pos, HORDE_ACCELERATION_RADIUS, level.random)) {
return true;
}
boolean onAmberMoss = level.getBlockState(pos.below()).getBlock() instanceof AmberMossBlock;
return level.random.nextInt(onAmberMoss ? 150 : 500) == 0;
}
private boolean canDestroyEgg(Level level, Entity entity) {
if (entity instanceof CrawlingBlightEntity || entity instanceof Bat) {
return false;
}
if (entity instanceof net.minecraft.world.entity.LivingEntity) {
return entity instanceof Player || level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING);
}
return false;
}
}
@@ -1,244 +0,0 @@
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.craisinlord.antarchy.content.block.LurkingTerrorEggBlock;
import com.craisinlord.antarchy.content.horde.CavarynHordeManager;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.tags.BlockTags;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.ambient.Bat;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.IntegerProperty;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class CreepingHorrorEggBlock extends Block {
public static final IntegerProperty HATCH = BlockStateProperties.HATCH;
public static final IntegerProperty EGGS = BlockStateProperties.EGGS;
private static final float PANIC_HATCH_CHANCE = 0.25F;
private static final double HORDE_ACCELERATION_RADIUS = 5.0D;
private static final int MAX_HATCH = 2;
private static final int MAX_EGGS = 4;
private static final VoxelShape SINGLE_SHAPE = Block.box(3.0D, 0.0D, 3.0D, 13.0D, 7.0D, 13.0D);
private static final VoxelShape MULTI_SHAPE = Block.box(1.0D, 0.0D, 1.0D, 15.0D, 7.0D, 15.0D);
public CreepingHorrorEggBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any().setValue(HATCH, 0).setValue(EGGS, 1));
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return state.getValue(EGGS) > 1 ? MULTI_SHAPE : SINGLE_SHAPE;
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return level.getBlockState(pos.below()).isFaceSturdy(level, pos.below(), Direction.UP);
}
@Override
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) {
return state.canSurvive(level, pos) ? super.updateShape(state, direction, neighborState, level, pos, neighborPos) : Blocks.AIR.defaultBlockState();
}
@Override
public boolean canBeReplaced(BlockState state, BlockPlaceContext context) {
return !context.isSecondaryUseActive()
&& context.getItemInHand().is(this.asItem())
&& state.getValue(EGGS) < MAX_EGGS;
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
BlockState existingState = context.getLevel().getBlockState(context.getClickedPos());
if (existingState.is(this)) {
return existingState.setValue(EGGS, Math.min(MAX_EGGS, existingState.getValue(EGGS) + 1));
}
return this.defaultBlockState();
}
@Override
public boolean isRandomlyTicking(BlockState state) {
return true;
}
@Override
public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (!this.shouldUpdateHatchLevel(level, pos)) {
return;
}
int hatch = state.getValue(HATCH);
if (hatch < MAX_HATCH) {
level.setBlock(pos, state.setValue(HATCH, hatch + 1), 2);
level.playSound(null, pos, SoundEvents.TURTLE_EGG_CRACK, SoundSource.BLOCKS, 0.7F, 0.95F + random.nextFloat() * 0.1F);
return;
}
this.hatchEggs(level, pos, state, random, state.getValue(EGGS));
}
@Override
public void stepOn(Level level, BlockPos pos, BlockState state, Entity entity) {
if (entity instanceof Player && !entity.isSteppingCarefully() && this.destroyEgg(level, state, pos, entity, 100)) {
if (level instanceof ServerLevel serverLevel) {
panicHatchNearby(serverLevel, pos);
}
}
super.stepOn(level, pos, state, entity);
}
@Override
public void fallOn(Level level, BlockState state, BlockPos pos, Entity entity, float fallDistance) {
this.destroyEgg(level, state, pos, entity, 3);
super.fallOn(level, state, pos, entity, fallDistance);
}
@Override
public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean isMoving) {
if (hasHatchSupport(level, pos) && !level.isClientSide) {
level.levelEvent(2012, pos, 15);
}
}
@Override
public void playerDestroy(Level level, Player player, BlockPos pos, BlockState state, BlockEntity blockEntity, net.minecraft.world.item.ItemStack stack) {
super.playerDestroy(level, player, pos, state, blockEntity, stack);
this.decreaseEggs(level, pos, state);
}
private static void panicHatchNearby(ServerLevel level, BlockPos origin) {
int radius = 6;
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
for (int dx = -radius; dx <= radius; dx++) {
for (int dy = -radius; dy <= radius; dy++) {
for (int dz = -radius; dz <= radius; dz++) {
if (dx == 0 && dy == 0 && dz == 0) continue;
mutable.set(origin.getX() + dx, origin.getY() + dy, origin.getZ() + dz);
BlockState nearby = level.getBlockState(mutable);
BlockPos immutable = mutable.immutable();
if (nearby.getBlock() instanceof CreepingHorrorEggBlock b) {
b.hatchPanickedEggs(level, immutable, nearby, level.random);
} else if (nearby.getBlock() instanceof LurkingTerrorEggBlock b) {
b.hatchPanickedEggs(level, immutable, nearby, level.random);
}
}
}
}
}
@Override
public void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(HATCH, EGGS);
}
public static boolean hasHatchSupport(BlockGetter level, BlockPos pos) {
return isSupportedGround(level, pos.below());
}
public static boolean isSupportedGround(BlockGetter level, BlockPos pos) {
return level.getBlockState(pos).is(BlockTags.SAND) || level.getBlockState(pos).blocksMotion();
}
private boolean destroyEgg(Level level, BlockState state, BlockPos pos, Entity entity, int chance) {
if (level.isClientSide || !this.canDestroyEgg(level, entity) || level.random.nextInt(chance) != 0) {
return false;
}
level.playSound(null, pos, SoundEvents.TURTLE_EGG_BREAK, SoundSource.BLOCKS, 0.7F, 0.9F + level.random.nextFloat() * 0.2F);
this.decreaseEggs(level, pos, state);
return true;
}
void hatchPanickedEggs(ServerLevel level, BlockPos pos, BlockState state, RandomSource random) {
int hatchedEggs = rollPanickedEggs(state.getValue(EGGS), random);
if (hatchedEggs <= 0) {
return;
}
this.hatchEggs(level, pos, state, random, hatchedEggs);
}
void hatchEggs(ServerLevel level, BlockPos pos, BlockState state, RandomSource random, int eggsToHatch) {
if (eggsToHatch >= state.getValue(EGGS)) {
level.removeBlock(pos, false);
} else {
level.setBlock(pos, state.setValue(EGGS, state.getValue(EGGS) - eggsToHatch), 2);
}
level.playSound(null, pos, SoundEvents.TURTLE_EGG_HATCH, SoundSource.BLOCKS, 0.75F, 0.95F + random.nextFloat() * 0.1F);
for (int i = 0; i < eggsToHatch; i++) {
CreepingHorrorEntity entity = AntarchyObjects.CREEPING_HORROR.get().create(level);
if (entity == null) {
continue;
}
double spawnX = pos.getX() + 0.25D + random.nextDouble() * 0.5D;
double spawnZ = pos.getZ() + 0.25D + random.nextDouble() * 0.5D;
entity.moveTo(spawnX, pos.getY() + 0.1D, spawnZ, random.nextFloat() * 360.0F, 0.0F);
level.addFreshEntity(entity);
}
}
public void hatchWithNucleus(ServerLevel level, BlockPos pos, BlockState state) {
this.hatchEggs(level, pos, state, level.random, state.getValue(EGGS));
}
private static int rollPanickedEggs(int eggs, RandomSource random) {
int hatchedEggs = 0;
for (int i = 0; i < eggs; i++) {
if (random.nextFloat() < PANIC_HATCH_CHANCE) {
hatchedEggs++;
}
}
return hatchedEggs;
}
private void decreaseEggs(Level level, BlockPos pos, BlockState state) {
int eggs = state.getValue(EGGS);
if (eggs <= 1) {
level.destroyBlock(pos, false);
return;
}
level.setBlock(pos, state.setValue(EGGS, eggs - 1), 2);
}
private boolean shouldUpdateHatchLevel(Level level, BlockPos pos) {
if (level instanceof ServerLevel serverLevel
&& CavarynHordeManager.shouldAccelerateNearbyEggHatching(serverLevel, pos, HORDE_ACCELERATION_RADIUS, level.random)) {
return true;
}
boolean onAmberMoss = level.getBlockState(pos.below()).getBlock() instanceof AmberMossBlock;
return level.random.nextInt(onAmberMoss ? 150 : 500) == 0;
}
private boolean canDestroyEgg(Level level, Entity entity) {
if (entity instanceof CreepingHorrorEntity || entity instanceof Bat) {
return false;
}
if (entity instanceof net.minecraft.world.entity.LivingEntity) {
return entity instanceof Player || level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING);
}
return false;
}
}
@@ -4,6 +4,8 @@ import com.craisinlord.antarchy.content.AntarchyTags;
import com.craisinlord.antarchy.mixins.AccessorFireBlock; import com.craisinlord.antarchy.mixins.AccessorFireBlock;
import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntMap;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.FireBlock; import net.minecraft.world.level.block.FireBlock;
import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockBehaviour;
@@ -17,6 +19,21 @@ public class DreamFireBlock extends FireBlock {
this.copyVanillaFlammability(); this.copyVanillaFlammability();
} }
@Override
public void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (level.getBlockState(pos.below()).is(AntarchyTags.Blocks.DREAM_FIRE_BASE_BLOCKS)) {
if (!this.canSurvive(state, level, pos)) {
level.removeBlock(pos, false);
return;
}
level.scheduleTick(pos, this, 30 + random.nextInt(10));
return;
}
super.tick(state, level, pos, random);
}
@Override @Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) { public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return level.getBlockState(pos.below()).is(AntarchyTags.Blocks.DREAM_FIRE_BASE_BLOCKS) return level.getBlockState(pos.below()).is(AntarchyTags.Blocks.DREAM_FIRE_BASE_BLOCKS)
@@ -1,15 +1,18 @@
package com.craisinlord.antarchy.content.block; package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.entity.UpwardFallingBlockEntity;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.FallingBlock; import net.minecraft.world.level.block.FallingBlock;
import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockBehaviour;
public class DreamSandBlock extends FallingBlock { public class DreamSandBlock extends FallingBlock {
@SuppressWarnings("rawtypes")
public DreamSandBlock(BlockBehaviour.Properties properties) { public DreamSandBlock(BlockBehaviour.Properties properties) {
super(properties); super(properties);
} }
@@ -18,4 +21,30 @@ public class DreamSandBlock extends FallingBlock {
public void fallOn(Level level, BlockState state, BlockPos pos, Entity entity, float fallDistance) { public void fallOn(Level level, BlockState state, BlockPos pos, Entity entity, float fallDistance) {
entity.causeFallDamage(fallDistance, 0.0F, level.damageSources().fall()); entity.causeFallDamage(fallDistance, 0.0F, level.damageSources().fall());
} }
@Override
public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) {
if (!level.isClientSide) {
level.scheduleTick(pos, this, 2);
}
}
@Override
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) {
level.scheduleTick(pos, this, 2);
return state;
}
@Override
public void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (!level.getBlockState(pos).is(this)) {
return;
}
BlockPos abovePos = pos.above();
BlockState above = level.getBlockState(abovePos);
boolean passable = above.isAir() || above.getCollisionShape(level, abovePos).isEmpty();
if (passable) {
UpwardFallingBlockEntity.fallUp(level, pos, state, false);
}
}
} }
@@ -5,23 +5,14 @@ import com.craisinlord.antarchy.content.advancement.AntarchyAdvancements;
import com.craisinlord.antarchy.content.AntarchyObjects; import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.AntarchySoundEvents; import com.craisinlord.antarchy.content.AntarchySoundEvents;
import com.craisinlord.antarchy.content.AntarchyTags; import com.craisinlord.antarchy.content.AntarchyTags;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource; import net.minecraft.sounds.SoundSource;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.DiggerItem;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.ShearsItem;
import net.minecraft.world.item.SwordItem;
import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
@@ -37,9 +28,7 @@ import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.DirectionProperty; import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.level.block.state.properties.EnumProperty; import net.minecraft.world.level.block.state.properties.EnumProperty;
import net.minecraft.world.level.block.state.properties.IntegerProperty; import net.minecraft.world.level.block.state.properties.IntegerProperty;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraft.world.phys.shapes.VoxelShape;
@@ -52,24 +41,6 @@ public class DuctTapeBlock extends Block {
public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
private static final int TAPE_HEIGHT = 2; private static final int TAPE_HEIGHT = 2;
private static final long STICK_SOUND_COOLDOWN_TICKS = 10L;
private static final long TAPE_DECAY_INTERVAL_TICKS = 30L;
private static final double FLOOR_TRIGGER_HEIGHT = 0.30D;
private static final double WALL_TRIGGER_DEPTH = 0.25D;
private static final double TRIGGER_PAD = 0.12D;
private static final double WALL_Y_PAD = 0.12D;
private static final double WALL_SIDE_PAD = 0.08D;
private static final double WALL_INNER_INSET = 0.03D;
private static final double TRIGGER_INFLATE_DEFAULT = 0.15D;
private static final int SEARCH_INTERVAL_TICKS = 4;
private static final double SEARCH_MOTION_THRESHOLD_SQR = 1.0E-8D;
private static final double SEARCH_PAD_XZ = Math.max(WALL_TRIGGER_DEPTH, TRIGGER_PAD);
private static final double SEARCH_PAD_Y = FLOOR_TRIGGER_HEIGHT;
private static final Map<UUID, Long> STICK_SOUND_TIMES = new HashMap<>();
private static final Map<UUID, String> STICK_CONTACT_KEYS = new HashMap<>();
private static final Map<String, Long> TAPE_DECAY_TIMES = new HashMap<>();
private static final Map<UUID, StuckContact> STUCK_ENTITIES = new HashMap<>();
public DuctTapeBlock(BlockBehaviour.Properties properties) { public DuctTapeBlock(BlockBehaviour.Properties properties) {
super(properties); super(properties);
@@ -131,14 +102,6 @@ public class DuctTapeBlock extends Block {
return state.canSurvive(context.getLevel(), context.getClickedPos()) ? state : null; return state.canSurvive(context.getLevel(), context.getClickedPos()) ? state : null;
} }
@Override
public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
if (!state.is(newState.getBlock())) {
releaseEntitiesForTape(level, pos);
}
super.onRemove(state, level, pos, newState, movedByPiston);
}
@Override @Override
public InteractionResult use( public InteractionResult use(
BlockState state, BlockState state,
@@ -153,14 +116,6 @@ public class DuctTapeBlock extends Block {
return InteractionResult.PASS; return InteractionResult.PASS;
} }
if (isReleaseTool(stack) && (isStuckToTape(player) || isTouchingTape(level, player))) {
if (!level.isClientSide) {
consumeTapeUse(level, pos, state);
level.playSound(null, pos, SoundEvents.WOOL_BREAK, SoundSource.BLOCKS, 0.8F, 0.9F + level.random.nextFloat() * 0.2F);
}
return InteractionResult.sidedSuccess(level.isClientSide);
}
if (!stack.isDamageableItem() || !stack.isDamaged() || stack.is(AntarchyTags.Items.DUCT_TAPE_BLACKLIST)) { if (!stack.isDamageableItem() || !stack.isDamaged() || stack.is(AntarchyTags.Items.DUCT_TAPE_BLACKLIST)) {
return InteractionResult.PASS; return InteractionResult.PASS;
} }
@@ -187,24 +142,6 @@ public class DuctTapeBlock extends Block {
return InteractionResult.sidedSuccess(level.isClientSide); return InteractionResult.sidedSuccess(level.isClientSide);
} }
@Override
public void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) {
if (level.isClientSide || entity.isSpectator() || !touchesTape(level, entity, pos, state)) {
return;
}
rememberStuckContact(level, pos, entity);
if (!(entity instanceof ItemEntity)) {
maybeConsumeTapeDecay(level, pos, state);
}
long gameTime = level.getGameTime();
String tapeKey = tapeKey(level, pos);
if (shouldPlayStickSound(entity.getUUID(), tapeKey, gameTime)) {
level.playSound(null, pos, AntarchySoundEvents.DUCT_TAPE_USE.get(), SoundSource.BLOCKS, 0.85F, 0.9F + level.random.nextFloat() * 0.15F);
}
applyStick(state, pos, entity);
}
@Override @Override
public void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) { public void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(USES, FACE, FACING); builder.add(USES, FACE, FACING);
@@ -237,12 +174,6 @@ public class DuctTapeBlock extends Block {
}; };
} }
private static boolean isReleaseTool(ItemStack stack) {
return stack.getItem() instanceof DiggerItem
|| stack.getItem() instanceof SwordItem
|| stack.getItem() instanceof ShearsItem;
}
private static void consumeTapeUse(Level level, BlockPos pos, BlockState state) { private static void consumeTapeUse(Level level, BlockPos pos, BlockState state) {
int remainingUses = state.getValue(USES) - 1; int remainingUses = state.getValue(USES) - 1;
if (remainingUses > 0) { if (remainingUses > 0) {
@@ -250,322 +181,6 @@ public class DuctTapeBlock extends Block {
return; return;
} }
releaseEntitiesForTape(level, pos);
TAPE_DECAY_TIMES.remove(tapeDecayKey(level, pos));
level.removeBlock(pos, false); level.removeBlock(pos, false);
} }
private static void removeTape(Level level, BlockPos pos, BlockState state) {
releaseEntitiesForTape(level, pos);
TAPE_DECAY_TIMES.remove(tapeDecayKey(level, pos));
level.removeBlock(pos, false);
}
private static void maybeConsumeTapeDecay(Level level, BlockPos pos, BlockState state) {
long gameTime = level.getGameTime();
String key = tapeDecayKey(level, pos);
Long lastConsumed = TAPE_DECAY_TIMES.get(key);
if (lastConsumed == null) {
TAPE_DECAY_TIMES.put(key, gameTime);
return;
}
if (gameTime - lastConsumed < TAPE_DECAY_INTERVAL_TICKS) {
return;
}
TAPE_DECAY_TIMES.put(key, gameTime);
consumeTapeUse(level, pos, state);
}
public static void tickStuckEntity(Entity entity) {
if (entity == null || entity.level().isClientSide() || isStickyBlacklist(entity)) {
return;
}
if (!entity.isAlive() || entity.isRemoved()) {
releaseEntity(entity);
return;
}
StuckContact contact = STUCK_ENTITIES.get(entity.getUUID());
if (contact != null && isContactValid(entity.level(), contact)) {
BlockPos pos = BlockPos.of(contact.blockPos());
BlockState state = entity.level().getBlockState(pos);
applyStick(state, pos, entity);
if (!(entity instanceof ItemEntity)) {
maybeConsumeTapeDecay(entity.level(), pos, state);
}
return;
}
if (contact != null) {
releaseEntity(entity);
}
if (!shouldSearchForTape(entity)) {
return;
}
TapeHit hit = findTouchedTape(entity.level(), entity);
if (hit == null) {
if (entity.isNoGravity()) {
entity.setNoGravity(false);
}
return;
}
rememberStuckContact(entity.level(), hit.pos(), entity);
applyStick(hit.state(), hit.pos(), entity);
if (!(entity instanceof ItemEntity)) {
maybeConsumeTapeDecay(entity.level(), hit.pos(), hit.state());
}
}
public static boolean isStuckToTape(Entity entity) {
if (entity == null || entity.level().isClientSide() || isStickyBlacklist(entity)) {
return false;
}
StuckContact contact = STUCK_ENTITIES.get(entity.getUUID());
return contact != null && isContactValid(entity.level(), contact);
}
public static boolean isTouchingTape(Entity entity) {
return entity != null && isTouchingTape(entity.level(), entity);
}
public static boolean isTouchingTape(Level level, Entity entity) {
if (isStickyBlacklist(entity)) {
return false;
}
return findTouchedTape(level, entity) != null;
}
public static boolean shouldTickStuckEntity(Entity entity) {
if (entity == null || entity.level().isClientSide() || isStickyBlacklist(entity)) {
return false;
}
if (!entity.isAlive() || entity.isRemoved()) {
return true;
}
StuckContact contact = STUCK_ENTITIES.get(entity.getUUID());
if (contact != null) {
return true;
}
return shouldSearchForTape(entity);
}
private static boolean isStickyBlacklist(Entity entity) {
return entity != null && entity.getType().is(AntarchyTags.Entities.DUCT_TAPE_STICK_BLACKLIST);
}
private static void applyStick(BlockState state, BlockPos pos, Entity entity) {
entity.setDeltaMovement(Vec3.ZERO);
entity.resetFallDistance();
entity.hasImpulse = true;
entity.setNoGravity(true);
Vec3 anchor = getTapeAnchor(state, pos, entity);
entity.setPos(anchor.x, anchor.y, anchor.z);
if (state.getValue(FACE) == AttachFace.FLOOR) {
entity.setOnGround(true);
}
}
private static void rememberStuckContact(Level level, BlockPos pos, Entity entity) {
UUID entityId = entity.getUUID();
String key = tapeKey(level, pos);
StuckContact existing = STUCK_ENTITIES.get(entityId);
if (existing != null && existing.tapeKey().equals(key)) {
return;
}
double offsetX = entity.getX() - pos.getX();
double offsetY = entity.getY() - pos.getY();
double offsetZ = entity.getZ() - pos.getZ();
STUCK_ENTITIES.put(entityId, new StuckContact(
key,
level.dimension().location().toString(),
pos.asLong(),
clamp(offsetX, 0.05D, 0.95D),
clamp(offsetY, 0.0D, 0.98D),
clamp(offsetZ, 0.05D, 0.95D)
));
}
private static Vec3 getTapeAnchor(BlockState state, BlockPos pos, Entity entity) {
StuckContact contact = STUCK_ENTITIES.get(entity.getUUID());
double offsetX = contact != null ? contact.offsetX() : 0.5D;
double offsetY = contact != null ? contact.offsetY() : 0.0D;
double offsetZ = contact != null ? contact.offsetZ() : 0.5D;
double wallOffset = entity instanceof Player ? 0.06D : -0.28D;
double centerX = pos.getX() + 0.5D;
double centerZ = pos.getZ() + 0.5D;
return switch (state.getValue(FACE)) {
case FLOOR -> new Vec3(
pos.getX() + offsetX,
pos.getY() + 0.01D,
pos.getZ() + offsetZ
);
case WALL -> switch (state.getValue(FACING)) {
case NORTH -> new Vec3(centerX, pos.getY() + offsetY, pos.getZ() - wallOffset);
case SOUTH -> new Vec3(centerX, pos.getY() + offsetY, pos.getZ() + 1.0D + wallOffset);
case EAST -> new Vec3(pos.getX() + 1.0D + wallOffset, pos.getY() + offsetY, centerZ);
case WEST -> new Vec3(pos.getX() - wallOffset, pos.getY() + offsetY, centerZ);
default -> new Vec3(centerX, pos.getY() + offsetY, centerZ);
};
default -> new Vec3(pos.getX() + offsetX, pos.getY() + 0.01D, pos.getZ() + offsetZ);
};
}
private static boolean isContactValid(Level level, StuckContact contact) {
if (!level.dimension().location().toString().equals(contact.dimensionId())) {
return false;
}
BlockPos pos = BlockPos.of(contact.blockPos());
BlockState state = level.getBlockState(pos);
return state.getBlock() instanceof DuctTapeBlock
&& tapeKey(level, pos).equals(contact.tapeKey());
}
private static boolean shouldSearchForTape(Entity entity) {
Vec3 velocity = entity.getDeltaMovement();
if (velocity.lengthSqr() < SEARCH_MOTION_THRESHOLD_SQR) {
return false;
}
return (entity.tickCount + entity.getId()) % SEARCH_INTERVAL_TICKS == 0;
}
private static TapeHit findTouchedTape(Level level, Entity entity) {
AABB box = entity.getBoundingBox().inflate(SEARCH_PAD_XZ, SEARCH_PAD_Y, SEARCH_PAD_XZ);
BlockPos min = BlockPos.containing(box.minX, box.minY, box.minZ);
BlockPos max = BlockPos.containing(box.maxX, box.maxY, box.maxZ);
if (!level.hasChunksAt(min, max)) {
return null;
}
BlockPos.MutableBlockPos cursor = new BlockPos.MutableBlockPos();
for (int x = min.getX(); x <= max.getX(); x++) {
for (int y = min.getY(); y <= max.getY(); y++) {
for (int z = min.getZ(); z <= max.getZ(); z++) {
cursor.set(x, y, z);
BlockState state = level.getBlockState(cursor);
if (state.isAir()) {
continue;
}
if (state.getBlock() instanceof DuctTapeBlock && touchesTape(level, entity, cursor, state)) {
return new TapeHit(cursor.immutable(), state);
}
}
}
}
return null;
}
private static boolean touchesTape(Level level, Entity entity, BlockPos pos, BlockState state) {
return entity.getBoundingBox().intersects(getStickyTriggerBounds(state, pos));
}
private static AABB getStickyTriggerBounds(BlockState state, BlockPos pos) {
AABB bounds = getShapeFor(state).bounds().move(pos);
return switch (state.getValue(FACE)) {
case FLOOR -> new AABB(
bounds.minX - TRIGGER_PAD,
pos.getY() - 0.02D,
bounds.minZ - TRIGGER_PAD,
bounds.maxX + TRIGGER_PAD,
pos.getY() + FLOOR_TRIGGER_HEIGHT,
bounds.maxZ + TRIGGER_PAD
);
case WALL -> {
yield switch (state.getValue(FACING)) {
case NORTH -> new AABB(bounds.minX - WALL_SIDE_PAD, bounds.minY - WALL_Y_PAD, bounds.minZ - WALL_TRIGGER_DEPTH, bounds.maxX + WALL_SIDE_PAD, bounds.maxY + WALL_Y_PAD, bounds.maxZ + WALL_INNER_INSET);
case SOUTH -> new AABB(bounds.minX - WALL_SIDE_PAD, bounds.minY - WALL_Y_PAD, bounds.minZ - WALL_INNER_INSET, bounds.maxX + WALL_SIDE_PAD, bounds.maxY + WALL_Y_PAD, bounds.maxZ + WALL_TRIGGER_DEPTH);
case EAST -> new AABB(bounds.minX - WALL_TRIGGER_DEPTH, bounds.minY - WALL_Y_PAD, bounds.minZ - WALL_SIDE_PAD, bounds.maxX + WALL_INNER_INSET, bounds.maxY + WALL_Y_PAD, bounds.maxZ + WALL_SIDE_PAD);
case WEST -> new AABB(bounds.minX - WALL_INNER_INSET, bounds.minY - WALL_Y_PAD, bounds.minZ - WALL_SIDE_PAD, bounds.maxX + WALL_TRIGGER_DEPTH, bounds.maxY + WALL_Y_PAD, bounds.maxZ + WALL_SIDE_PAD);
default -> bounds.inflate(TRIGGER_INFLATE_DEFAULT);
};
}
default -> bounds.inflate(TRIGGER_INFLATE_DEFAULT);
};
}
private static void releaseEntitiesForTape(Level level, BlockPos pos) {
String key = tapeKey(level, pos);
AABB searchBox = AABB.unitCubeFromLowerCorner(Vec3.atLowerCornerOf(pos)).inflate(2.0D);
STUCK_ENTITIES.entrySet().removeIf(entry -> {
StuckContact contact = entry.getValue();
if (!key.equals(contact.tapeKey())) {
return false;
}
level.getEntitiesOfClass(Entity.class, searchBox, candidate -> candidate.getUUID().equals(entry.getKey()))
.forEach(candidate -> candidate.setNoGravity(false));
STICK_SOUND_TIMES.remove(entry.getKey());
STICK_CONTACT_KEYS.remove(entry.getKey());
return true;
});
}
private static void releaseEntity(Entity entity) {
if (entity == null) {
return;
}
STUCK_ENTITIES.remove(entity.getUUID());
STICK_SOUND_TIMES.remove(entity.getUUID());
STICK_CONTACT_KEYS.remove(entity.getUUID());
entity.setNoGravity(false);
}
private static String tapeDecayKey(Level level, BlockPos pos) {
return level.dimension().location() + ":" + pos.asLong();
}
private static String tapeKey(Level level, BlockPos pos) {
return level.dimension().location() + ":" + pos.asLong();
}
private static boolean shouldPlayStickSound(UUID entityId, String tapeKey, long gameTime) {
String lastKey = STICK_CONTACT_KEYS.get(entityId);
Long lastContact = STICK_SOUND_TIMES.get(entityId);
if (lastKey == null || !tapeKey.equals(lastKey)) {
STICK_CONTACT_KEYS.put(entityId, tapeKey);
STICK_SOUND_TIMES.put(entityId, gameTime);
return true;
}
if (lastContact == null || gameTime - lastContact > STICK_SOUND_COOLDOWN_TICKS) {
STICK_SOUND_TIMES.put(entityId, gameTime);
return true;
}
return false;
}
private static double clamp(double value, double min, double max) {
return Math.max(min, Math.min(max, value));
}
private record StuckContact(
String tapeKey,
String dimensionId,
long blockPos,
double offsetX,
double offsetY,
double offsetZ
) {
}
private record TapeHit(BlockPos pos, BlockState state) {
}
} }
@@ -25,7 +25,6 @@ public final class DuplicatorTreeLogic {
private static final int LOG_SEARCH_BELOW = 5; private static final int LOG_SEARCH_BELOW = 5;
private static final int LOG_SEARCH_ABOVE = 1; private static final int LOG_SEARCH_ABOVE = 1;
// Cache center log pos per chunk. WeakHashMap lets levels be GC'd when unloaded.
private static final WeakHashMap<ServerLevel, HashMap<Long, BlockPos>> CENTER_LOG_CACHE = new WeakHashMap<>(); private static final WeakHashMap<ServerLevel, HashMap<Long, BlockPos>> CENTER_LOG_CACHE = new WeakHashMap<>();
private DuplicatorTreeLogic() { private DuplicatorTreeLogic() {
@@ -0,0 +1,76 @@
package com.craisinlord.antarchy.content.block;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.EntityCollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
public class FlytrapGooBlock extends Block {
private static final double BOUNCE_VELOCITY_THRESHOLD = 0.6;
private static final double MAX_SINK_SPEED = 0.05;
private static final double SPRINT_VELOCITY_THRESHOLD = 0.1;
public FlytrapGooBlock(BlockBehaviour.Properties properties) {
super(properties);
}
public boolean isStickyBlock(BlockState state) {
return true;
}
public boolean canStickTo(BlockState state, BlockState other) {
return !other.is(Blocks.SLIME_BLOCK) && !other.is(Blocks.HONEY_BLOCK);
}
@Override
public VoxelShape getCollisionShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
if (context instanceof EntityCollisionContext ecc) {
Entity entity = ecc.getEntity();
if (entity != null) {
Vec3 delta = entity.getDeltaMovement();
double vy = delta.y;
double hSpeed = Math.sqrt(delta.x * delta.x + delta.z * delta.z);
if (vy <= 0.0 && vy > -BOUNCE_VELOCITY_THRESHOLD && hSpeed < SPRINT_VELOCITY_THRESHOLD) {
return Shapes.empty();
}
}
}
return super.getCollisionShape(state, level, pos, context);
}
@Override
public void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) {
Vec3 delta = entity.getDeltaMovement();
if (delta.y < -MAX_SINK_SPEED) {
entity.setDeltaMovement(delta.x * 0.9, -MAX_SINK_SPEED, delta.z * 0.9);
} else {
entity.setDeltaMovement(delta.x * 0.9, delta.y, delta.z * 0.9);
}
entity.fallDistance = 0.0F;
}
@Override
public void fallOn(Level level, BlockState state, BlockPos pos, Entity entity, float fallDistance) {
entity.causeFallDamage(fallDistance, 0.0F, level.damageSources().fall());
}
@Override
public void updateEntityAfterFallOn(BlockGetter level, Entity entity) {
Vec3 delta = entity.getDeltaMovement();
if (delta.y < 0.0) {
double coefficient = entity instanceof LivingEntity ? 1.0 : 0.8;
entity.setDeltaMovement(delta.x, -delta.y * coefficient, delta.z);
}
}
}
@@ -19,7 +19,6 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf; import net.minecraft.world.level.block.state.properties.DoubleBlockHalf;
import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.BlockHitResult;
/** A two-block-tall, light-emitting reed found around Lumen pools. */
public final class GlimmeringReedBlock extends DoublePlantBlock implements BonemealableBlock { public final class GlimmeringReedBlock extends DoublePlantBlock implements BonemealableBlock {
public GlimmeringReedBlock(BlockBehaviour.Properties properties) { public GlimmeringReedBlock(BlockBehaviour.Properties properties) {
@@ -1,160 +0,0 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.JumpyBugEntity;
import com.craisinlord.antarchy.content.horde.CavarynHordeManager;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.EntityType;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.level.block.state.properties.IntegerProperty;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class JumpyBugEggBlock extends Block {
public static final IntegerProperty HATCH = BlockStateProperties.HATCH;
public static final BooleanProperty HANGING = BlockStateProperties.HANGING;
public static final BooleanProperty ROTATED = BooleanProperty.create("rotated");
private static final int MAX_HATCH = 2;
private static final double PLAYER_PROXIMITY_RADIUS = 12.0D;
private static final double HORDE_ACCELERATION_RADIUS = 5.0D;
private static final float PLAYER_PROXIMITY_HATCH_CHANCE = 0.25F;
private static final int PLAYER_PROXIMITY_CHECK_INTERVAL = 200;
private static final VoxelShape FLOOR_SHAPE = Block.box(1.5D, 0.0D, 1.5D, 14.5D, 16.0D, 14.5D);
private static final VoxelShape CEILING_SHAPE = Block.box(1.5D, 0.0D, 1.5D, 14.5D, 16.0D, 14.5D);
private static final ResourceLocation JUMPY_BUG_ID = new ResourceLocation(Antarchy.MODID, "jumpy_bug");
public JumpyBugEggBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any().setValue(HATCH, 0).setValue(HANGING, false).setValue(ROTATED, false));
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return state.getValue(HANGING) ? CEILING_SHAPE : FLOOR_SHAPE;
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
boolean hanging = context.getClickedFace() == Direction.DOWN
|| (context.getClickedFace() != Direction.UP && !canSupportFloor(context.getLevel(), context.getClickedPos()) && canSupportCeiling(context.getLevel(), context.getClickedPos()));
boolean rotated = context.getHorizontalDirection().getAxis() == Direction.Axis.X;
return this.defaultBlockState().setValue(HANGING, hanging).setValue(ROTATED, rotated);
}
@Override
public BlockState rotate(BlockState state, Rotation rotation) {
return rotation == Rotation.CLOCKWISE_90 || rotation == Rotation.COUNTERCLOCKWISE_90
? state.setValue(ROTATED, !state.getValue(ROTATED))
: state;
}
@Override
public BlockState mirror(BlockState state, Mirror mirror) {
return state;
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return state.getValue(HANGING) ? canSupportCeiling(level, pos) : canSupportFloor(level, pos);
}
@Override
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) {
return state.canSurvive(level, pos) ? super.updateShape(state, direction, neighborState, level, pos, neighborPos) : Blocks.AIR.defaultBlockState();
}
private static boolean canSupportFloor(LevelReader level, BlockPos pos) {
return level.getBlockState(pos.below()).isFaceSturdy(level, pos.below(), Direction.UP);
}
private static boolean canSupportCeiling(LevelReader level, BlockPos pos) {
return level.getBlockState(pos.above()).isFaceSturdy(level, pos.above(), Direction.DOWN);
}
@Override
public boolean isRandomlyTicking(BlockState state) {
return true;
}
@Override
public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (!this.shouldUpdateHatchLevel(level, pos, state)) {
return;
}
int hatch = state.getValue(HATCH);
if (hatch < MAX_HATCH) {
level.setBlock(pos, state.setValue(HATCH, hatch + 1), 2);
level.playSound(null, pos, SoundEvents.TURTLE_EGG_CRACK, SoundSource.BLOCKS, 0.7F, 0.95F + random.nextFloat() * 0.1F);
return;
}
this.hatch(level, pos, random);
}
private boolean shouldUpdateHatchLevel(Level level, BlockPos pos, BlockState state) {
if (level instanceof ServerLevel serverLevel
&& CavarynHordeManager.shouldAccelerateNearbyEggHatching(serverLevel, pos, HORDE_ACCELERATION_RADIUS, level.random)) {
return true;
}
if (level.random.nextInt(PLAYER_PROXIMITY_CHECK_INTERVAL) == 0) {
Player nearbyPlayer = level.getNearestPlayer(pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D, PLAYER_PROXIMITY_RADIUS, false);
if (nearbyPlayer != null && level.random.nextFloat() < PLAYER_PROXIMITY_HATCH_CHANCE) {
return true;
}
}
BlockPos checkPos = state.getValue(HANGING) ? pos.above() : pos.below();
boolean onAmberMoss = level.getBlockState(checkPos).getBlock() instanceof AmberMossBlock;
return level.random.nextInt(onAmberMoss ? 150 : 500) == 0;
}
private void hatch(ServerLevel level, BlockPos pos, RandomSource random) {
level.removeBlock(pos, false);
level.playSound(null, pos, SoundEvents.TURTLE_EGG_HATCH, SoundSource.BLOCKS, 0.75F, 0.95F + random.nextFloat() * 0.1F);
@SuppressWarnings("unchecked")
EntityType<JumpyBugEntity> jumpyBugType = (EntityType<JumpyBugEntity>) (EntityType<?>) BuiltInRegistries.ENTITY_TYPE.getOptional(JUMPY_BUG_ID).orElse(null);
if (jumpyBugType == null) {
return;
}
JumpyBugEntity entity = jumpyBugType.create(level);
if (entity == null) {
return;
}
double spawnX = pos.getX() + 0.25D + random.nextDouble() * 0.5D;
double spawnZ = pos.getZ() + 0.25D + random.nextDouble() * 0.5D;
entity.moveTo(spawnX, pos.getY() + 0.1D, spawnZ, random.nextFloat() * 360.0F, 0.0F);
level.addFreshEntity(entity);
}
public void hatchWithNucleus(ServerLevel level, BlockPos pos) {
this.hatch(level, pos, level.random);
}
@Override
public void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(HATCH, HANGING, ROTATED);
}
}
@@ -1,244 +0,0 @@
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.craisinlord.antarchy.content.block.CreepingHorrorEggBlock;
import com.craisinlord.antarchy.content.horde.CavarynHordeManager;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.tags.BlockTags;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.ambient.Bat;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.IntegerProperty;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class LurkingTerrorEggBlock extends Block {
public static final IntegerProperty HATCH = BlockStateProperties.HATCH;
public static final IntegerProperty EGGS = BlockStateProperties.EGGS;
private static final float PANIC_HATCH_CHANCE = 0.25F;
private static final double HORDE_ACCELERATION_RADIUS = 5.0D;
private static final int MAX_HATCH = 2;
private static final int MAX_EGGS = 4;
private static final VoxelShape SINGLE_SHAPE = Block.box(3.0D, 0.0D, 3.0D, 13.0D, 7.0D, 13.0D);
private static final VoxelShape MULTI_SHAPE = Block.box(1.0D, 0.0D, 1.0D, 15.0D, 7.0D, 15.0D);
public LurkingTerrorEggBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any().setValue(HATCH, 0).setValue(EGGS, 1));
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return state.getValue(EGGS) > 1 ? MULTI_SHAPE : SINGLE_SHAPE;
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return level.getBlockState(pos.below()).isFaceSturdy(level, pos.below(), Direction.UP);
}
@Override
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) {
return state.canSurvive(level, pos) ? super.updateShape(state, direction, neighborState, level, pos, neighborPos) : Blocks.AIR.defaultBlockState();
}
@Override
public boolean canBeReplaced(BlockState state, BlockPlaceContext context) {
return !context.isSecondaryUseActive()
&& context.getItemInHand().is(this.asItem())
&& state.getValue(EGGS) < MAX_EGGS;
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
BlockState existingState = context.getLevel().getBlockState(context.getClickedPos());
if (existingState.is(this)) {
return existingState.setValue(EGGS, Math.min(MAX_EGGS, existingState.getValue(EGGS) + 1));
}
return this.defaultBlockState();
}
@Override
public boolean isRandomlyTicking(BlockState state) {
return true;
}
@Override
public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (!this.shouldUpdateHatchLevel(level, pos)) {
return;
}
int hatch = state.getValue(HATCH);
if (hatch < MAX_HATCH) {
level.setBlock(pos, state.setValue(HATCH, hatch + 1), 2);
level.playSound(null, pos, SoundEvents.TURTLE_EGG_CRACK, SoundSource.BLOCKS, 0.7F, 0.95F + random.nextFloat() * 0.1F);
return;
}
this.hatchEggs(level, pos, state, random, state.getValue(EGGS));
}
@Override
public void stepOn(Level level, BlockPos pos, BlockState state, Entity entity) {
if (entity instanceof Player && !entity.isSteppingCarefully() && this.destroyEgg(level, state, pos, entity, 100)) {
if (level instanceof ServerLevel serverLevel) {
panicHatchNearby(serverLevel, pos);
}
}
super.stepOn(level, pos, state, entity);
}
@Override
public void fallOn(Level level, BlockState state, BlockPos pos, Entity entity, float fallDistance) {
this.destroyEgg(level, state, pos, entity, 3);
super.fallOn(level, state, pos, entity, fallDistance);
}
@Override
public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean isMoving) {
if (hasHatchSupport(level, pos) && !level.isClientSide) {
level.levelEvent(2012, pos, 15);
}
}
@Override
public void playerDestroy(Level level, Player player, BlockPos pos, BlockState state, BlockEntity blockEntity, net.minecraft.world.item.ItemStack stack) {
super.playerDestroy(level, player, pos, state, blockEntity, stack);
this.decreaseEggs(level, pos, state);
}
private static void panicHatchNearby(ServerLevel level, BlockPos origin) {
int radius = 6;
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
for (int dx = -radius; dx <= radius; dx++) {
for (int dy = -radius; dy <= radius; dy++) {
for (int dz = -radius; dz <= radius; dz++) {
if (dx == 0 && dy == 0 && dz == 0) continue;
mutable.set(origin.getX() + dx, origin.getY() + dy, origin.getZ() + dz);
BlockState nearby = level.getBlockState(mutable);
BlockPos immutable = mutable.immutable();
if (nearby.getBlock() instanceof LurkingTerrorEggBlock b) {
b.hatchPanickedEggs(level, immutable, nearby, level.random);
} else if (nearby.getBlock() instanceof CreepingHorrorEggBlock b) {
b.hatchPanickedEggs(level, immutable, nearby, level.random);
}
}
}
}
}
@Override
public void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(HATCH, EGGS);
}
public static boolean hasHatchSupport(BlockGetter level, BlockPos pos) {
return isSupportedGround(level, pos.below());
}
public static boolean isSupportedGround(BlockGetter level, BlockPos pos) {
return level.getBlockState(pos).is(BlockTags.SAND) || level.getBlockState(pos).blocksMotion();
}
private boolean destroyEgg(Level level, BlockState state, BlockPos pos, Entity entity, int chance) {
if (level.isClientSide || !this.canDestroyEgg(level, entity) || level.random.nextInt(chance) != 0) {
return false;
}
level.playSound(null, pos, SoundEvents.TURTLE_EGG_BREAK, SoundSource.BLOCKS, 0.7F, 0.9F + level.random.nextFloat() * 0.2F);
this.decreaseEggs(level, pos, state);
return true;
}
void hatchPanickedEggs(ServerLevel level, BlockPos pos, BlockState state, RandomSource random) {
int hatchedEggs = rollPanickedEggs(state.getValue(EGGS), random);
if (hatchedEggs <= 0) {
return;
}
this.hatchEggs(level, pos, state, random, hatchedEggs);
}
void hatchEggs(ServerLevel level, BlockPos pos, BlockState state, RandomSource random, int eggsToHatch) {
if (eggsToHatch >= state.getValue(EGGS)) {
level.removeBlock(pos, false);
} else {
level.setBlock(pos, state.setValue(EGGS, state.getValue(EGGS) - eggsToHatch), 2);
}
level.playSound(null, pos, SoundEvents.TURTLE_EGG_HATCH, SoundSource.BLOCKS, 0.75F, 0.95F + random.nextFloat() * 0.1F);
for (int i = 0; i < eggsToHatch; i++) {
LurkingTerrorEntity entity = AntarchyObjects.LURKING_TERROR.get().create(level);
if (entity == null) {
continue;
}
double spawnX = pos.getX() + 0.25D + random.nextDouble() * 0.5D;
double spawnZ = pos.getZ() + 0.25D + random.nextDouble() * 0.5D;
entity.moveTo(spawnX, pos.getY() + 0.1D, spawnZ, random.nextFloat() * 360.0F, 0.0F);
level.addFreshEntity(entity);
}
}
public void hatchWithNucleus(ServerLevel level, BlockPos pos, BlockState state) {
this.hatchEggs(level, pos, state, level.random, state.getValue(EGGS));
}
private static int rollPanickedEggs(int eggs, RandomSource random) {
int hatchedEggs = 0;
for (int i = 0; i < eggs; i++) {
if (random.nextFloat() < PANIC_HATCH_CHANCE) {
hatchedEggs++;
}
}
return hatchedEggs;
}
private void decreaseEggs(Level level, BlockPos pos, BlockState state) {
int eggs = state.getValue(EGGS);
if (eggs <= 1) {
level.destroyBlock(pos, false);
return;
}
level.setBlock(pos, state.setValue(EGGS, eggs - 1), 2);
}
private boolean shouldUpdateHatchLevel(Level level, BlockPos pos) {
if (level instanceof ServerLevel serverLevel
&& CavarynHordeManager.shouldAccelerateNearbyEggHatching(serverLevel, pos, HORDE_ACCELERATION_RADIUS, level.random)) {
return true;
}
boolean onAmberMoss = level.getBlockState(pos.below()).getBlock() instanceof AmberMossBlock;
return level.random.nextInt(onAmberMoss ? 150 : 500) == 0;
}
private boolean canDestroyEgg(Level level, Entity entity) {
if (entity instanceof LurkingTerrorEntity || entity instanceof Bat) {
return false;
}
if (entity instanceof net.minecraft.world.entity.LivingEntity) {
return entity instanceof Player || level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING);
}
return false;
}
}
@@ -1,5 +1,6 @@
package com.craisinlord.antarchy.content.block; package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.entity.WormEntity;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
@@ -16,9 +17,9 @@ import net.minecraft.world.phys.shapes.VoxelShape;
public class MucusBlock extends GlowLichenBlock { public class MucusBlock extends GlowLichenBlock {
private static final VoxelShape DOWN_COLLISION_SHAPE = Shapes.box(0.0D, 0.0D, 0.0D, 1.0D, 0.0625D, 1.0D); 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_ACCELERATION = 0.045D;
private static final double SLIDE_MAX_SPEED = 0.6D; private static final double SLIDE_MAX_SPEED = 1.2D;
private static final double SLIDE_MIN_SPEED = 0.02D; private static final double SLIDE_MIN_SPEED = 0.01D;
public MucusBlock(BlockBehaviour.Properties properties) { public MucusBlock(BlockBehaviour.Properties properties) {
super(properties); super(properties);
@@ -30,9 +31,12 @@ public class MucusBlock extends GlowLichenBlock {
} }
@Override @Override
public void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) { public void stepOn(Level level, BlockPos pos, BlockState state, Entity entity) {
super.entityInside(state, level, pos, entity); super.stepOn(level, pos, state, entity);
if (level.isClientSide || !state.getValue(MultifaceBlock.getFaceProperty(Direction.DOWN))) { if (level.isClientSide
|| entity instanceof WormEntity
|| entity.isShiftKeyDown()
|| !state.getValue(MultifaceBlock.getFaceProperty(Direction.DOWN))) {
return; return;
} }
@@ -1,20 +1,35 @@
package com.craisinlord.antarchy.content.block; package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.worldgen.thoraxis.NadirTreeGrowers;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.tags.BlockTags; import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.tags.TagKey;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.BonemealableBlock;
import net.minecraft.world.level.block.BushBlock; import net.minecraft.world.level.block.BushBlock;
import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraft.world.phys.shapes.VoxelShape;
public class NadirSaplingBlock extends BushBlock { public class NadirSaplingBlock extends BushBlock implements BonemealableBlock {
private static final VoxelShape SHAPE = Block.box(2.0D, 0.0D, 2.0D, 14.0D, 12.0D, 14.0D); private static final TagKey<Block> SUPPORTS = TagKey.create(
Registries.BLOCK,
new ResourceLocation(Antarchy.MODID, "nadir_sapling_supports")
);
private static final VoxelShape SHAPE = Block.box(2.0D, 4.0D, 2.0D, 14.0D, 16.0D, 14.0D);
public NadirSaplingBlock(BlockBehaviour.Properties properties) { public NadirSaplingBlock(BlockBehaviour.Properties properties) {
super(properties); super(properties);
@@ -27,7 +42,21 @@ public class NadirSaplingBlock extends BushBlock {
@Override @Override
public boolean mayPlaceOn(BlockState state, BlockGetter level, BlockPos pos) { public boolean mayPlaceOn(BlockState state, BlockGetter level, BlockPos pos) {
return state.is(BlockTags.DIRT) || state.is(Blocks.FARMLAND); return state.is(SUPPORTS);
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
BlockPos supportPos = pos.above();
BlockState supportState = level.getBlockState(supportPos);
return supportState.is(SUPPORTS) && supportState.isFaceSturdy(level, supportPos, Direction.DOWN);
}
@Override
public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (random.nextInt(7) == 0) {
this.growConfiguredTree(level, pos, state, random);
}
} }
@Override @Override
@@ -43,4 +72,32 @@ public class NadirSaplingBlock extends BushBlock {
? super.updateShape(state, direction, neighborState, level, pos, neighborPos) ? super.updateShape(state, direction, neighborState, level, pos, neighborPos)
: Blocks.AIR.defaultBlockState(); : Blocks.AIR.defaultBlockState();
} }
@Override
public boolean isValidBonemealTarget(LevelReader level, BlockPos pos, BlockState state, boolean isClient) {
return true;
}
@Override
public boolean isBonemealSuccess(Level level, RandomSource random, BlockPos pos, BlockState state) {
return random.nextFloat() < 0.45F;
}
@Override
public void performBonemeal(ServerLevel level, RandomSource random, BlockPos pos, BlockState state) {
this.growConfiguredTree(level, pos, state, random);
}
private void growConfiguredTree(ServerLevel level, BlockPos pos, BlockState state, RandomSource random) {
Holder.Reference<ConfiguredFeature<?, ?>> feature = level.registryAccess()
.lookupOrThrow(Registries.CONFIGURED_FEATURE)
.getOrThrow(NadirTreeGrowers.NADIR_TREE);
level.removeBlock(pos, false);
if (feature.value().place(level, level.getChunkSource().getGenerator(), random, pos)) {
return;
}
level.setBlock(pos, state, Block.UPDATE_ALL);
}
} }
@@ -23,12 +23,6 @@ import net.minecraft.world.level.material.Fluids;
public class OuranwoodLeavesBlock extends LeavesBlock implements BonemealableBlock { public class OuranwoodLeavesBlock extends LeavesBlock implements BonemealableBlock {
/*
* We still include vanilla LeavesBlock.DISTANCE in the state definition because
* LeavesBlock's constructor sets it.
*
* This is the real Ouranwood decay distance.
*/
public static final IntegerProperty OURANWOOD_DISTANCE = IntegerProperty.create("ouranwood_distance", 1, 17); public static final IntegerProperty OURANWOOD_DISTANCE = IntegerProperty.create("ouranwood_distance", 1, 17);
public static final BooleanProperty PERSISTENT = LeavesBlock.PERSISTENT; public static final BooleanProperty PERSISTENT = LeavesBlock.PERSISTENT;
@@ -13,12 +13,6 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.IntegerProperty; import net.minecraft.world.level.block.state.properties.IntegerProperty;
/**
* Invisible world-gen-only marker placed inside a flying squirrel hollow.
* Schedules itself to replace with COARSE_DIRT and spawn squirrels shortly
* after the chunk loads, so entity creation never blocks the gen thread.
* No BlockItem is registered, so this block never appears in creative or JEI.
*/
public class OuranwoodSquirrelNestBlock extends Block { public class OuranwoodSquirrelNestBlock extends Block {
public static final IntegerProperty SQUIRREL_COUNT = IntegerProperty.create("squirrels", 1, 3); public static final IntegerProperty SQUIRREL_COUNT = IntegerProperty.create("squirrels", 1, 3);
@@ -14,7 +14,6 @@ import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
/** Invisible worldgen marker which activates the Queen at a generated trail terminus. */
public final class QueenTrailSpawnMarkerBlock extends BaseEntityBlock { public final class QueenTrailSpawnMarkerBlock extends BaseEntityBlock {
private final Supplier<? extends BlockEntityType<QueenTrailSpawnMarkerBlockEntity>> type; private final Supplier<? extends BlockEntityType<QueenTrailSpawnMarkerBlockEntity>> type;
@@ -3,6 +3,7 @@ package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.config.AntarchySettings; import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.block.entity.RoyalEggBlockEntity; import com.craisinlord.antarchy.content.block.entity.RoyalEggBlockEntity;
import com.craisinlord.antarchy.content.entity.royal.RoyalMountEntity; import com.craisinlord.antarchy.content.entity.royal.RoyalMountEntity;
import com.craisinlord.antarchy.content.worldgen.thoraxis.ThoraxisUndersideManager;
import java.util.UUID; import java.util.UUID;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
@@ -18,6 +19,7 @@ import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.MobSpawnType; import net.minecraft.world.entity.MobSpawnType;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.entity.item.FallingBlockEntity; import net.minecraft.world.entity.item.FallingBlockEntity;
import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LevelAccessor;
@@ -30,6 +32,7 @@ import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.level.block.state.properties.IntegerProperty; import net.minecraft.world.level.block.state.properties.IntegerProperty;
import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.CollisionContext;
@@ -39,6 +42,7 @@ import org.jetbrains.annotations.Nullable;
public abstract class RoyalEggBlock extends BaseEntityBlock { public abstract class RoyalEggBlock extends BaseEntityBlock {
public static final IntegerProperty HATCH = BlockStateProperties.HATCH; public static final IntegerProperty HATCH = BlockStateProperties.HATCH;
public static final BooleanProperty INVERTED = BooleanProperty.create("inverted");
private static final int MAX_HATCH = 2; private static final int MAX_HATCH = 2;
private static final int FALL_DELAY = 2; private static final int FALL_DELAY = 2;
@@ -49,16 +53,23 @@ public abstract class RoyalEggBlock extends BaseEntityBlock {
Block.box(5.0D, 14.0D, 5.0D, 11.0D, 15.0D, 11.0D), Block.box(5.0D, 14.0D, 5.0D, 11.0D, 15.0D, 11.0D),
Block.box(6.0D, 15.0D, 6.0D, 10.0D, 16.0D, 10.0D)); Block.box(6.0D, 15.0D, 6.0D, 10.0D, 16.0D, 10.0D));
public RoyalEggBlock(Properties properties) { private static final VoxelShape INVERTED_SHAPE = Shapes.or(
Block.box(3.0D, 3.0D, 3.0D, 13.0D, 16.0D, 13.0D),
Block.box(2.0D, 5.0D, 2.0D, 14.0D, 15.0D, 14.0D),
Block.box(4.0D, 2.0D, 4.0D, 12.0D, 3.0D, 12.0D),
Block.box(5.0D, 1.0D, 5.0D, 11.0D, 2.0D, 11.0D),
Block.box(6.0D, 0.0D, 6.0D, 10.0D, 1.0D, 10.0D));
protected RoyalEggBlock(Properties properties) {
super(properties); super(properties);
this.registerDefaultState(this.stateDefinition.any().setValue(HATCH, 0)); this.registerDefaultState(this.stateDefinition.any().setValue(HATCH, 0).setValue(INVERTED, false));
} }
public abstract EntityType<? extends RoyalMountEntity> mountType(); protected abstract EntityType<? extends RoyalMountEntity> mountType();
@Override @Override
public void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) { protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(HATCH); builder.add(HATCH, INVERTED);
} }
@Override @Override
@@ -68,7 +79,16 @@ public abstract class RoyalEggBlock extends BaseEntityBlock {
@Override @Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) { public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return SHAPE; return state.getValue(INVERTED) ? INVERTED_SHAPE : SHAPE;
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
return this.defaultBlockState().setValue(INVERTED, isInvertedGravityAt(context.getLevel(), context.getClickedPos()));
}
private static boolean isInvertedGravityAt(Level level, BlockPos pos) {
return ThoraxisUndersideManager.isThoraxis(level) && pos.getY() < ThoraxisUndersideManager.GRAVITY_FLIP_Y;
} }
@Nullable @Nullable
@@ -105,7 +125,8 @@ public abstract class RoyalEggBlock extends BaseEntityBlock {
UUID placer = source == null ? null : source.getPlacerUuid(); UUID placer = source == null ? null : source.getPlacerUuid();
int hatch = state.getValue(HATCH); int hatch = state.getValue(HATCH);
level.setBlock(pos, Blocks.AIR.defaultBlockState(), 2); level.setBlock(pos, Blocks.AIR.defaultBlockState(), 2);
level.setBlock(target, state.setValue(HATCH, Math.max(0, hatch - 1)), 2); level.setBlock(target, state.setValue(HATCH, Math.max(0, hatch - 1))
.setValue(INVERTED, isInvertedGravityAt(level, target)), 2);
if (level.getBlockEntity(target) instanceof RoyalEggBlockEntity moved) { if (level.getBlockEntity(target) instanceof RoyalEggBlockEntity moved) {
moved.setPlacerUuid(placer); moved.setPlacerUuid(placer);
} }
@@ -129,6 +150,12 @@ public abstract class RoyalEggBlock extends BaseEntityBlock {
@Override @Override
public void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { public void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
boolean inverted = state.getValue(INVERTED);
if (inverted) {
tickInvertedFall(state, level, pos);
return;
}
if (!FallingBlock.isFree(level.getBlockState(pos.below())) || pos.getY() < level.getMinBuildHeight()) { if (!FallingBlock.isFree(level.getBlockState(pos.below())) || pos.getY() < level.getMinBuildHeight()) {
return; return;
} }
@@ -141,6 +168,21 @@ public abstract class RoyalEggBlock extends BaseEntityBlock {
} }
} }
private void tickInvertedFall(BlockState state, ServerLevel level, BlockPos pos) {
BlockPos above = pos.above();
if (!FallingBlock.isFree(level.getBlockState(above)) || above.getY() > level.getMaxBuildHeight()) {
return;
}
UUID placer = level.getBlockEntity(pos) instanceof RoyalEggBlockEntity egg ? egg.getPlacerUuid() : null;
level.removeBlock(pos, false);
level.setBlock(above, state, Block.UPDATE_ALL);
if (level.getBlockEntity(above) instanceof RoyalEggBlockEntity moved) {
moved.setPlacerUuid(placer);
}
level.scheduleTick(above, this, FALL_DELAY);
}
@Override @Override
public boolean isRandomlyTicking(BlockState state) { public boolean isRandomlyTicking(BlockState state) {
return true; return true;
@@ -170,7 +212,7 @@ public abstract class RoyalEggBlock extends BaseEntityBlock {
return; return;
} }
mount.moveTo(pos.getX() + 0.5D, pos.getY(), pos.getZ() + 0.5D, level.random.nextFloat() * 360.0F, 0.0F); mount.moveTo(pos.getX() + 0.5D, pos.getY(), pos.getZ() + 0.5D, level.random.nextFloat() * 360.0F, 0.0F);
mount.setBaby(true); mount.setGrowthProgress(0.0F);
mount.finalizeSpawn(level, level.getCurrentDifficultyAt(pos), MobSpawnType.BREEDING, null, null); mount.finalizeSpawn(level, level.getCurrentDifficultyAt(pos), MobSpawnType.BREEDING, null, null);
if (placer != null) { if (placer != null) {
mount.setTame(true); mount.setTame(true);
@@ -0,0 +1,244 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.entity.SkulkingFrightEntity;
import com.craisinlord.antarchy.content.block.AmberMossBlock;
import com.craisinlord.antarchy.content.block.CrawlingBlightEggBlock;
import com.craisinlord.antarchy.content.horde.CavarynHordeManager;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.tags.BlockTags;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.ambient.Bat;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.IntegerProperty;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class SkulkingFrightEggBlock extends Block {
public static final IntegerProperty HATCH = BlockStateProperties.HATCH;
public static final IntegerProperty EGGS = BlockStateProperties.EGGS;
private static final float PANIC_HATCH_CHANCE = 0.25F;
private static final double HORDE_ACCELERATION_RADIUS = 5.0D;
private static final int MAX_HATCH = 2;
private static final int MAX_EGGS = 4;
private static final VoxelShape SINGLE_SHAPE = Block.box(3.0D, 0.0D, 3.0D, 13.0D, 7.0D, 13.0D);
private static final VoxelShape MULTI_SHAPE = Block.box(1.0D, 0.0D, 1.0D, 15.0D, 7.0D, 15.0D);
public SkulkingFrightEggBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any().setValue(HATCH, 0).setValue(EGGS, 1));
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return state.getValue(EGGS) > 1 ? MULTI_SHAPE : SINGLE_SHAPE;
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return level.getBlockState(pos.below()).isFaceSturdy(level, pos.below(), Direction.UP);
}
@Override
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) {
return state.canSurvive(level, pos) ? super.updateShape(state, direction, neighborState, level, pos, neighborPos) : Blocks.AIR.defaultBlockState();
}
@Override
public boolean canBeReplaced(BlockState state, BlockPlaceContext context) {
return !context.isSecondaryUseActive()
&& context.getItemInHand().is(this.asItem())
&& state.getValue(EGGS) < MAX_EGGS;
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
BlockState existingState = context.getLevel().getBlockState(context.getClickedPos());
if (existingState.is(this)) {
return existingState.setValue(EGGS, Math.min(MAX_EGGS, existingState.getValue(EGGS) + 1));
}
return this.defaultBlockState();
}
@Override
public boolean isRandomlyTicking(BlockState state) {
return true;
}
@Override
public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (!this.shouldUpdateHatchLevel(level, pos)) {
return;
}
int hatch = state.getValue(HATCH);
if (hatch < MAX_HATCH) {
level.setBlock(pos, state.setValue(HATCH, hatch + 1), 2);
level.playSound(null, pos, SoundEvents.TURTLE_EGG_CRACK, SoundSource.BLOCKS, 0.7F, 0.95F + random.nextFloat() * 0.1F);
return;
}
this.hatchEggs(level, pos, state, random, state.getValue(EGGS));
}
@Override
public void stepOn(Level level, BlockPos pos, BlockState state, Entity entity) {
if (entity instanceof Player && !entity.isSteppingCarefully() && this.destroyEgg(level, state, pos, entity, 100)) {
if (level instanceof ServerLevel serverLevel) {
panicHatchNearby(serverLevel, pos);
}
}
super.stepOn(level, pos, state, entity);
}
@Override
public void fallOn(Level level, BlockState state, BlockPos pos, Entity entity, float fallDistance) {
this.destroyEgg(level, state, pos, entity, 3);
super.fallOn(level, state, pos, entity, fallDistance);
}
@Override
public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean isMoving) {
if (hasHatchSupport(level, pos) && !level.isClientSide) {
level.levelEvent(2012, pos, 15);
}
}
@Override
public void playerDestroy(Level level, Player player, BlockPos pos, BlockState state, BlockEntity blockEntity, net.minecraft.world.item.ItemStack stack) {
super.playerDestroy(level, player, pos, state, blockEntity, stack);
this.decreaseEggs(level, pos, state);
}
private static void panicHatchNearby(ServerLevel level, BlockPos origin) {
int radius = 6;
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
for (int dx = -radius; dx <= radius; dx++) {
for (int dy = -radius; dy <= radius; dy++) {
for (int dz = -radius; dz <= radius; dz++) {
if (dx == 0 && dy == 0 && dz == 0) continue;
mutable.set(origin.getX() + dx, origin.getY() + dy, origin.getZ() + dz);
BlockState nearby = level.getBlockState(mutable);
BlockPos immutable = mutable.immutable();
if (nearby.getBlock() instanceof SkulkingFrightEggBlock b) {
b.hatchPanickedEggs(level, immutable, nearby, level.random);
} else if (nearby.getBlock() instanceof CrawlingBlightEggBlock b) {
b.hatchPanickedEggs(level, immutable, nearby, level.random);
}
}
}
}
}
@Override
public void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(HATCH, EGGS);
}
public static boolean hasHatchSupport(BlockGetter level, BlockPos pos) {
return isSupportedGround(level, pos.below());
}
public static boolean isSupportedGround(BlockGetter level, BlockPos pos) {
return level.getBlockState(pos).is(BlockTags.SAND) || level.getBlockState(pos).blocksMotion();
}
private boolean destroyEgg(Level level, BlockState state, BlockPos pos, Entity entity, int chance) {
if (level.isClientSide || !this.canDestroyEgg(level, entity) || level.random.nextInt(chance) != 0) {
return false;
}
level.playSound(null, pos, SoundEvents.TURTLE_EGG_BREAK, SoundSource.BLOCKS, 0.7F, 0.9F + level.random.nextFloat() * 0.2F);
this.decreaseEggs(level, pos, state);
return true;
}
void hatchPanickedEggs(ServerLevel level, BlockPos pos, BlockState state, RandomSource random) {
int hatchedEggs = rollPanickedEggs(state.getValue(EGGS), random);
if (hatchedEggs <= 0) {
return;
}
this.hatchEggs(level, pos, state, random, hatchedEggs);
}
void hatchEggs(ServerLevel level, BlockPos pos, BlockState state, RandomSource random, int eggsToHatch) {
if (eggsToHatch >= state.getValue(EGGS)) {
level.removeBlock(pos, false);
} else {
level.setBlock(pos, state.setValue(EGGS, state.getValue(EGGS) - eggsToHatch), 2);
}
level.playSound(null, pos, SoundEvents.TURTLE_EGG_HATCH, SoundSource.BLOCKS, 0.75F, 0.95F + random.nextFloat() * 0.1F);
for (int i = 0; i < eggsToHatch; i++) {
SkulkingFrightEntity entity = AntarchyObjects.SKULKING_FRIGHT.get().create(level);
if (entity == null) {
continue;
}
double spawnX = pos.getX() + 0.25D + random.nextDouble() * 0.5D;
double spawnZ = pos.getZ() + 0.25D + random.nextDouble() * 0.5D;
entity.moveTo(spawnX, pos.getY() + 0.1D, spawnZ, random.nextFloat() * 360.0F, 0.0F);
level.addFreshEntity(entity);
}
}
public void hatchWithNucleus(ServerLevel level, BlockPos pos, BlockState state) {
this.hatchEggs(level, pos, state, level.random, state.getValue(EGGS));
}
private static int rollPanickedEggs(int eggs, RandomSource random) {
int hatchedEggs = 0;
for (int i = 0; i < eggs; i++) {
if (random.nextFloat() < PANIC_HATCH_CHANCE) {
hatchedEggs++;
}
}
return hatchedEggs;
}
private void decreaseEggs(Level level, BlockPos pos, BlockState state) {
int eggs = state.getValue(EGGS);
if (eggs <= 1) {
level.destroyBlock(pos, false);
return;
}
level.setBlock(pos, state.setValue(EGGS, eggs - 1), 2);
}
private boolean shouldUpdateHatchLevel(Level level, BlockPos pos) {
if (level instanceof ServerLevel serverLevel
&& CavarynHordeManager.shouldAccelerateNearbyEggHatching(serverLevel, pos, HORDE_ACCELERATION_RADIUS, level.random)) {
return true;
}
boolean onAmberMoss = level.getBlockState(pos.below()).getBlock() instanceof AmberMossBlock;
return level.random.nextInt(onAmberMoss ? 150 : 500) == 0;
}
private boolean canDestroyEgg(Level level, Entity entity) {
if (entity instanceof SkulkingFrightEntity || entity instanceof Bat) {
return false;
}
if (entity instanceof net.minecraft.world.entity.LivingEntity) {
return entity instanceof Player || level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING);
}
return false;
}
}
@@ -0,0 +1,160 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.SpringbugEntity;
import com.craisinlord.antarchy.content.horde.CavarynHordeManager;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.EntityType;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.level.block.state.properties.IntegerProperty;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class SpringbugEggBlock extends Block {
public static final IntegerProperty HATCH = BlockStateProperties.HATCH;
public static final BooleanProperty HANGING = BlockStateProperties.HANGING;
public static final BooleanProperty ROTATED = BooleanProperty.create("rotated");
private static final int MAX_HATCH = 2;
private static final double PLAYER_PROXIMITY_RADIUS = 12.0D;
private static final double HORDE_ACCELERATION_RADIUS = 5.0D;
private static final float PLAYER_PROXIMITY_HATCH_CHANCE = 0.25F;
private static final int PLAYER_PROXIMITY_CHECK_INTERVAL = 200;
private static final VoxelShape FLOOR_SHAPE = Block.box(1.5D, 0.0D, 1.5D, 14.5D, 16.0D, 14.5D);
private static final VoxelShape CEILING_SHAPE = Block.box(1.5D, 0.0D, 1.5D, 14.5D, 16.0D, 14.5D);
private static final ResourceLocation SPRINGBUG_ID = new ResourceLocation(Antarchy.MODID, "springbug");
public SpringbugEggBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any().setValue(HATCH, 0).setValue(HANGING, false).setValue(ROTATED, false));
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return state.getValue(HANGING) ? CEILING_SHAPE : FLOOR_SHAPE;
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
boolean hanging = context.getClickedFace() == Direction.DOWN
|| (context.getClickedFace() != Direction.UP && !canSupportFloor(context.getLevel(), context.getClickedPos()) && canSupportCeiling(context.getLevel(), context.getClickedPos()));
boolean rotated = context.getHorizontalDirection().getAxis() == Direction.Axis.X;
return this.defaultBlockState().setValue(HANGING, hanging).setValue(ROTATED, rotated);
}
@Override
public BlockState rotate(BlockState state, Rotation rotation) {
return rotation == Rotation.CLOCKWISE_90 || rotation == Rotation.COUNTERCLOCKWISE_90
? state.setValue(ROTATED, !state.getValue(ROTATED))
: state;
}
@Override
public BlockState mirror(BlockState state, Mirror mirror) {
return state;
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return state.getValue(HANGING) ? canSupportCeiling(level, pos) : canSupportFloor(level, pos);
}
@Override
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) {
return state.canSurvive(level, pos) ? super.updateShape(state, direction, neighborState, level, pos, neighborPos) : Blocks.AIR.defaultBlockState();
}
private static boolean canSupportFloor(LevelReader level, BlockPos pos) {
return level.getBlockState(pos.below()).isFaceSturdy(level, pos.below(), Direction.UP);
}
private static boolean canSupportCeiling(LevelReader level, BlockPos pos) {
return level.getBlockState(pos.above()).isFaceSturdy(level, pos.above(), Direction.DOWN);
}
@Override
public boolean isRandomlyTicking(BlockState state) {
return true;
}
@Override
public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (!this.shouldUpdateHatchLevel(level, pos, state)) {
return;
}
int hatch = state.getValue(HATCH);
if (hatch < MAX_HATCH) {
level.setBlock(pos, state.setValue(HATCH, hatch + 1), 2);
level.playSound(null, pos, SoundEvents.TURTLE_EGG_CRACK, SoundSource.BLOCKS, 0.7F, 0.95F + random.nextFloat() * 0.1F);
return;
}
this.hatch(level, pos, random);
}
private boolean shouldUpdateHatchLevel(Level level, BlockPos pos, BlockState state) {
if (level instanceof ServerLevel serverLevel
&& CavarynHordeManager.shouldAccelerateNearbyEggHatching(serverLevel, pos, HORDE_ACCELERATION_RADIUS, level.random)) {
return true;
}
if (level.random.nextInt(PLAYER_PROXIMITY_CHECK_INTERVAL) == 0) {
Player nearbyPlayer = level.getNearestPlayer(pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D, PLAYER_PROXIMITY_RADIUS, false);
if (nearbyPlayer != null && level.random.nextFloat() < PLAYER_PROXIMITY_HATCH_CHANCE) {
return true;
}
}
BlockPos checkPos = state.getValue(HANGING) ? pos.above() : pos.below();
boolean onAmberMoss = level.getBlockState(checkPos).getBlock() instanceof AmberMossBlock;
return level.random.nextInt(onAmberMoss ? 150 : 500) == 0;
}
private void hatch(ServerLevel level, BlockPos pos, RandomSource random) {
level.removeBlock(pos, false);
level.playSound(null, pos, SoundEvents.TURTLE_EGG_HATCH, SoundSource.BLOCKS, 0.75F, 0.95F + random.nextFloat() * 0.1F);
@SuppressWarnings("unchecked")
EntityType<SpringbugEntity> springbugType = (EntityType<SpringbugEntity>) (EntityType<?>) BuiltInRegistries.ENTITY_TYPE.getOptional(SPRINGBUG_ID).orElse(null);
if (springbugType == null) {
return;
}
SpringbugEntity entity = springbugType.create(level);
if (entity == null) {
return;
}
double spawnX = pos.getX() + 0.25D + random.nextDouble() * 0.5D;
double spawnZ = pos.getZ() + 0.25D + random.nextDouble() * 0.5D;
entity.moveTo(spawnX, pos.getY() + 0.1D, spawnZ, random.nextFloat() * 360.0F, 0.0F);
level.addFreshEntity(entity);
}
public void hatchWithNucleus(ServerLevel level, BlockPos pos) {
this.hatch(level, pos, level.random);
}
@Override
public void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(HATCH, HANGING, ROTATED);
}
}
@@ -1,76 +0,0 @@
package com.craisinlord.antarchy.content.block;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.EntityCollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
public class TriffidGooBlock extends Block {
private static final double BOUNCE_VELOCITY_THRESHOLD = 0.6;
private static final double MAX_SINK_SPEED = 0.05;
private static final double SPRINT_VELOCITY_THRESHOLD = 0.1;
public TriffidGooBlock(BlockBehaviour.Properties properties) {
super(properties);
}
public boolean isStickyBlock(BlockState state) {
return true;
}
public boolean canStickTo(BlockState state, BlockState other) {
return !other.is(Blocks.SLIME_BLOCK) && !other.is(Blocks.HONEY_BLOCK);
}
@Override
public VoxelShape getCollisionShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
if (context instanceof EntityCollisionContext ecc) {
Entity entity = ecc.getEntity();
if (entity != null) {
Vec3 delta = entity.getDeltaMovement();
double vy = delta.y;
double hSpeed = Math.sqrt(delta.x * delta.x + delta.z * delta.z);
if (vy <= 0.0 && vy > -BOUNCE_VELOCITY_THRESHOLD && hSpeed < SPRINT_VELOCITY_THRESHOLD) {
return Shapes.empty();
}
}
}
return super.getCollisionShape(state, level, pos, context);
}
@Override
public void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) {
Vec3 delta = entity.getDeltaMovement();
if (delta.y < -MAX_SINK_SPEED) {
entity.setDeltaMovement(delta.x * 0.9, -MAX_SINK_SPEED, delta.z * 0.9);
} else {
entity.setDeltaMovement(delta.x * 0.9, delta.y, delta.z * 0.9);
}
entity.fallDistance = 0.0F;
}
@Override
public void fallOn(Level level, BlockState state, BlockPos pos, Entity entity, float fallDistance) {
entity.causeFallDamage(fallDistance, 0.0F, level.damageSources().fall());
}
@Override
public void updateEntityAfterFallOn(BlockGetter level, Entity entity) {
Vec3 delta = entity.getDeltaMovement();
if (delta.y < 0.0) {
double coefficient = entity instanceof LivingEntity ? 1.0 : 0.8;
entity.setDeltaMovement(delta.x, -delta.y * coefficient, delta.z);
}
}
}
@@ -1,19 +1,24 @@
package com.craisinlord.antarchy.content.block; package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.block.entity.UnderVaultBlockEntity; import com.craisinlord.antarchy.content.block.entity.UnderVaultBlockEntity;
import com.craisinlord.antarchy.content.block.entity.undervault.UnderVaultEffects;
import com.craisinlord.antarchy.content.block.entity.undervault.UnderVaultLogic;
import com.craisinlord.antarchy.content.block.entity.undervault.UnderVaultState;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.BaseEntityBlock; import net.minecraft.world.level.block.BaseEntityBlock;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.HorizontalDirectionalBlock;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.RenderShape; import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker; import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
@@ -22,33 +27,58 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BooleanProperty; import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.level.block.state.properties.DirectionProperty; import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.level.block.state.properties.EnumProperty;
import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.resources.ResourceLocation;
import java.util.function.Supplier; import java.util.function.Supplier;
public final class UnderVaultBlock extends BaseEntityBlock { public final class UnderVaultBlock extends BaseEntityBlock {
public static final DirectionProperty FACING = DirectionProperty.create("facing"); public static final EnumProperty<UnderVaultState> STATE = EnumProperty.create("vault_state", UnderVaultState.class);
public static final BooleanProperty ACTIVE = BooleanProperty.create("active"); public static final DirectionProperty FACING = HorizontalDirectionalBlock.FACING;
public static final BooleanProperty OMINOUS = BooleanProperty.create("ominous");
public static final DirectionProperty UNDER_FACING = DirectionProperty.create("under_facing", Direction.values());
private final Supplier<? extends BlockEntityType<UnderVaultBlockEntity>> blockEntityType; private final Supplier<? extends BlockEntityType<UnderVaultBlockEntity>> blockEntityType;
public UnderVaultBlock(Supplier<? extends BlockEntityType<UnderVaultBlockEntity>> blockEntityType, public UnderVaultBlock(Supplier<? extends BlockEntityType<UnderVaultBlockEntity>> blockEntityType, BlockBehaviour.Properties properties) {
BlockBehaviour.Properties properties) { super(properties.lightLevel(UnderVaultBlock::lightLevel));
super(properties);
this.blockEntityType = blockEntityType; this.blockEntityType = blockEntityType;
registerDefaultState(stateDefinition.any().setValue(FACING, Direction.DOWN).setValue(ACTIVE, true)); this.registerDefaultState(this.stateDefinition.any()
.setValue(FACING, Direction.NORTH)
.setValue(STATE, UnderVaultState.INACTIVE)
.setValue(OMINOUS, false)
.setValue(UNDER_FACING, Direction.NORTH));
}
public static int lightLevel(BlockState state) {
return state.getValue(STATE).lightLevel();
} }
@Override @Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) { protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(FACING, ACTIVE); builder.add(FACING, STATE, OMINOUS);
builder.add(UNDER_FACING);
} }
@Override @Override
public BlockState getStateForPlacement(net.minecraft.world.item.context.BlockPlaceContext context) { public BlockState getStateForPlacement(BlockPlaceContext context) {
return context.getClickedFace() == Direction.DOWN if (context.getClickedFace() != Direction.DOWN) {
? defaultBlockState().setValue(FACING, Direction.DOWN) return null;
: null; }
return this.defaultBlockState()
.setValue(FACING, context.getHorizontalDirection().getOpposite())
.setValue(UNDER_FACING, Direction.DOWN);
}
@Override
public BlockState rotate(BlockState state, Rotation rotation) {
BlockState rotated = state.setValue(FACING, rotation.rotate(state.getValue(FACING)));
return rotated.setValue(UNDER_FACING, rotation.rotate(state.getValue(UNDER_FACING)));
}
@Override
public BlockState mirror(BlockState state, Mirror mirror) {
BlockState mirrored = state.rotate(mirror.getRotation(state.getValue(FACING)));
return mirrored.setValue(UNDER_FACING, mirror.getRotation(state.getValue(UNDER_FACING)).rotate(state.getValue(UNDER_FACING)));
} }
@Override @Override
@@ -62,29 +92,41 @@ public final class UnderVaultBlock extends BaseEntityBlock {
} }
@Override @Override
public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand,
InteractionHand hand, BlockHitResult hit) { BlockHitResult hitResult) {
ItemStack stack = player.getItemInHand(hand); ItemStack stack = player.getItemInHand(hand);
if (!state.getValue(ACTIVE) || !isKey(stack)) { if (stack.isEmpty() || state.getValue(STATE) != UnderVaultState.ACTIVE) {
return InteractionResult.PASS; return InteractionResult.PASS;
} }
if (!level.isClientSide && level instanceof ServerLevel serverLevel if (level instanceof ServerLevel serverLevel
&& level.getBlockEntity(pos) instanceof UnderVaultBlockEntity vault) { && level.getBlockEntity(pos) instanceof UnderVaultBlockEntity underVault) {
if (vault.unlock(serverLevel, pos, player, stack)) { UnderVaultLogic.Server.tryInsertKey(
level.setBlock(pos, state.setValue(ACTIVE, false), Block.UPDATE_ALL); serverLevel, pos, state, underVault.getVaultData().getConfig(),
return InteractionResult.CONSUME; underVault.getVaultData().getServerData(), underVault.getVaultData().getSharedData(),
} player, stack);
return InteractionResult.SUCCESS;
} }
return InteractionResult.sidedSuccess(level.isClientSide); return level.isClientSide ? InteractionResult.CONSUME : InteractionResult.PASS;
}
private static boolean isKey(ItemStack stack) {
return stack.is(BuiltInRegistries.ITEM.get(new ResourceLocation(Antarchy.MODID, "undertrial_key")));
} }
@Override @Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, public boolean triggerEvent(BlockState state, Level level, BlockPos pos, int id, int param) {
BlockEntityType<T> type) { return UnderVaultEffects.handle(level, pos, id, param);
return createTickerHelper(type, blockEntityType.get(), UnderVaultBlockEntity::tick); }
@Override
@SuppressWarnings("unchecked")
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> type) {
if (this.blockEntityType == null || type != this.blockEntityType.get()) {
return null;
}
if (level.isClientSide) {
return (BlockEntityTicker<T>) (BlockEntityTicker<UnderVaultBlockEntity>) UnderVaultBlockEntity::clientTick;
}
return (BlockEntityTicker<T>) (BlockEntityTicker<UnderVaultBlockEntity>) ((serverLevel, pos, blockState, blockEntity) -> {
if (serverLevel instanceof ServerLevel levelServer) {
UnderVaultBlockEntity.serverTick(levelServer, pos, blockState, blockEntity);
}
});
} }
} }
@@ -1,8 +1,16 @@
package com.craisinlord.antarchy.content.block; package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.block.entity.UndertrialSpawnerBlockEntity; import com.craisinlord.antarchy.content.block.entity.UndertrialSpawnerBlockEntity;
import com.craisinlord.antarchy.content.block.entity.undertrial.UndertrialSpawnerEffects;
import com.craisinlord.antarchy.content.block.entity.undertrial.UndertrialSpawnerState;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.SpawnEggItem;
import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.BaseEntityBlock; import net.minecraft.world.level.block.BaseEntityBlock;
@@ -15,29 +23,36 @@ import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BooleanProperty; import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.level.block.state.properties.EnumProperty;
import net.minecraft.world.phys.BlockHitResult;
import java.util.function.Supplier; import java.util.function.Supplier;
public final class UndertrialSpawnerBlock extends BaseEntityBlock { public final class UndertrialSpawnerBlock extends BaseEntityBlock {
public static final BooleanProperty ACTIVE = BooleanProperty.create("active"); public static final EnumProperty<UndertrialSpawnerState> STATE = EnumProperty.create("trial_spawner_state", UndertrialSpawnerState.class);
public static final BooleanProperty OMINOUS = BooleanProperty.create("ominous"); public static final BooleanProperty OMINOUS = BooleanProperty.create("ominous");
private final Supplier<? extends BlockEntityType<UndertrialSpawnerBlockEntity>> blockEntityType; private final Supplier<? extends BlockEntityType<UndertrialSpawnerBlockEntity>> blockEntityType;
public UndertrialSpawnerBlock(Supplier<? extends BlockEntityType<UndertrialSpawnerBlockEntity>> blockEntityType, public UndertrialSpawnerBlock(Supplier<? extends BlockEntityType<UndertrialSpawnerBlockEntity>> blockEntityType, BlockBehaviour.Properties properties) {
BlockBehaviour.Properties properties) { super(properties.lightLevel(UndertrialSpawnerBlock::lightLevel));
super(properties);
this.blockEntityType = blockEntityType; this.blockEntityType = blockEntityType;
registerDefaultState(stateDefinition.any().setValue(ACTIVE, false).setValue(OMINOUS, false)); this.registerDefaultState(this.stateDefinition.any()
.setValue(STATE, UndertrialSpawnerState.INACTIVE)
.setValue(OMINOUS, false));
}
public static int lightLevel(BlockState state) {
return state.getValue(STATE).lightLevel();
} }
@Override @Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) { protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(ACTIVE, OMINOUS); builder.add(STATE, OMINOUS);
} }
@Override @Override
public BlockState getStateForPlacement(BlockPlaceContext context) { public BlockState getStateForPlacement(BlockPlaceContext context) {
return context.getClickedFace() == Direction.DOWN ? defaultBlockState() : null; return context.getClickedFace() == Direction.DOWN ? this.defaultBlockState() : null;
} }
@Override @Override
@@ -51,8 +66,35 @@ public final class UndertrialSpawnerBlock extends BaseEntityBlock {
} }
@Override @Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand,
BlockEntityType<T> type) { BlockHitResult hitResult) {
return createTickerHelper(type, blockEntityType.get(), UndertrialSpawnerBlockEntity::tick); ItemStack stack = player.getItemInHand(hand);
if (!(stack.getItem() instanceof SpawnEggItem)) {
return InteractionResult.PASS;
}
if (level.getBlockEntity(pos) instanceof UndertrialSpawnerBlockEntity spawner) {
if (!level.isClientSide) {
spawner.setSpawnEntity(((SpawnEggItem) stack.getItem()).getType(stack.getTag()));
}
return InteractionResult.sidedSuccess(level.isClientSide);
}
return InteractionResult.PASS;
}
@Override
public boolean triggerEvent(BlockState state, Level level, BlockPos pos, int id, int param) {
return UndertrialSpawnerEffects.handle(level, pos, id, param);
}
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> blockEntityType) {
if (level.isClientSide) {
return createTickerHelper(blockEntityType, this.blockEntityType.get(), UndertrialSpawnerBlockEntity::clientTick);
}
return createTickerHelper(blockEntityType, this.blockEntityType.get(), (tickLevel, tickPos, tickState, blockEntity) -> {
if (tickLevel instanceof ServerLevel serverLevel) {
UndertrialSpawnerBlockEntity.serverTick(serverLevel, tickPos, tickState, blockEntity);
}
});
} }
} }
@@ -41,6 +41,28 @@ public class AntNestBlockEntity extends BlockEntity {
} }
public static void serverTick(ServerLevel level, BlockPos pos, BlockState state, AntNestBlockEntity nest) { public static void serverTick(ServerLevel level, BlockPos pos, BlockState state, AntNestBlockEntity nest) {
if (state.getBlock() instanceof com.craisinlord.antarchy.content.block.AntTrapBlock) {
if (level.getGameTime() % 20L == 0L && nest.storedAnts.size() < nest.maxOccupants()) {
net.minecraft.world.phys.AABB searchArea = new net.minecraft.world.phys.AABB(pos).inflate(15.0D);
for (BaseAntEntity ant : level.getEntitiesOfClass(BaseAntEntity.class, searchArea, BaseAntEntity::isAlive)) {
if (ant.distanceToSqr(net.minecraft.world.phys.Vec3.atCenterOf(pos)) > 225.0D) {
continue;
}
if (!nest.canAccept(ant.getType())) {
continue;
}
if (ant.distanceToSqr(net.minecraft.world.phys.Vec3.atCenterOf(pos)) <= 2.25D) {
nest.tryStoreAnt(ant);
if (nest.storedAnts.size() >= nest.maxOccupants()) {
break;
}
} else {
ant.getNavigation().moveTo(pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D, 1.05D);
}
}
}
return;
}
boolean playerNearby = level.hasNearbyAlivePlayer( boolean playerNearby = level.hasNearbyAlivePlayer(
pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D, PLAYER_ACTIVATION_RANGE); pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D, PLAYER_ACTIVATION_RANGE);
if (!playerNearby) { if (!playerNearby) {
@@ -116,12 +138,17 @@ public class AntNestBlockEntity extends BlockEntity {
} }
public void releaseAll(ServerLevel level) { public void releaseAll(ServerLevel level) {
while (!this.storedAnts.isEmpty()) { int remaining = this.storedAnts.size();
this.releaseOne(level); while (remaining-- > 0 && !this.storedAnts.isEmpty()) {
this.releaseOne(level, true);
} }
} }
private void releaseOne(ServerLevel level) { private void releaseOne(ServerLevel level) {
this.releaseOne(level, false);
}
private void releaseOne(ServerLevel level, boolean forceRelease) {
if (this.storedAnts.isEmpty()) { if (this.storedAnts.isEmpty()) {
return; return;
} }
@@ -133,20 +160,39 @@ public class AntNestBlockEntity extends BlockEntity {
return; return;
} }
BlockPos spawnPos = this.getBlockPos().above(); BlockPos origin = this.getBlockPos();
if (!level.getBlockState(spawnPos).canBeReplaced()) { java.util.List<BlockPos> candidates = new java.util.ArrayList<>();
for (int y = 1; y <= 3; y++) {
candidates.add(origin.above(y));
for (int radius = 1; radius <= 2; radius++) {
candidates.add(origin.offset(radius, y, 0));
candidates.add(origin.offset(-radius, y, 0));
candidates.add(origin.offset(0, y, radius));
candidates.add(origin.offset(0, y, -radius));
}
}
BlockPos spawnPos = null;
for (BlockPos candidate : candidates) {
antEntity.moveTo(candidate.getX() + SPAWN_OFFSET_XZ, candidate.getY() + SPAWN_OFFSET_Y, candidate.getZ() + SPAWN_OFFSET_XZ,
level.random.nextFloat() * 360.0F, 0.0F);
if (level.noCollision(antEntity)) {
spawnPos = candidate;
break;
}
}
if (spawnPos == null && !forceRelease) {
return; return;
} }
if (spawnPos == null) {
antEntity.moveTo(spawnPos.getX() + SPAWN_OFFSET_XZ, spawnPos.getY() + SPAWN_OFFSET_Y, spawnPos.getZ() + SPAWN_OFFSET_XZ, level.random.nextFloat() * 360.0F, 0.0F); antEntity.moveTo(origin.getX() + SPAWN_OFFSET_XZ, origin.getY() + SPAWN_OFFSET_Y, origin.getZ() + SPAWN_OFFSET_XZ,
if (!level.noCollision(antEntity)) { level.random.nextFloat() * 360.0F, 0.0F);
return;
} }
antEntity.setNestPos(origin);
this.storedAnts.remove(0);
antEntity.setNestPos(this.getBlockPos());
antEntity.onExitNest(); antEntity.onExitNest();
level.addFreshEntity(antEntity); if (!level.addFreshEntity(antEntity) && !forceRelease) {
return;
}
this.storedAnts.remove(0);
this.setChanged(); this.setChanged();
} }
@@ -5,6 +5,7 @@ import com.craisinlord.antarchy.content.entity.portal.DimensionalTearEntity;
import java.util.function.Supplier; import java.util.function.Supplier;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.HolderLookup; import net.minecraft.core.HolderLookup;
import net.minecraft.core.SectionPos;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;
@@ -12,6 +13,7 @@ import net.minecraft.util.RandomSource;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -139,14 +141,21 @@ public class DimensionalTearMarkerBlockEntity extends BlockEntity {
if (pos.getY() < minY || pos.getY() > maxY) { if (pos.getY() < minY || pos.getY() > maxY) {
return false; return false;
} }
BlockPos.MutableBlockPos checkPos = new BlockPos.MutableBlockPos();
LevelChunk chunk = null;
for (int dx = -2; dx <= 2; dx++) { for (int dx = -2; dx <= 2; dx++) {
for (int dy = -2; dy <= 3; dy++) { for (int dz = -4; dz <= 4; dz++) {
for (int dz = -4; dz <= 4; dz++) { int chunkX = SectionPos.blockToSectionCoord(pos.getX() + dx);
BlockPos checkPos = pos.offset(dx, dy, dz); int chunkZ = SectionPos.blockToSectionCoord(pos.getZ() + dz);
if (!level.isLoaded(checkPos)) { if (chunk == null || chunk.getPos().x != chunkX || chunk.getPos().z != chunkZ) {
chunk = level.getChunkSource().getChunkNow(chunkX, chunkZ);
if (chunk == null) {
return false; return false;
} }
if (!level.getBlockState(checkPos).getCollisionShape(level, checkPos).isEmpty()) { }
for (int dy = -2; dy <= 3; dy++) {
checkPos.set(pos.getX() + dx, pos.getY() + dy, pos.getZ() + dz);
if (!chunk.getBlockState(checkPos).getCollisionShape(level, checkPos).isEmpty()) {
return false; return false;
} }
} }
@@ -1,6 +1,8 @@
package com.craisinlord.antarchy.content.block.entity; package com.craisinlord.antarchy.content.block.entity;
import com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity; import com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity;
import java.util.EnumMap;
import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.function.Supplier; import java.util.function.Supplier;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
@@ -14,7 +16,8 @@ import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
public class PortalGunPortalBaseBlockEntity extends BlockEntity { public class PortalGunPortalBaseBlockEntity extends BlockEntity implements PortalGunPortalCellAccess {
private final Map<net.minecraft.core.Direction, PortalGunPortalFaceRecord> faceRecords = new EnumMap<>(net.minecraft.core.Direction.class);
private UUID ownerId; private UUID ownerId;
private UUID portalId; private UUID portalId;
private PortalGunPortalEntity.PortalSide side = PortalGunPortalEntity.PortalSide.BLUE; private PortalGunPortalEntity.PortalSide side = PortalGunPortalEntity.PortalSide.BLUE;
@@ -26,6 +29,11 @@ public class PortalGunPortalBaseBlockEntity extends BlockEntity {
super(typeSupplier.get(), pos, state); super(typeSupplier.get(), pos, state);
} }
@Override
public Map<net.minecraft.core.Direction, PortalGunPortalFaceRecord> portalGun$getFaceRecords() {
return this.faceRecords;
}
public void configure(UUID ownerId, UUID portalId, PortalGunPortalEntity.PortalSide side, BlockPos masterPos) { public void configure(UUID ownerId, UUID portalId, PortalGunPortalEntity.PortalSide side, BlockPos masterPos) {
this.ownerId = ownerId; this.ownerId = ownerId;
this.portalId = portalId; this.portalId = portalId;
@@ -61,6 +69,11 @@ public class PortalGunPortalBaseBlockEntity extends BlockEntity {
public void updatePair(UUID linkedPortalId, int pairTime) { public void updatePair(UUID linkedPortalId, int pairTime) {
this.linkedPortalId = linkedPortalId; this.linkedPortalId = linkedPortalId;
this.pairTime = pairTime; this.pairTime = pairTime;
for (PortalGunPortalFaceRecord record : java.util.List.copyOf(this.faceRecords.values())) {
if (record.portalId().equals(this.portalId)) {
this.portalGun$putFaceRecord(record.withPair(linkedPortalId, pairTime));
}
}
this.setChanged(); this.setChanged();
} }
@@ -69,11 +82,20 @@ public class PortalGunPortalBaseBlockEntity extends BlockEntity {
} }
public void onBroken() { public void onBroken() {
if (!(this.level instanceof ServerLevel serverLevel) || this.portalId == null) { if (!(this.level instanceof ServerLevel serverLevel)) {
return; return;
} }
if (serverLevel.getEntity(this.portalId) instanceof PortalGunPortalEntity portal && !portal.isRemoved()) { java.util.Set<UUID> portalIds = new java.util.HashSet<>();
portal.discard(); if (this.portalId != null) {
portalIds.add(this.portalId);
}
for (PortalGunPortalFaceRecord record : this.faceRecords.values()) {
portalIds.add(record.portalId());
}
for (UUID id : portalIds) {
if (serverLevel.getEntity(id) instanceof PortalGunPortalEntity portal && !portal.isRemoved()) {
portal.discard();
}
} }
} }
@@ -81,15 +103,28 @@ public class PortalGunPortalBaseBlockEntity extends BlockEntity {
if (((level.getGameTime() + pos.asLong()) & 15L) != 0L) { if (((level.getGameTime() + pos.asLong()) & 15L) != 0L) {
return; return;
} }
if (level.getBlockEntity(blockEntity.masterPos) instanceof PortalGunPortalMasterBlockEntity master
&& master.matches(blockEntity.ownerId, blockEntity.portalId, blockEntity.side)) {
PortalGunPortalFaceRecord masterRecord = master.portalGun$getFaceRecord(master.getFacing(), blockEntity.portalId);
if (masterRecord != null && blockEntity.portalGun$getFaceRecord(masterRecord.face(), masterRecord.portalId()) == null) {
blockEntity.portalGun$putFaceRecord(masterRecord.withMaster(false));
}
}
blockEntity.portalGun$restoreMasterFaces(level, pos);
if (blockEntity.portalId != null
&& !(level.getEntity(blockEntity.portalId) instanceof PortalGunPortalEntity)
&& blockEntity.faceRecords.values().stream().anyMatch(record -> !record.portalId().equals(blockEntity.portalId))) {
return;
}
if (!(level.getBlockEntity(blockEntity.masterPos) instanceof PortalGunPortalMasterBlockEntity master) if (!(level.getBlockEntity(blockEntity.masterPos) instanceof PortalGunPortalMasterBlockEntity master)
|| !master.matches(blockEntity.ownerId, blockEntity.portalId, blockEntity.side) || !master.matches(blockEntity.ownerId, blockEntity.portalId, blockEntity.side)
|| !pos.equals(master.getBasePos())) { || !master.containsPortalSpot(pos)) {
level.removeBlock(pos, false); level.removeBlock(pos, false);
return; return;
} }
if (!(level.getEntity(blockEntity.portalId) instanceof PortalGunPortalEntity portal) if (!(level.getEntity(blockEntity.portalId) instanceof PortalGunPortalEntity portal)
|| portal.isRemoved() || portal.isRemoved()
|| !pos.equals(portal.getBasePos()) || !portal.containsPortalSpot(pos)
|| blockEntity.ownerId == null || blockEntity.ownerId == null
|| !blockEntity.ownerId.equals(portal.getOwnerId()) || !blockEntity.ownerId.equals(portal.getOwnerId())
|| blockEntity.side != portal.getPortalSide()) { || blockEntity.side != portal.getPortalSide()) {
@@ -123,6 +158,7 @@ public class PortalGunPortalBaseBlockEntity extends BlockEntity {
tag.putInt("MasterY", this.masterPos.getY()); tag.putInt("MasterY", this.masterPos.getY());
tag.putInt("MasterZ", this.masterPos.getZ()); tag.putInt("MasterZ", this.masterPos.getZ());
tag.putInt("PairTime", this.pairTime); tag.putInt("PairTime", this.pairTime);
this.portalGun$saveFaceRecords(tag);
} }
@Override @Override
@@ -134,6 +170,7 @@ public class PortalGunPortalBaseBlockEntity extends BlockEntity {
this.side = tag.getInt("Side") == PortalGunPortalEntity.PortalSide.ORANGE.ordinal() ? PortalGunPortalEntity.PortalSide.ORANGE : PortalGunPortalEntity.PortalSide.BLUE; this.side = tag.getInt("Side") == PortalGunPortalEntity.PortalSide.ORANGE.ordinal() ? PortalGunPortalEntity.PortalSide.ORANGE : PortalGunPortalEntity.PortalSide.BLUE;
this.masterPos = new BlockPos(tag.getInt("MasterX"), tag.getInt("MasterY"), tag.getInt("MasterZ")); this.masterPos = new BlockPos(tag.getInt("MasterX"), tag.getInt("MasterY"), tag.getInt("MasterZ"));
this.pairTime = tag.getInt("PairTime"); this.pairTime = tag.getInt("PairTime");
this.portalGun$loadFaceRecords(tag);
} }
@Override @Override
@@ -0,0 +1,117 @@
package com.craisinlord.antarchy.content.block.entity;
import com.craisinlord.antarchy.content.portalgun.PortalGunPlacement;
import com.craisinlord.antarchy.content.portalgun.PortalGunSavedData;
import java.util.Map;
import java.util.UUID;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
public interface PortalGunPortalCellAccess {
Map<Direction, PortalGunPortalFaceRecord> portalGun$getFaceRecords();
default PortalGunPortalFaceRecord portalGun$getFaceRecord(Direction face) {
return this.portalGun$getFaceRecords().get(face);
}
default PortalGunPortalFaceRecord portalGun$getFaceRecord(Direction face, UUID portalId) {
PortalGunPortalFaceRecord record = this.portalGun$getFaceRecord(face);
return record != null && record.portalId().equals(portalId) ? record : null;
}
default boolean portalGun$putFaceRecord(PortalGunPortalFaceRecord record) {
PortalGunPortalFaceRecord existing = this.portalGun$getFaceRecord(record.face());
if (existing != null
&& (!java.util.Objects.equals(existing.gunId(), record.gunId())
|| existing.side() != record.side())) {
return false;
}
this.portalGun$getFaceRecords().put(record.face(), record);
if (this instanceof net.minecraft.world.level.block.entity.BlockEntity blockEntity) {
blockEntity.setChanged();
}
return true;
}
default PortalGunPortalFaceRecord portalGun$removeFaceRecord(Direction face, UUID portalId) {
PortalGunPortalFaceRecord existing = this.portalGun$getFaceRecord(face, portalId);
if (existing == null) {
return null;
}
PortalGunPortalFaceRecord removed = this.portalGun$getFaceRecords().remove(face);
if (this instanceof net.minecraft.world.level.block.entity.BlockEntity blockEntity) {
blockEntity.setChanged();
}
return removed;
}
default void portalGun$updateFacePair(UUID portalId, UUID linkedPortalId, int pairTime) {
for (PortalGunPortalFaceRecord record : java.util.List.copyOf(this.portalGun$getFaceRecords().values())) {
if (record.portalId().equals(portalId)) {
this.portalGun$putFaceRecord(record.withPair(linkedPortalId, pairTime));
}
}
}
default void portalGun$restoreMasterFaces(ServerLevel level, BlockPos pos) {
for (PortalGunPortalFaceRecord record : java.util.List.copyOf(this.portalGun$getFaceRecords().values())) {
if (record.ownerId() == null || record.portalId() == null) {
continue;
}
if (!PortalGunSavedData.isRegistered(level, record.gunId(), record.side(), record.portalId())) {
this.portalGun$removeFaceRecord(record.face(), record.portalId());
continue;
}
if (!record.master() || !record.masterPos().equals(pos)) {
continue;
}
boolean complete = !record.portalSpots().isEmpty() && record.portalSpots().get(0).equals(record.masterPos());
for (int i = 0; complete && i < record.portalSpots().size(); i++) {
BlockPos spot = record.portalSpots().get(i);
BlockPos support = spot.relative(record.face().getOpposite());
if (!level.hasChunkAt(spot) || !level.hasChunkAt(support)
|| !level.getBlockState(support).isFaceSturdy(level, support, record.face())
|| !(level.getBlockEntity(spot) instanceof PortalGunPortalCellAccess cell)) {
complete = false;
continue;
}
PortalGunPortalFaceRecord footprintRecord = cell.portalGun$getFaceRecord(record.face(), record.portalId());
complete = footprintRecord != null && footprintRecord.master() == (i == 0);
}
complete = complete && PortalGunPlacement.isRectangularFootprint(
record.portalSpots().toArray(BlockPos[]::new),
record.face(),
record.upAxis(),
record.portalWidth(),
record.portalHeight()
);
if (complete) {
PortalGunPortalMasterBlockEntity.restorePortalEntity(level, record);
}
}
}
default void portalGun$saveFaceRecords(CompoundTag tag) {
ListTag faces = new ListTag();
for (PortalGunPortalFaceRecord record : this.portalGun$getFaceRecords().values()) {
faces.add(record.save());
}
tag.put("PortalFaces", faces);
}
default void portalGun$loadFaceRecords(CompoundTag tag) {
Map<Direction, PortalGunPortalFaceRecord> records = this.portalGun$getFaceRecords();
records.clear();
ListTag faces = tag.getList("PortalFaces", Tag.TAG_COMPOUND);
for (int i = 0; i < faces.size(); i++) {
PortalGunPortalFaceRecord record = PortalGunPortalFaceRecord.load(faces.getCompound(i));
if (record != null) {
records.put(record.face(), record);
}
}
}
}
@@ -0,0 +1,149 @@
package com.craisinlord.antarchy.content.block.entity;
import com.craisinlord.antarchy.content.portalgun.PortalGunPlacement;
import com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity;
import com.craisinlord.antarchy.content.portalgun.PortalGunVariant;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
public record PortalGunPortalFaceRecord(
UUID ownerId,
UUID gunId,
PortalGunVariant variant,
UUID portalId,
UUID linkedPortalId,
PortalGunPortalEntity.PortalSide side,
Direction face,
Direction upAxis,
BlockPos masterPos,
BlockPos basePos,
List<BlockPos> portalSpots,
Set<BlockPos> compensatedSpots,
int pairTime,
int portalWidth,
int portalHeight,
boolean master
) {
public PortalGunPortalFaceRecord {
masterPos = masterPos.immutable();
basePos = basePos.immutable();
portalSpots = portalSpots.stream().map(BlockPos::immutable).toList();
compensatedSpots = Set.copyOf(compensatedSpots);
}
public PortalGunPlacement placement() {
return PortalGunPlacement.fromStored(this.face, this.upAxis, this.masterPos, this.basePos, this.portalSpots.toArray(BlockPos[]::new), this.compensatedSpots, this.portalWidth, this.portalHeight);
}
public PortalGunPortalFaceRecord withPair(UUID linkedPortalId, int pairTime) {
return new PortalGunPortalFaceRecord(this.ownerId, this.gunId, this.variant, this.portalId, linkedPortalId, this.side, this.face, this.upAxis, this.masterPos, this.basePos, this.portalSpots, this.compensatedSpots, pairTime, this.portalWidth, this.portalHeight, this.master);
}
public PortalGunPortalFaceRecord withMaster(boolean master) {
return new PortalGunPortalFaceRecord(this.ownerId, this.gunId, this.variant, this.portalId, this.linkedPortalId, this.side, this.face, this.upAxis, this.masterPos, this.basePos, this.portalSpots, this.compensatedSpots, this.pairTime, this.portalWidth, this.portalHeight, master);
}
public CompoundTag save() {
CompoundTag tag = new CompoundTag();
tag.putUUID("OwnerId", this.ownerId);
if (this.gunId != null) {
tag.putUUID("GunId", this.gunId);
}
tag.putInt("Variant", this.variant.id());
tag.putUUID("PortalId", this.portalId);
if (this.linkedPortalId != null) {
tag.putUUID("LinkedPortalId", this.linkedPortalId);
}
tag.putInt("Side", this.side.ordinal());
tag.putInt("Face", this.face.get3DDataValue());
tag.putInt("UpAxis", this.upAxis.get3DDataValue());
putPos(tag, "Master", this.masterPos);
putPos(tag, "Base", this.basePos);
tag.putInt("PairTime", this.pairTime);
tag.putInt("PortalWidth", this.portalWidth);
tag.putInt("PortalHeight", this.portalHeight);
tag.putBoolean("MasterRole", this.master);
ListTag spots = new ListTag();
for (BlockPos pos : this.portalSpots) {
spots.add(savePos(pos));
}
tag.put("PortalSpots", spots);
ListTag compensated = new ListTag();
for (BlockPos pos : this.compensatedSpots) {
compensated.add(savePos(pos));
}
tag.put("CompensatedSpots", compensated);
return tag;
}
public static PortalGunPortalFaceRecord load(CompoundTag tag) {
if (!tag.hasUUID("OwnerId") || !tag.hasUUID("PortalId")) {
return null;
}
ListTag spotsTag = tag.getList("PortalSpots", Tag.TAG_COMPOUND);
List<BlockPos> spots = new java.util.ArrayList<>(spotsTag.size());
for (int i = 0; i < spotsTag.size(); i++) {
spots.add(loadPos(spotsTag.getCompound(i)));
}
ListTag compensatedTag = tag.getList("CompensatedSpots", Tag.TAG_COMPOUND);
Set<BlockPos> compensated = new HashSet<>();
for (int i = 0; i < compensatedTag.size(); i++) {
compensated.add(loadPos(compensatedTag.getCompound(i)));
}
PortalGunPortalEntity.PortalSide side = tag.getInt("Side") == PortalGunPortalEntity.PortalSide.ORANGE.ordinal()
? PortalGunPortalEntity.PortalSide.ORANGE
: PortalGunPortalEntity.PortalSide.BLUE;
int width = net.minecraft.util.Mth.clamp(tag.getInt("PortalWidth"), 1, 16);
int height = net.minecraft.util.Mth.clamp(tag.getInt("PortalHeight"), 2, 16);
return new PortalGunPortalFaceRecord(
tag.getUUID("OwnerId"),
tag.hasUUID("GunId") ? tag.getUUID("GunId") : null,
PortalGunVariant.byId(tag.getInt("Variant")),
tag.getUUID("PortalId"),
tag.hasUUID("LinkedPortalId") ? tag.getUUID("LinkedPortalId") : null,
side,
Direction.from3DDataValue(tag.getInt("Face")),
Direction.from3DDataValue(tag.getInt("UpAxis")),
getPos(tag, "Master"),
getPos(tag, "Base"),
spots,
compensated,
tag.getInt("PairTime"),
width,
height,
tag.getBoolean("MasterRole")
);
}
private static void putPos(CompoundTag tag, String key, BlockPos pos) {
CompoundTag value = new CompoundTag();
value.putInt("X", pos.getX());
value.putInt("Y", pos.getY());
value.putInt("Z", pos.getZ());
tag.put(key, value);
}
private static BlockPos getPos(CompoundTag tag, String key) {
CompoundTag value = tag.getCompound(key);
return new BlockPos(value.getInt("X"), value.getInt("Y"), value.getInt("Z"));
}
private static CompoundTag savePos(BlockPos pos) {
CompoundTag tag = new CompoundTag();
tag.putInt("X", pos.getX());
tag.putInt("Y", pos.getY());
tag.putInt("Z", pos.getZ());
return tag;
}
private static BlockPos loadPos(CompoundTag tag) {
return new BlockPos(tag.getInt("X"), tag.getInt("Y"), tag.getInt("Z"));
}
}
@@ -4,15 +4,17 @@ import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity; import com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity;
import com.craisinlord.antarchy.content.portalgun.PortalGunPlacement; import com.craisinlord.antarchy.content.portalgun.PortalGunPlacement;
import com.craisinlord.antarchy.content.portalgun.PortalGunSavedData; import com.craisinlord.antarchy.content.portalgun.PortalGunSavedData;
import com.craisinlord.antarchy.content.portalgun.PortalGunVariant;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.function.Supplier; import java.util.function.Supplier;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag; import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
@@ -30,14 +32,19 @@ import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
public class PortalGunPortalMasterBlockEntity extends BlockEntity { public class PortalGunPortalMasterBlockEntity extends BlockEntity implements PortalGunPortalCellAccess {
private final Map<Direction, PortalGunPortalFaceRecord> faceRecords = new EnumMap<>(Direction.class);
private UUID ownerId; private UUID ownerId;
private UUID gunId;
private PortalGunVariant variant = PortalGunVariant.DEFAULT;
private UUID portalId; private UUID portalId;
private PortalGunPortalEntity.PortalSide side = PortalGunPortalEntity.PortalSide.BLUE; private PortalGunPortalEntity.PortalSide side = PortalGunPortalEntity.PortalSide.BLUE;
private Direction facing = Direction.NORTH; private Direction facing = Direction.NORTH;
private Direction upAxis = Direction.UP; private Direction upAxis = Direction.UP;
private BlockPos basePos = BlockPos.ZERO; private BlockPos basePos = BlockPos.ZERO;
private BlockPos[] portalSpots = new BlockPos[] {BlockPos.ZERO, BlockPos.ZERO}; private BlockPos[] portalSpots = new BlockPos[] {BlockPos.ZERO, BlockPos.ZERO};
private int portalWidth = 1;
private int portalHeight = 2;
private Set<BlockPos> compensatedSpots = Set.of(); private Set<BlockPos> compensatedSpots = Set.of();
private UUID linkedPortalId; private UUID linkedPortalId;
private int pairTime; private int pairTime;
@@ -48,6 +55,8 @@ public class PortalGunPortalMasterBlockEntity extends BlockEntity {
public void configure( public void configure(
UUID ownerId, UUID ownerId,
UUID gunId,
PortalGunVariant variant,
UUID portalId, UUID portalId,
PortalGunPortalEntity.PortalSide side, PortalGunPortalEntity.PortalSide side,
Direction facing, Direction facing,
@@ -55,20 +64,32 @@ public class PortalGunPortalMasterBlockEntity extends BlockEntity {
BlockPos basePos, BlockPos basePos,
BlockPos[] portalSpots, BlockPos[] portalSpots,
Set<BlockPos> compensatedSpots, Set<BlockPos> compensatedSpots,
int pairTime int pairTime,
int portalWidth,
int portalHeight
) { ) {
this.ownerId = ownerId; this.ownerId = ownerId;
this.gunId = gunId;
this.variant = variant == null ? PortalGunVariant.DEFAULT : variant;
this.portalId = portalId; this.portalId = portalId;
this.side = side; this.side = side;
this.facing = facing; this.facing = facing;
this.upAxis = upAxis; this.upAxis = upAxis;
this.basePos = basePos.immutable(); this.basePos = basePos.immutable();
this.portalSpots = new BlockPos[] {portalSpots[0].immutable(), portalSpots[1].immutable()}; this.portalSpots = java.util.Arrays.stream(portalSpots).map(BlockPos::immutable).toArray(BlockPos[]::new);
this.portalWidth = portalWidth;
this.portalHeight = portalHeight;
this.compensatedSpots = new HashSet<>(compensatedSpots); this.compensatedSpots = new HashSet<>(compensatedSpots);
this.pairTime = pairTime; this.pairTime = pairTime;
this.portalGun$putFaceRecord(new PortalGunPortalFaceRecord(ownerId, gunId, this.variant, portalId, this.linkedPortalId, side, facing, upAxis, this.worldPosition, this.basePos, List.of(this.portalSpots), this.compensatedSpots, pairTime, portalWidth, portalHeight, true));
this.setChanged(); this.setChanged();
} }
@Override
public Map<Direction, PortalGunPortalFaceRecord> portalGun$getFaceRecords() {
return this.faceRecords;
}
public UUID getPortalId() { public UUID getPortalId() {
return this.portalId; return this.portalId;
} }
@@ -77,6 +98,14 @@ public class PortalGunPortalMasterBlockEntity extends BlockEntity {
return this.ownerId; return this.ownerId;
} }
public UUID getGunId() {
return this.gunId;
}
public PortalGunVariant getVariant() {
return this.variant;
}
public PortalGunPortalEntity.PortalSide getSide() { public PortalGunPortalEntity.PortalSide getSide() {
return this.side; return this.side;
} }
@@ -94,7 +123,16 @@ public class PortalGunPortalMasterBlockEntity extends BlockEntity {
} }
public BlockPos[] getPortalSpots() { public BlockPos[] getPortalSpots() {
return new BlockPos[] {this.portalSpots[0], this.portalSpots[1]}; return this.portalSpots.clone();
}
public boolean containsPortalSpot(BlockPos pos) {
for (BlockPos portalSpot : this.portalSpots) {
if (portalSpot.equals(pos)) {
return true;
}
}
return false;
} }
public Set<BlockPos> getCompensatedSpots() { public Set<BlockPos> getCompensatedSpots() {
@@ -112,6 +150,10 @@ public class PortalGunPortalMasterBlockEntity extends BlockEntity {
public void updatePair(UUID linkedPortalId, int pairTime) { public void updatePair(UUID linkedPortalId, int pairTime) {
this.linkedPortalId = linkedPortalId; this.linkedPortalId = linkedPortalId;
this.pairTime = pairTime; this.pairTime = pairTime;
PortalGunPortalFaceRecord record = this.portalGun$getFaceRecord(this.facing, this.portalId);
if (record != null) {
this.portalGun$putFaceRecord(record.withPair(linkedPortalId, pairTime));
}
this.setChanged(); this.setChanged();
} }
@@ -120,11 +162,20 @@ public class PortalGunPortalMasterBlockEntity extends BlockEntity {
} }
public void onBroken() { public void onBroken() {
if (!(this.level instanceof ServerLevel serverLevel) || this.portalId == null) { if (!(this.level instanceof ServerLevel serverLevel)) {
return; return;
} }
if (serverLevel.getEntity(this.portalId) instanceof PortalGunPortalEntity portal && !portal.isRemoved()) { Set<UUID> portalIds = new HashSet<>();
portal.discard(); if (this.portalId != null) {
portalIds.add(this.portalId);
}
for (PortalGunPortalFaceRecord record : this.faceRecords.values()) {
portalIds.add(record.portalId());
}
for (UUID id : portalIds) {
if (serverLevel.getEntity(id) instanceof PortalGunPortalEntity portal && !portal.isRemoved()) {
portal.discard();
}
} }
} }
@@ -132,6 +183,12 @@ public class PortalGunPortalMasterBlockEntity extends BlockEntity {
if (((level.getGameTime() + pos.asLong()) & 15L) != 0L) { if (((level.getGameTime() + pos.asLong()) & 15L) != 0L) {
return; return;
} }
blockEntity.portalGun$restoreMasterFaces(level, pos);
if (blockEntity.portalId != null
&& !(level.getEntity(blockEntity.portalId) instanceof PortalGunPortalEntity)
&& blockEntity.faceRecords.values().stream().anyMatch(record -> !record.portalId().equals(blockEntity.portalId))) {
return;
}
if (!blockEntity.hasValidFootprint(level, pos)) { if (!blockEntity.hasValidFootprint(level, pos)) {
level.removeBlock(pos, false); level.removeBlock(pos, false);
return; return;
@@ -161,16 +218,24 @@ public class PortalGunPortalMasterBlockEntity extends BlockEntity {
if (this.ownerId == null || this.portalId == null || !pos.equals(this.worldPosition)) { if (this.ownerId == null || this.portalId == null || !pos.equals(this.worldPosition)) {
return false; return false;
} }
if (!(level.getBlockEntity(this.basePos) instanceof PortalGunPortalBaseBlockEntity base) if (!PortalGunPlacement.isRectangularFootprint(this.portalSpots, this.facing, this.upAxis, this.portalWidth, this.portalHeight)) {
|| !base.matches(this.ownerId, this.portalId, this.side)
|| !pos.equals(base.getMasterPos())) {
return false; return false;
} }
List<BlockPos> supportPositions = new ArrayList<>(2); List<BlockPos> supportPositions = new ArrayList<>(this.portalSpots.length);
for (BlockPos portalSpot : this.portalSpots) { for (int i = 0; i < this.portalSpots.length; i++) {
BlockPos portalSpot = this.portalSpots[i];
if (portalSpot == null || BlockPos.ZERO.equals(portalSpot)) { if (portalSpot == null || BlockPos.ZERO.equals(portalSpot)) {
return false; return false;
} }
if (i == 0) {
if (!portalSpot.equals(pos)) {
return false;
}
} else if (!(level.getBlockEntity(portalSpot) instanceof PortalGunPortalBaseBlockEntity base)
|| !base.matches(this.ownerId, this.portalId, this.side)
|| !pos.equals(base.getMasterPos())) {
return false;
}
supportPositions.add(portalSpot.relative(this.facing.getOpposite())); supportPositions.add(portalSpot.relative(this.facing.getOpposite()));
} }
for (BlockPos supportPos : supportPositions) { for (BlockPos supportPos : supportPositions) {
@@ -186,23 +251,60 @@ public class PortalGunPortalMasterBlockEntity extends BlockEntity {
if (this.portalId == null || this.ownerId == null) { if (this.portalId == null || this.ownerId == null) {
return null; return null;
} }
if (!PortalGunSavedData.isRegistered(level, this.gunId, this.side, this.portalId)) {
return null;
}
if (level.getEntity(this.portalId) instanceof PortalGunPortalEntity portal && !portal.isRemoved()) { if (level.getEntity(this.portalId) instanceof PortalGunPortalEntity portal && !portal.isRemoved()) {
return portal; return portal;
} }
PortalGunPortalFaceRecord record = this.portalGun$getFaceRecord(this.facing, this.portalId);
if (record != null) {
return restorePortalEntity(level, record);
}
EntityType<?> rawType = BuiltInRegistries.ENTITY_TYPE.get(new ResourceLocation(Antarchy.MODID, "portal_gun_portal")); EntityType<?> rawType = BuiltInRegistries.ENTITY_TYPE.get(new ResourceLocation(Antarchy.MODID, "portal_gun_portal"));
if (!(rawType instanceof EntityType<?>)) { if (!(rawType instanceof EntityType<?>)) {
return null; return null;
} }
PortalGunPlacement placement = PortalGunPlacement.fromStored(this.facing, this.upAxis, this.worldPosition, this.basePos, this.compensatedSpots); PortalGunPlacement placement = PortalGunPlacement.fromStored(this.facing, this.upAxis, this.worldPosition, this.basePos, this.portalSpots, this.compensatedSpots, this.portalWidth, this.portalHeight);
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
PortalGunPortalEntity restored = new PortalGunPortalEntity((EntityType<? extends PortalGunPortalEntity>) rawType, level); PortalGunPortalEntity restored = new PortalGunPortalEntity((EntityType<? extends PortalGunPortalEntity>) rawType, level);
restored.setUUID(this.portalId); restored.setUUID(this.portalId);
restored.configure(this.ownerId, this.side, placement); restored.configure(this.ownerId, this.gunId, this.variant, this.side, placement);
restored.restorePair(this.linkedPortalId, this.pairTime); restored.restorePair(this.linkedPortalId, this.pairTime);
Vec3 center = placement.center(); Vec3 center = placement.center();
restored.moveTo(center.x, center.y, center.z, placement.yaw(), 0.0F); restored.moveTo(center.x, center.y, center.z, placement.yaw(), 0.0F);
level.addFreshEntity(restored); level.addFreshEntity(restored);
PortalGunSavedData.setPortal(level.getServer(), this.ownerId, this.side, restored.getUUID()); PortalGunSavedData.setPortal(level, this.gunId, this.ownerId, this.side, restored.getUUID());
return restored;
}
public static PortalGunPortalEntity restorePortalEntity(ServerLevel level, PortalGunPortalFaceRecord record) {
if (record.ownerId() == null || record.portalId() == null
|| !PortalGunSavedData.isRegistered(level, record.gunId(), record.side(), record.portalId())) {
return null;
}
if (level.getEntity(record.portalId()) instanceof PortalGunPortalEntity portal && !portal.isRemoved()) {
return portal;
}
EntityType<?> rawType = BuiltInRegistries.ENTITY_TYPE.get(new ResourceLocation(Antarchy.MODID, "portal_gun_portal"));
if (rawType == null) {
return null;
}
PortalGunPlacement placement = record.placement();
@SuppressWarnings("unchecked")
PortalGunPortalEntity restored = new PortalGunPortalEntity((EntityType<? extends PortalGunPortalEntity>) rawType, level);
restored.setUUID(record.portalId());
restored.configure(record.ownerId(), record.gunId(), record.variant(), record.side(), placement);
restored.restorePair(record.linkedPortalId(), record.pairTime());
Vec3 center = placement.center();
restored.moveTo(center.x, center.y, center.z, placement.yaw(), 0.0F);
level.addFreshEntity(restored);
PortalGunSavedData.setPortal(level, record.gunId(), record.ownerId(), record.side(), restored.getUUID());
PortalGunPortalEntity linked = PortalGunSavedData.findLoadedPortal(level, record.gunId(), record.side() == PortalGunPortalEntity.PortalSide.BLUE ? PortalGunPortalEntity.PortalSide.ORANGE : PortalGunPortalEntity.PortalSide.BLUE);
if (linked != null && linked != restored && !linked.isRemoved()) {
restored.linkTo(linked);
linked.linkTo(restored);
}
return restored; return restored;
} }
@@ -211,8 +313,8 @@ public class PortalGunPortalMasterBlockEntity extends BlockEntity {
return; return;
} }
PortalGunPortalEntity counterpart = PortalGunSavedData.findLoadedPortal( PortalGunPortalEntity counterpart = PortalGunSavedData.findLoadedPortal(
level.getServer(), level,
this.ownerId, this.gunId,
this.side == PortalGunPortalEntity.PortalSide.BLUE ? PortalGunPortalEntity.PortalSide.ORANGE : PortalGunPortalEntity.PortalSide.BLUE this.side == PortalGunPortalEntity.PortalSide.BLUE ? PortalGunPortalEntity.PortalSide.ORANGE : PortalGunPortalEntity.PortalSide.BLUE
); );
if (counterpart == null || counterpart == portal || counterpart.isRemoved()) { if (counterpart == null || counterpart == portal || counterpart.isRemoved()) {
@@ -230,6 +332,10 @@ public class PortalGunPortalMasterBlockEntity extends BlockEntity {
if (this.ownerId != null) { if (this.ownerId != null) {
tag.putUUID("OwnerId", this.ownerId); tag.putUUID("OwnerId", this.ownerId);
} }
if (this.gunId != null) {
tag.putUUID("GunId", this.gunId);
}
tag.putInt("Variant", this.variant.id());
if (this.portalId != null) { if (this.portalId != null) {
tag.putUUID("PortalId", this.portalId); tag.putUUID("PortalId", this.portalId);
} }
@@ -243,6 +349,8 @@ public class PortalGunPortalMasterBlockEntity extends BlockEntity {
tag.putInt("BaseY", this.basePos.getY()); tag.putInt("BaseY", this.basePos.getY());
tag.putInt("BaseZ", this.basePos.getZ()); tag.putInt("BaseZ", this.basePos.getZ());
tag.putInt("PairTime", this.pairTime); tag.putInt("PairTime", this.pairTime);
tag.putInt("PortalWidth", this.portalWidth);
tag.putInt("PortalHeight", this.portalHeight);
ListTag spots = new ListTag(); ListTag spots = new ListTag();
for (BlockPos portalSpot : this.portalSpots) { for (BlockPos portalSpot : this.portalSpots) {
CompoundTag spot = new CompoundTag(); CompoundTag spot = new CompoundTag();
@@ -261,12 +369,15 @@ public class PortalGunPortalMasterBlockEntity extends BlockEntity {
compensated.add(spot); compensated.add(spot);
} }
tag.put("CompensatedSpots", compensated); tag.put("CompensatedSpots", compensated);
this.portalGun$saveFaceRecords(tag);
} }
@Override @Override
public void load(CompoundTag tag) { public void load(CompoundTag tag) {
super.load(tag); super.load(tag);
this.ownerId = tag.hasUUID("OwnerId") ? tag.getUUID("OwnerId") : null; this.ownerId = tag.hasUUID("OwnerId") ? tag.getUUID("OwnerId") : null;
this.gunId = tag.hasUUID("GunId") ? tag.getUUID("GunId") : null;
this.variant = PortalGunVariant.byId(tag.getInt("Variant"));
this.portalId = tag.hasUUID("PortalId") ? tag.getUUID("PortalId") : null; this.portalId = tag.hasUUID("PortalId") ? tag.getUUID("PortalId") : null;
this.linkedPortalId = tag.hasUUID("LinkedPortalId") ? tag.getUUID("LinkedPortalId") : null; this.linkedPortalId = tag.hasUUID("LinkedPortalId") ? tag.getUUID("LinkedPortalId") : null;
this.side = tag.getInt("Side") == PortalGunPortalEntity.PortalSide.ORANGE.ordinal() ? PortalGunPortalEntity.PortalSide.ORANGE : PortalGunPortalEntity.PortalSide.BLUE; this.side = tag.getInt("Side") == PortalGunPortalEntity.PortalSide.ORANGE.ordinal() ? PortalGunPortalEntity.PortalSide.ORANGE : PortalGunPortalEntity.PortalSide.BLUE;
@@ -275,10 +386,15 @@ public class PortalGunPortalMasterBlockEntity extends BlockEntity {
this.basePos = new BlockPos(tag.getInt("BaseX"), tag.getInt("BaseY"), tag.getInt("BaseZ")); this.basePos = new BlockPos(tag.getInt("BaseX"), tag.getInt("BaseY"), tag.getInt("BaseZ"));
this.pairTime = tag.getInt("PairTime"); this.pairTime = tag.getInt("PairTime");
ListTag spots = tag.getList("PortalSpots", Tag.TAG_COMPOUND); ListTag spots = tag.getList("PortalSpots", Tag.TAG_COMPOUND);
for (int i = 0; i < Math.min(2, spots.size()); i++) { if (!spots.isEmpty()) {
this.portalSpots = new BlockPos[spots.size()];
}
for (int i = 0; i < spots.size(); i++) {
CompoundTag spot = spots.getCompound(i); CompoundTag spot = spots.getCompound(i);
this.portalSpots[i] = new BlockPos(spot.getInt("X"), spot.getInt("Y"), spot.getInt("Z")); this.portalSpots[i] = new BlockPos(spot.getInt("X"), spot.getInt("Y"), spot.getInt("Z"));
} }
this.portalWidth = net.minecraft.util.Mth.clamp(tag.getInt("PortalWidth"), 1, 16);
this.portalHeight = net.minecraft.util.Mth.clamp(tag.getInt("PortalHeight"), 2, 16);
ListTag compensated = tag.getList("CompensatedSpots", Tag.TAG_COMPOUND); ListTag compensated = tag.getList("CompensatedSpots", Tag.TAG_COMPOUND);
Set<BlockPos> compensatedSpots = new HashSet<>(); Set<BlockPos> compensatedSpots = new HashSet<>();
for (int i = 0; i < compensated.size(); i++) { for (int i = 0; i < compensated.size(); i++) {
@@ -286,6 +402,10 @@ public class PortalGunPortalMasterBlockEntity extends BlockEntity {
compensatedSpots.add(new BlockPos(spot.getInt("X"), spot.getInt("Y"), spot.getInt("Z"))); compensatedSpots.add(new BlockPos(spot.getInt("X"), spot.getInt("Y"), spot.getInt("Z")));
} }
this.compensatedSpots = compensatedSpots; this.compensatedSpots = compensatedSpots;
this.portalGun$loadFaceRecords(tag);
if (this.faceRecords.isEmpty() && this.ownerId != null && this.portalId != null && this.portalSpots.length > 0) {
this.portalGun$putFaceRecord(new PortalGunPortalFaceRecord(this.ownerId, this.gunId, this.variant, this.portalId, this.linkedPortalId, this.side, this.facing, this.upAxis, this.worldPosition, this.basePos, List.of(this.portalSpots), this.compensatedSpots, this.pairTime, this.portalWidth, this.portalHeight, true));
}
} }
@Override @Override
@@ -6,9 +6,9 @@ import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.block.PotentNyxiteBlock; import com.craisinlord.antarchy.content.block.PotentNyxiteBlock;
import com.craisinlord.antarchy.content.block.state.PotentNyxiteState; import com.craisinlord.antarchy.content.block.state.PotentNyxiteState;
import com.craisinlord.antarchy.content.fluid.AntarchyFluidChecks; import com.craisinlord.antarchy.content.fluid.AntarchyFluidChecks;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi; import com.craisinlord.anthology.gravity.GravityApi;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection; import com.craisinlord.anthology.gravity.GravityDirection;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil; import com.craisinlord.anthology.gravity.GravityRotationUtil;
import com.craisinlord.antarchy.content.client.particle.InvertedGeyserParticleOptions; import com.craisinlord.antarchy.content.client.particle.InvertedGeyserParticleOptions;
import java.util.List; import java.util.List;
import java.util.function.Predicate; import java.util.function.Predicate;
@@ -333,9 +333,9 @@ public class PotentNyxiteBlockEntity extends BlockEntity {
continue; continue;
} }
AntarchyGravityDirection gravityDirection = AntarchyGravityApi.getGravityDirection(entity); GravityDirection gravityDirection = GravityApi.getGravityDirection(entity);
Vec3 currentWorldVelocity = gravityDirection.isInverted() Vec3 currentWorldVelocity = gravityDirection.isInverted()
? AntarchyGravityRotationUtil.vecPlayerToWorld(entity.getDeltaMovement(), gravityDirection) ? GravityRotationUtil.vecPlayerToWorld(entity.getDeltaMovement(), gravityDirection)
: entity.getDeltaMovement(); : entity.getDeltaMovement();
double axisVelocity = currentWorldVelocity.y * eruptionDirection.getStepY(); double axisVelocity = currentWorldVelocity.y * eruptionDirection.getStepY();
@@ -343,7 +343,7 @@ public class PotentNyxiteBlockEntity extends BlockEntity {
Vec3 nextWorldVelocity = currentWorldVelocity.add(worldPush); Vec3 nextWorldVelocity = currentWorldVelocity.add(worldPush);
entity.setDeltaMovement( entity.setDeltaMovement(
gravityDirection.isInverted() gravityDirection.isInverted()
? AntarchyGravityRotationUtil.vecWorldToPlayer(nextWorldVelocity, gravityDirection) ? GravityRotationUtil.vecWorldToPlayer(nextWorldVelocity, gravityDirection)
: nextWorldVelocity : nextWorldVelocity
); );
entity.hurtMarked = true; entity.hurtMarked = true;
@@ -10,6 +10,7 @@ import net.minecraft.world.Difficulty;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.Nullable;
public final class QueenTrailSpawnMarkerBlockEntity extends BlockEntity { public final class QueenTrailSpawnMarkerBlockEntity extends BlockEntity {
private static final double ACTIVATION_DISTANCE_SQUARED = 96.0D * 96.0D; private static final double ACTIVATION_DISTANCE_SQUARED = 96.0D * 96.0D;
@@ -19,11 +20,11 @@ public final class QueenTrailSpawnMarkerBlockEntity extends BlockEntity {
private float yaw; private float yaw;
private boolean configured; private boolean configured;
private boolean consumed; private boolean consumed;
@Nullable
private UUID queenUuid; private UUID queenUuid;
public QueenTrailSpawnMarkerBlockEntity(BlockPos pos, BlockState state, public QueenTrailSpawnMarkerBlockEntity(BlockPos pos, BlockState state, Supplier<? extends BlockEntityType<QueenTrailSpawnMarkerBlockEntity>> typeSupplier) {
Supplier<? extends BlockEntityType<QueenTrailSpawnMarkerBlockEntity>> type) { super(typeSupplier.get(), pos, state);
super(type.get(), pos, state);
} }
public void configure(long siteId, BlockPos spawnPos, BlockPos homePos, float yaw) { public void configure(long siteId, BlockPos spawnPos, BlockPos homePos, float yaw) {
@@ -32,52 +33,109 @@ public final class QueenTrailSpawnMarkerBlockEntity extends BlockEntity {
this.homePos = homePos.immutable(); this.homePos = homePos.immutable();
this.yaw = yaw; this.yaw = yaw;
this.configured = true; this.configured = true;
setChanged(); this.setChanged();
} }
public long getSiteId() { return siteId; } public long getSiteId() {
public BlockPos getSpawnPos() { return spawnPos; } return this.siteId;
public boolean isConfigured() { return configured; } }
public BlockPos getSpawnPos() {
return this.spawnPos;
}
public boolean isConfigured() {
return this.configured;
}
public boolean isConsumed() {
return this.consumed;
}
public static void serverTick(ServerLevel level, QueenTrailSpawnMarkerBlockEntity marker) { public static void serverTick(ServerLevel level, QueenTrailSpawnMarkerBlockEntity marker) {
if (!marker.configured || marker.consumed || level.getDifficulty() == Difficulty.PEACEFUL) return; if (!marker.configured || marker.consumed || level.getDifficulty() == Difficulty.PEACEFUL) {
if (Math.floorMod(level.getGameTime(), 20L) != Math.floorMod(marker.siteId, 20L)) return; return;
boolean nearby = level.players().stream().anyMatch(player -> !player.isSpectator() }
&& player.distanceToSqr(marker.spawnPos.getX() + .5D, marker.spawnPos.getY() + .5D, if (Math.floorMod(level.getGameTime(), 20L) != Math.floorMod(marker.siteId, 20L)) {
marker.spawnPos.getZ() + .5D) <= ACTIVATION_DISTANCE_SQUARED); return;
if (!nearby) return; }
for (int chunkX = (marker.spawnPos.getX() - 16) >> 4; chunkX <= (marker.spawnPos.getX() + 16) >> 4; chunkX++) boolean nearbyPlayer = level.players().stream().anyMatch(player -> !player.isSpectator()
for (int chunkZ = (marker.spawnPos.getZ() - 16) >> 4; chunkZ <= (marker.spawnPos.getZ() + 16) >> 4; chunkZ++) && player.distanceToSqr(marker.spawnPos.getX() + 0.5D, marker.spawnPos.getY() + 0.5D, marker.spawnPos.getZ() + 0.5D) <= ACTIVATION_DISTANCE_SQUARED);
if (!nearbyPlayer) {
return;
}
for (int chunkX = (marker.spawnPos.getX() - 16) >> 4; chunkX <= (marker.spawnPos.getX() + 16) >> 4; chunkX++) {
for (int chunkZ = (marker.spawnPos.getZ() - 16) >> 4; chunkZ <= (marker.spawnPos.getZ() + 16) >> 4; chunkZ++) {
level.getChunk(chunkX, chunkZ); level.getChunk(chunkX, chunkZ);
QueenEntity queen = QueenEntity.spawnFromUndersideTrail(level, marker.spawnPos, marker.homePos, marker.siteId, marker.yaw); }
}
marker.spawnNow(level);
}
@Nullable
public QueenEntity spawnNow(ServerLevel level) {
if (!this.configured) {
return null;
}
if (this.consumed) {
if (this.queenUuid != null && level.getEntity(this.queenUuid) instanceof QueenEntity queen) {
return queen;
}
return null;
}
for (int chunkX = (this.spawnPos.getX() - 16) >> 4; chunkX <= (this.spawnPos.getX() + 16) >> 4; chunkX++) {
for (int chunkZ = (this.spawnPos.getZ() - 16) >> 4; chunkZ <= (this.spawnPos.getZ() + 16) >> 4; chunkZ++) {
level.getChunk(chunkX, chunkZ);
}
}
QueenEntity queen = QueenEntity.spawnFromUndersideTrail(level, this.spawnPos, this.homePos, this.siteId, this.yaw);
if (queen == null) {
for (int radius = 2; radius <= 10 && queen == null; radius += 2) {
for (int dx = -radius; dx <= radius && queen == null; dx += radius) {
for (int dz = -radius; dz <= radius && queen == null; dz += radius) {
BlockPos candidate = this.spawnPos.offset(dx, 0, dz);
if (candidate.equals(this.spawnPos)) {
continue;
}
queen = QueenEntity.spawnFromUndersideTrail(level, candidate, this.homePos, this.siteId, this.yaw);
if (queen != null) {
this.spawnPos = candidate.immutable();
}
}
}
}
}
if (queen != null) { if (queen != null) {
marker.consumed = true; this.consumed = true;
marker.queenUuid = queen.getUUID(); this.queenUuid = queen.getUUID();
marker.setChanged(); this.setChanged();
}
return queen;
}
@Override
protected void saveAdditional(CompoundTag tag) {
super.saveAdditional(tag);
tag.putLong("site_id", this.siteId);
tag.putLong("spawn_pos", this.spawnPos.asLong());
tag.putLong("home_pos", this.homePos.asLong());
tag.putFloat("yaw", this.yaw);
tag.putBoolean("configured", this.configured);
tag.putBoolean("consumed", this.consumed);
if (this.queenUuid != null) {
tag.putUUID("queen_uuid", this.queenUuid);
} }
} }
@Override @Override
public void load(CompoundTag tag) { public void load(CompoundTag tag) {
super.load(tag); super.load(tag);
siteId = tag.getLong("site_id"); this.siteId = tag.getLong("site_id");
spawnPos = BlockPos.of(tag.getLong("spawn_pos")); this.spawnPos = BlockPos.of(tag.getLong("spawn_pos"));
homePos = BlockPos.of(tag.getLong("home_pos")); this.homePos = BlockPos.of(tag.getLong("home_pos"));
yaw = tag.getFloat("yaw"); this.yaw = tag.getFloat("yaw");
configured = tag.getBoolean("configured"); this.configured = tag.getBoolean("configured");
consumed = tag.getBoolean("consumed"); this.consumed = tag.getBoolean("consumed");
queenUuid = tag.hasUUID("queen_uuid") ? tag.getUUID("queen_uuid") : null; this.queenUuid = tag.hasUUID("queen_uuid") ? tag.getUUID("queen_uuid") : null;
}
@Override
protected void saveAdditional(CompoundTag tag) {
super.saveAdditional(tag);
tag.putLong("site_id", siteId);
tag.putLong("spawn_pos", spawnPos.asLong());
tag.putLong("home_pos", homePos.asLong());
tag.putFloat("yaw", yaw);
tag.putBoolean("configured", configured);
tag.putBoolean("consumed", consumed);
if (queenUuid != null) tag.putUUID("queen_uuid", queenUuid);
} }
} }
@@ -1,10 +1,18 @@
package com.craisinlord.antarchy.content.block.entity; package com.craisinlord.antarchy.content.block.entity;
import com.craisinlord.antarchy.Antarchy; import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.block.UnderVaultBlock;
import com.craisinlord.antarchy.content.block.entity.undervault.UnderVaultConfig;
import com.craisinlord.antarchy.content.block.entity.undervault.UnderVaultData;
import com.craisinlord.antarchy.content.block.entity.undervault.UnderVaultLogic;
import com.craisinlord.antarchy.content.block.entity.undervault.UnderVaultState;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.particles.SimpleParticleType; import net.minecraft.core.particles.SimpleParticleType;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientGamePacketListener;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
@@ -12,72 +20,87 @@ import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.storage.loot.LootParams; import net.minecraft.world.phys.AABB;
import net.minecraft.world.level.storage.loot.LootTable;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.minecraft.core.Direction;
import net.minecraft.core.dispenser.DefaultDispenseItemBehavior;
import java.util.Optional;
import java.util.function.Supplier; import java.util.function.Supplier;
public final class UnderVaultBlockEntity extends BlockEntity { public final class UnderVaultBlockEntity extends BlockEntity {
private boolean unlocked; private final UnderVaultData vaultData;
private boolean playerWasNearby;
public UnderVaultBlockEntity(BlockPos pos, net.minecraft.world.level.block.state.BlockState state, public UnderVaultBlockEntity(BlockPos pos, BlockState state, Supplier<? extends BlockEntityType<UnderVaultBlockEntity>> type) {
Supplier<? extends BlockEntityType<UnderVaultBlockEntity>> type) {
super(type.get(), pos, state); super(type.get(), pos, state);
this.vaultData = new UnderVaultData();
this.vaultData.setConfig(createConfig());
} }
public static void tick(Level level, BlockPos pos, net.minecraft.world.level.block.state.BlockState state, private static UnderVaultConfig createConfig() {
UnderVaultBlockEntity blockEntity) { return new UnderVaultConfig(new ResourceLocation(Antarchy.MODID, "chests/undertrial_vault"), 4.0D, 4.0D,
if (level.isClientSide && state.getValue(com.craisinlord.antarchy.content.block.UnderVaultBlock.ACTIVE) new ItemStack(BuiltInRegistries.ITEM.get(new ResourceLocation(Antarchy.MODID, "undertrial_key"))),
&& level.random.nextInt(4) == 0) { Optional.empty());
}
public static void serverTick(ServerLevel level, BlockPos pos, BlockState state, UnderVaultBlockEntity blockEntity) {
blockEntity.vaultData.setLevel(level);
boolean playerNearby = !level.getEntitiesOfClass(Player.class, new AABB(pos).inflate(4.0D), player -> !player.isSpectator()).isEmpty();
if (state.getValue(UnderVaultBlock.STATE) == UnderVaultState.INACTIVE && playerNearby && !blockEntity.playerWasNearby) {
state = state.setValue(UnderVaultBlock.STATE, UnderVaultState.ACTIVE);
level.setBlockAndUpdate(pos, state);
}
blockEntity.playerWasNearby = playerNearby;
UnderVaultLogic.Server.tick(level, pos, state, blockEntity.vaultData.getConfig(), blockEntity.vaultData.getServerData(), blockEntity.vaultData.getSharedData());
}
public static void clientTick(Level level, BlockPos pos, BlockState state, UnderVaultBlockEntity blockEntity) {
blockEntity.vaultData.setLevel(level);
UnderVaultLogic.Client.tick(level, pos, state, blockEntity.vaultData.getClientData(), blockEntity.vaultData.getSharedData());
UnderVaultState vaultState = state.getValue(UnderVaultBlock.STATE);
if (level.isClientSide && level.random.nextInt(4) == 0
&& (vaultState == UnderVaultState.ACTIVE || vaultState == UnderVaultState.UNLOCKING)) {
Player player = level.getNearestPlayer(pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D, 8.0D, false); Player player = level.getNearestPlayer(pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D, 8.0D, false);
if (player != null) { if (player != null) {
Vec3 start = Vec3.atCenterOf(pos); Vec3 start = Vec3.atCenterOf(pos);
Vec3 end = player.position().add(0.0D, player.getBbHeight() * 0.5D, 0.0D); Vec3 end = player.position().add(0.0D, player.getBbHeight() * 0.5D, 0.0D);
Vec3 point = start.lerp(end, 0.15D + level.random.nextDouble() * 0.7D); double progress = 0.15D + level.random.nextDouble() * 0.7D;
level.addParticle(particle("undervault_connection"), point.x, point.y, point.z, 0.0D, 0.0D, 0.0D); Vec3 point = start.lerp(end, progress);
level.addParticle((SimpleParticleType) BuiltInRegistries.PARTICLE_TYPE.get(new ResourceLocation(Antarchy.MODID, "undervault_connection")), point.x, point.y, point.z, 0.0D, 0.0D, 0.0D);
} }
} }
} }
private static SimpleParticleType particle(String id) { @Override
return (SimpleParticleType) BuiltInRegistries.PARTICLE_TYPE.get(new ResourceLocation(Antarchy.MODID, id)); public void setLevel(Level level) {
} super.setLevel(level);
this.vaultData.setLevel(level);
public boolean unlock(ServerLevel level, BlockPos pos, Player player, ItemStack key) {
if (unlocked) {
return false;
}
if (!player.getAbilities().instabuild) {
key.shrink(1);
}
LootTable table = level.getServer().getLootData().getLootTable(
new ResourceLocation(Antarchy.MODID, "chests/undertrial_vault"));
LootParams params = new LootParams.Builder(level).withParameter(
net.minecraft.world.level.storage.loot.parameters.LootContextParams.ORIGIN,
Vec3.atCenterOf(pos)).create(LootContextParamSets.CHEST);
for (ItemStack stack : table.getRandomItems(params)) {
DefaultDispenseItemBehavior.spawnItem(level, stack, 2, Direction.DOWN,
Vec3.atBottomCenterOf(pos).relative(Direction.DOWN, 1.2D));
}
unlocked = true;
setChanged();
level.levelEvent(3011, pos, 0);
return true;
} }
@Override @Override
public void load(CompoundTag tag) { public void load(CompoundTag tag) {
super.load(tag); super.load(tag);
unlocked = tag.getBoolean("Unlocked"); vaultData.load(tag);
vaultData.setConfig(createConfig());
} }
@Override @Override
protected void saveAdditional(CompoundTag tag) { protected void saveAdditional(CompoundTag tag) {
super.saveAdditional(tag); super.saveAdditional(tag);
tag.putBoolean("Unlocked", unlocked); tag.merge(vaultData.save());
}
@Override
public CompoundTag getUpdateTag() {
return vaultData.save();
}
@Override
public Packet<ClientGamePacketListener> getUpdatePacket() {
return ClientboundBlockEntityDataPacket.create(this);
}
public UnderVaultData getVaultData() {
return vaultData;
} }
} }
@@ -0,0 +1,38 @@
package com.craisinlord.antarchy.content.block.entity;
import net.minecraft.world.entity.MobSpawnType;
public final class UndertrialSpawnContext implements AutoCloseable {
private static final ThreadLocal<Integer> DEPTH = ThreadLocal.withInitial(() -> 0);
private boolean closed;
private UndertrialSpawnContext() {
DEPTH.set(DEPTH.get() + 1);
}
public static UndertrialSpawnContext enter() {
return new UndertrialSpawnContext();
}
public static boolean isActive() {
return DEPTH.get() > 0;
}
public static boolean isTrialSpawn(MobSpawnType spawnReason) {
return spawnReason == MobSpawnType.SPAWNER && isActive();
}
@Override
public void close() {
if (!closed) {
closed = true;
int depth = DEPTH.get() - 1;
if (depth <= 0) {
DEPTH.remove();
} else {
DEPTH.set(depth);
}
}
}
}
@@ -1,113 +1,242 @@
package com.craisinlord.antarchy.content.block.entity; package com.craisinlord.antarchy.content.block.entity;
import com.craisinlord.antarchy.Antarchy; import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.block.UndertrialSpawnerBlock; import com.craisinlord.antarchy.content.block.UndertrialSpawnerBlock;
import com.craisinlord.antarchy.content.block.entity.undertrial.UndertrialPlayerDetector;
import com.craisinlord.antarchy.content.block.entity.undertrial.UndertrialSpawner;
import com.craisinlord.antarchy.content.block.entity.undertrial.UndertrialSpawnerConfig;
import com.craisinlord.antarchy.content.block.entity.undertrial.UndertrialSpawnerEffects;
import com.craisinlord.antarchy.content.block.entity.undertrial.UndertrialSpawnerState;
import com.craisinlord.anthology.effect.AnthologyEffects;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.dispenser.DefaultDispenseItemBehavior;
import net.minecraft.core.particles.SimpleParticleType; import net.minecraft.core.particles.SimpleParticleType;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.random.SimpleWeightedRandomList;
import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.monster.Zombie;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets;
import net.minecraft.world.level.storage.loot.LootParams; import net.minecraft.world.level.storage.loot.LootParams;
import net.minecraft.world.level.storage.loot.LootTable; import net.minecraft.world.level.storage.loot.LootTable;
import net.minecraft.world.level.storage.loot.parameters.LootContextParam; import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets;
import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.minecraft.core.dispenser.DefaultDispenseItemBehavior;
import java.util.List; import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.function.Supplier; import java.util.function.Supplier;
public final class UndertrialSpawnerBlockEntity extends BlockEntity { public final class UndertrialSpawnerBlockEntity extends BlockEntity implements UndertrialSpawner.StateAccessor {
private static final String COOLDOWN_TAG = "Cooldown"; private static final String SPAWNER_TAG = "trial_spawner";
private static final String WAVES_TAG = "Waves"; private static final int DEFAULT_TARGET_COOLDOWN_LENGTH = 36000;
private static final int MAX_WAVES = 6; private static final int EFFECT_DURATION = 3600;
private int cooldown; private UndertrialSpawner trialSpawner;
private int waves; private UndertrialSpawnerState previousClientState;
private double clientSpin;
private double clientOldSpin;
private SimpleWeightedRandomList<ResourceLocation> normalLootTables = SimpleWeightedRandomList.empty();
private SimpleWeightedRandomList<ResourceLocation> ominousLootTables = SimpleWeightedRandomList.empty();
private Tag normalLootTablesTag;
private Tag ominousLootTablesTag;
public UndertrialSpawnerBlockEntity(BlockPos pos, BlockState state, public UndertrialSpawnerBlockEntity(BlockPos pos, BlockState state, Supplier<? extends BlockEntityType<UndertrialSpawnerBlockEntity>> type) {
Supplier<? extends BlockEntityType<UndertrialSpawnerBlockEntity>> type) {
super(type.get(), pos, state); super(type.get(), pos, state);
this.trialSpawner = new UndertrialSpawner(this, UndertrialPlayerDetector.INCLUDING_CREATIVE_PLAYERS,
UndertrialPlayerDetector.EntitySelector.SELECT_FROM_LEVEL);
this.trialSpawner.overridePeacefulAndMobSpawnRule();
this.previousClientState = state.getValue(UndertrialSpawnerBlock.STATE);
} }
public static void tick(Level level, BlockPos pos, BlockState state, UndertrialSpawnerBlockEntity blockEntity) { public static void serverTick(ServerLevel level, BlockPos pos, BlockState state, UndertrialSpawnerBlockEntity blockEntity) {
if (!(level instanceof ServerLevel serverLevel)) { Set<UUID> before = new HashSet<>();
if (level.isClientSide && state.getValue(UndertrialSpawnerBlock.ACTIVE) for (Mob mob : level.getEntitiesOfClass(Mob.class, new AABB(pos).inflate(16.0D))) {
&& level.random.nextInt(2) == 0) { before.add(mob.getUUID());
level.addParticle(particle("undertrial_omen"), pos.getX() + 0.5D + (level.random.nextDouble() - 0.5D) * 0.7D, }
UndertrialSpawnerState previousState = blockEntity.getState();
boolean ominous = state.getValue(UndertrialSpawnerBlock.OMINOUS);
boolean rewardReady = previousState == UndertrialSpawnerState.EJECTING_REWARD
&& blockEntity.trialSpawner.getData().isReadyToEjectItems(level, 30.0F, blockEntity.trialSpawner.getTargetCooldownLength());
try (UndertrialSpawnContext ignored = UndertrialSpawnContext.enter()) {
blockEntity.trialSpawner.tickServer(level, pos, ominous);
}
if (rewardReady && blockEntity.getState() == UndertrialSpawnerState.EJECTING_REWARD) {
blockEntity.ejectReward(level, pos, ominous);
}
for (Mob mob : level.getEntitiesOfClass(Mob.class, new AABB(pos).inflate(16.0D))) {
if (!before.contains(mob.getUUID())) {
blockEntity.applyUndertrialEffects(mob);
}
}
}
public static void clientTick(Level level, BlockPos pos, BlockState state, UndertrialSpawnerBlockEntity blockEntity) {
UndertrialSpawnerState currentState = state.getValue(UndertrialSpawnerBlock.STATE);
blockEntity.clientOldSpin = blockEntity.clientSpin;
if (currentState == UndertrialSpawnerState.ACTIVE || currentState == UndertrialSpawnerState.WAITING_FOR_REWARD_EJECTION) {
blockEntity.clientSpin = (blockEntity.clientSpin + 4.0D) % 360.0D;
}
if (currentState == UndertrialSpawnerState.ACTIVE || currentState == UndertrialSpawnerState.WAITING_FOR_REWARD_EJECTION) {
if (level.random.nextInt(2) == 0) {
level.addParticle(blockEntity.particle("undertrial_omen"), pos.getX() + 0.5D + (level.random.nextDouble() - 0.5D) * 0.7D,
pos.getY() + 0.45D + level.random.nextDouble() * 0.35D, pos.getY() + 0.45D + level.random.nextDouble() * 0.35D,
pos.getZ() + 0.5D + (level.random.nextDouble() - 0.5D) * 0.7D, 0.0D, 0.01D, 0.0D); pos.getZ() + 0.5D + (level.random.nextDouble() - 0.5D) * 0.7D, 0.0D, 0.01D, 0.0D);
} }
return; } else if (currentState == UndertrialSpawnerState.WAITING_FOR_PLAYERS && blockEntity.previousClientState != currentState) {
} ResourceLocation detectionSound = new ResourceLocation(Antarchy.MODID,
if (blockEntity.cooldown > 0) { level.random.nextBoolean() ? "undertrial_detect_player1" : "undertrial_detect_player2");
blockEntity.cooldown--; level.playSound(null, pos, BuiltInRegistries.SOUND_EVENT.get(detectionSound),
return; net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F);
} for (int i = 0; i < 12; i++) {
if (!state.getValue(UndertrialSpawnerBlock.ACTIVE)) { level.addParticle(blockEntity.particle("undertrial_spawner_detection"), pos.getX() + 0.5D + (level.random.nextDouble() - 0.5D) * 1.4D,
return; pos.getY() + 0.15D + level.random.nextDouble() * 0.7D,
} pos.getZ() + 0.5D + (level.random.nextDouble() - 0.5D) * 1.4D, 0.0D, 0.0D, 0.0D);
if (serverLevel.getNearestPlayer(pos.getX() + 0.5D, pos.getY() - 0.5D, pos.getZ() + 0.5D, 16.0D, false) == null) { }
return;
}
long livingTrialMobs = serverLevel.getEntitiesOfClass(Mob.class, new AABB(pos).inflate(16.0D),
mob -> mob.getTags().contains("antarchy_undertrial_mob")).size();
if (livingTrialMobs > 0) {
return;
}
if (blockEntity.waves >= MAX_WAVES) {
blockEntity.ejectReward(serverLevel, pos);
serverLevel.setBlock(pos, state.setValue(UndertrialSpawnerBlock.ACTIVE, false), 3);
return;
}
Zombie zombie = EntityType.ZOMBIE.create(serverLevel);
if (zombie != null) {
zombie.moveTo(pos.getX() + 0.5D, pos.getY() - 1.0D, pos.getZ() + 0.5D,
serverLevel.random.nextFloat() * 360.0F, 0.0F);
zombie.addTag("antarchy_undertrial_mob");
serverLevel.addFreshEntity(zombie);
blockEntity.waves++;
blockEntity.cooldown = 80;
blockEntity.setChanged();
} }
blockEntity.previousClientState = currentState;
} }
private static SimpleParticleType particle(String id) { private SimpleParticleType particle(String id) {
return (SimpleParticleType) BuiltInRegistries.PARTICLE_TYPE.get(new ResourceLocation(Antarchy.MODID, id)); return (SimpleParticleType) BuiltInRegistries.PARTICLE_TYPE.get(new ResourceLocation(Antarchy.MODID, id));
} }
private void ejectReward(ServerLevel level, BlockPos pos) { private void applyUndertrialEffects(Mob mob) {
ResourceLocation id = new ResourceLocation(Antarchy.MODID, "spawners/undertrial"); mob.addEffect(new MobEffectInstance(AntarchyObjects.INVERTED_EFFECT.get(), EFFECT_DURATION, 0, false, true, true));
LootTable table = level.getServer().getLootData().getLootTable(id); int roll = mob.getRandom().nextInt(100);
LootParams params = new LootParams.Builder(level).create(LootContextParamSets.EMPTY); if (roll < 30) {
for (ItemStack stack : table.getRandomItems(params)) { mob.addEffect(new MobEffectInstance(AnthologyEffects.contracted(), EFFECT_DURATION, 0, false, true, true));
DefaultDispenseItemBehavior.spawnItem(level, stack, 2, Direction.DOWN, } else if (roll < 50) {
Vec3.atBottomCenterOf(pos).relative(Direction.DOWN, 1.2D)); mob.addEffect(new MobEffectInstance(effect("shrinking"), EFFECT_DURATION, 0, false, true, true));
} else if (roll < 65) {
mob.addEffect(new MobEffectInstance(effect("growth"), EFFECT_DURATION, 0, false, true, true));
} }
level.levelEvent(3014, pos, 0); }
private static MobEffect effect(String path) {
MobEffect effect = BuiltInRegistries.MOB_EFFECT.get(new ResourceLocation(Antarchy.MODID, path));
if (effect == null) {
throw new IllegalStateException("Missing mob effect " + Antarchy.MODID + ":" + path);
}
return effect;
} }
@Override @Override
public void load(CompoundTag tag) { public void load(CompoundTag tag) {
super.load(tag); super.load(tag);
cooldown = tag.getInt(COOLDOWN_TAG); Tag spawnerTag = tag.contains(SPAWNER_TAG) ? tag.get(SPAWNER_TAG) : tag;
waves = tag.getInt(WAVES_TAG); if (spawnerTag instanceof CompoundTag compound) {
UndertrialSpawner decoded = trialSpawner.load(compound);
captureLootTables(decoded, spawnerTag);
trialSpawner = createRewardlessSpawner(decoded);
}
}
@Override
public CompoundTag getUpdateTag() {
CompoundTag tag = new CompoundTag();
saveAdditional(tag);
return tag;
} }
@Override @Override
protected void saveAdditional(CompoundTag tag) { protected void saveAdditional(CompoundTag tag) {
super.saveAdditional(tag); super.saveAdditional(tag);
tag.putInt(COOLDOWN_TAG, cooldown); CompoundTag spawnerTag = trialSpawner.save();
tag.putInt(WAVES_TAG, waves); if (normalLootTablesTag != null) {
spawnerTag.getCompound(UndertrialSpawner.NORMAL_CONFIG_TAG_NAME).put("loot_tables_to_eject", normalLootTablesTag.copy());
}
if (ominousLootTablesTag != null) {
spawnerTag.getCompound(UndertrialSpawner.OMINOUS_CONFIG_TAG_NAME).put("loot_tables_to_eject", ominousLootTablesTag.copy());
}
tag.put(SPAWNER_TAG, spawnerTag);
}
@Override
public void setState(Level level, UndertrialSpawnerState state) {
level.setBlockAndUpdate(worldPosition, getBlockState().setValue(UndertrialSpawnerBlock.STATE, state));
}
@Override
public UndertrialSpawnerState getState() {
return getBlockState().getValue(UndertrialSpawnerBlock.STATE);
}
@Override
public void markUpdated() {
setChanged();
if (level != null) {
level.sendBlockUpdated(worldPosition, getBlockState(), getBlockState(), 3);
}
}
public UndertrialSpawner getTrialSpawner() {
return trialSpawner;
}
public void setSpawnEntity(EntityType<?> entityType) {
if (this.level == null) {
return;
}
this.trialSpawner.getData().setEntityId(this.trialSpawner, this.level.random, entityType);
this.markUpdated();
}
public double getClientSpin(float partialTick) {
return this.clientOldSpin + (this.clientSpin - this.clientOldSpin) * partialTick;
}
private void captureLootTables(UndertrialSpawner source, Tag spawnerTag) {
normalLootTables = source.getNormalConfig().lootTablesToEject();
ominousLootTables = source.getOminousConfig().lootTablesToEject();
if (spawnerTag instanceof CompoundTag compound) {
CompoundTag normalConfig = compound.getCompound(UndertrialSpawner.NORMAL_CONFIG_TAG_NAME);
CompoundTag ominousConfig = compound.getCompound(UndertrialSpawner.OMINOUS_CONFIG_TAG_NAME);
normalLootTablesTag = normalConfig.get("loot_tables_to_eject");
ominousLootTablesTag = ominousConfig.get("loot_tables_to_eject");
}
}
private UndertrialSpawner createRewardlessSpawner(UndertrialSpawner source) {
UndertrialSpawner rewardless = new UndertrialSpawner(withoutLootTables(source.getNormalConfig()), withoutLootTables(source.getOminousConfig()),
source.getData(), targetCooldownLength(source), source.getRequiredPlayerRange(), this,
source.getPlayerDetector(), source.getEntitySelector());
rewardless.overridePeacefulAndMobSpawnRule();
return rewardless;
}
private static int targetCooldownLength(UndertrialSpawner source) {
int targetCooldownLength = source.getTargetCooldownLength();
return targetCooldownLength > 0 ? targetCooldownLength : DEFAULT_TARGET_COOLDOWN_LENGTH;
}
private static UndertrialSpawnerConfig withoutLootTables(UndertrialSpawnerConfig config) {
return new UndertrialSpawnerConfig(config.spawnRange(), config.totalMobs(), config.simultaneousMobs(),
config.totalMobsAddedPerPlayer(), config.simultaneousMobsAddedPerPlayer(), config.ticksBetweenSpawn(),
config.spawnPotentialsDefinition(), SimpleWeightedRandomList.empty(), config.itemsToDropWhenOminous());
}
private void ejectReward(ServerLevel level, BlockPos pos, boolean ominous) {
SimpleWeightedRandomList<ResourceLocation> lootTables = ominous ? ominousLootTables : normalLootTables;
lootTables.getRandomValue(level.getRandom()).ifPresent(key -> {
LootTable lootTable = level.getServer().getLootData().getLootTable(key);
LootParams params = new LootParams.Builder(level).create(LootContextParamSets.EMPTY);
for (ItemStack stack : lootTable.getRandomItems(params)) {
DefaultDispenseItemBehavior.spawnItem(level, stack, 2, Direction.DOWN,
Vec3.atBottomCenterOf(pos).relative(Direction.DOWN, 1.2D));
}
UndertrialSpawnerEffects.ejectItem(level, pos);
});
} }
} }
@@ -0,0 +1,130 @@
package com.craisinlord.antarchy.content.block.entity.undertrial;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.FloatTag;
import net.minecraft.nbt.NumericTag;
import net.minecraft.nbt.Tag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.item.Equipable;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.storage.loot.BuiltInLootTables;
import net.minecraft.world.level.storage.loot.LootParams;
import net.minecraft.world.level.storage.loot.LootTable;
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSet;
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
public record UndertrialEquipmentTable(ResourceLocation lootTable, Map<EquipmentSlot, Float> slotDropChances) {
private static final LootContextParamSet EQUIPMENT = LootContextParamSet.builder()
.required(LootContextParams.ORIGIN)
.required(LootContextParams.THIS_ENTITY)
.build();
public static Optional<UndertrialEquipmentTable> load(Tag tag) {
if (!(tag instanceof CompoundTag compound) || !compound.contains("loot_table", Tag.TAG_STRING)) {
return Optional.empty();
}
ResourceLocation lootTable = ResourceLocation.tryParse(compound.getString("loot_table"));
if (lootTable == null) {
return Optional.empty();
}
Map<EquipmentSlot, Float> chances = new EnumMap<>(EquipmentSlot.class);
Tag chancesTag = compound.get("slot_drop_chances");
if (chancesTag instanceof NumericTag numeric) {
for (EquipmentSlot slot : EquipmentSlot.values()) {
chances.put(slot, numeric.getAsFloat());
}
} else if (chancesTag instanceof CompoundTag chanceMap) {
for (String key : chanceMap.getAllKeys()) {
EquipmentSlot slot = slotByName(key);
if (slot == null || !(chanceMap.get(key) instanceof NumericTag value)) {
return Optional.empty();
}
chances.put(slot, value.getAsFloat());
}
} else if (chancesTag != null) {
return Optional.empty();
}
return Optional.of(new UndertrialEquipmentTable(lootTable, chances));
}
private static EquipmentSlot slotByName(String name) {
for (EquipmentSlot slot : EquipmentSlot.values()) {
if (slot.getName().equals(name)) {
return slot;
}
}
return null;
}
public CompoundTag save() {
CompoundTag tag = new CompoundTag();
tag.putString("loot_table", this.lootTable.toString());
if (!this.slotDropChances.isEmpty()) {
Set<Float> distinct = new HashSet<>(this.slotDropChances.values());
if (distinct.size() == 1 && this.slotDropChances.keySet().containsAll(List.of(EquipmentSlot.values()))) {
tag.put("slot_drop_chances", FloatTag.valueOf(distinct.iterator().next()));
} else {
CompoundTag map = new CompoundTag();
for (Map.Entry<EquipmentSlot, Float> entry : this.slotDropChances.entrySet()) {
map.putFloat(entry.getKey().getName(), entry.getValue());
}
tag.put("slot_drop_chances", map);
}
}
return tag;
}
public void equip(Mob mob) {
if (!(mob.level() instanceof ServerLevel level) || this.lootTable.equals(BuiltInLootTables.EMPTY)) {
return;
}
LootTable table = level.getServer().getLootData().getLootTable(this.lootTable);
if (table == LootTable.EMPTY) {
return;
}
LootParams params = new LootParams.Builder(level)
.withParameter(LootContextParams.ORIGIN, mob.position())
.withParameter(LootContextParams.THIS_ENTITY, mob)
.create(EQUIPMENT);
List<EquipmentSlot> used = new ArrayList<>();
for (ItemStack stack : table.getRandomItems(params, 0L)) {
EquipmentSlot slot = resolveSlot(stack, used);
if (slot != null) {
ItemStack equipped = slot.isArmor() ? stack.split(1) : stack;
mob.setItemSlot(slot, equipped);
Float chance = this.slotDropChances.get(slot);
if (chance != null) {
mob.setDropChance(slot, chance);
}
used.add(slot);
}
}
}
private static EquipmentSlot resolveSlot(ItemStack stack, List<EquipmentSlot> used) {
if (stack.isEmpty()) {
return null;
}
Equipable equipable = Equipable.get(stack);
if (equipable != null) {
EquipmentSlot slot = equipable.getEquipmentSlot();
if (!used.contains(slot)) {
return slot;
}
} else if (!used.contains(EquipmentSlot.MAINHAND)) {
return EquipmentSlot.MAINHAND;
}
return null;
}
}
@@ -0,0 +1,70 @@
package com.craisinlord.antarchy.content.block.entity.undertrial;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.player.Player;
import java.util.ArrayList;
import java.util.List;
public final class UndertrialOmen {
public static final int TRIAL_OMEN_PER_BAD_OMEN_LEVEL = 18000;
private static final String TAG_PREFIX = "antarchy.trial_omen.";
private UndertrialOmen() {
}
public static boolean hasTrialOmen(Player player) {
long now = player.level().getGameTime();
boolean active = false;
List<String> expired = new ArrayList<>();
for (String tag : player.getTags()) {
if (tag.startsWith(TAG_PREFIX)) {
long expiresAt = parseExpiry(tag);
if (expiresAt > now) {
active = true;
} else {
expired.add(tag);
}
}
}
for (String tag : expired) {
player.removeTag(tag);
}
return active;
}
public static boolean hasBadOmen(Player player) {
return player.hasEffect(MobEffects.BAD_OMEN);
}
public static void transformBadOmenIntoTrialOmen(Player player) {
MobEffectInstance badOmen = player.getEffect(MobEffects.BAD_OMEN);
if (badOmen != null) {
int duration = TRIAL_OMEN_PER_BAD_OMEN_LEVEL * (badOmen.getAmplifier() + 1);
player.removeEffect(MobEffects.BAD_OMEN);
grantTrialOmen(player, duration);
}
}
public static void grantTrialOmen(Player player, int duration) {
List<String> existing = new ArrayList<>();
for (String tag : player.getTags()) {
if (tag.startsWith(TAG_PREFIX)) {
existing.add(tag);
}
}
for (String tag : existing) {
player.removeTag(tag);
}
player.addTag(TAG_PREFIX + (player.level().getGameTime() + duration));
}
private static long parseExpiry(String tag) {
try {
return Long.parseLong(tag.substring(TAG_PREFIX.length()));
} catch (NumberFormatException exception) {
return Long.MIN_VALUE;
}
}
}
@@ -0,0 +1,48 @@
package com.craisinlord.antarchy.content.block.entity.undertrial;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.function.Predicate;
public interface UndertrialPlayerDetector {
UndertrialPlayerDetector NO_CREATIVE_PLAYERS = (level, selector, pos, range, requireLineOfSight) -> collect(level, pos,
selector.getPlayers(level, player -> player.blockPosition().closerThan(pos, range) && !player.isCreative() && !player.isSpectator()),
requireLineOfSight);
UndertrialPlayerDetector INCLUDING_CREATIVE_PLAYERS = (level, selector, pos, range, requireLineOfSight) -> collect(level, pos,
selector.getPlayers(level, player -> player.blockPosition().closerThan(pos, range) && !player.isSpectator()),
requireLineOfSight);
List<UUID> detect(ServerLevel level, EntitySelector selector, BlockPos pos, double range, boolean requireLineOfSight);
private static List<UUID> collect(ServerLevel level, BlockPos pos, List<? extends Player> players, boolean requireLineOfSight) {
List<UUID> result = new ArrayList<>();
for (Player player : players) {
if (!requireLineOfSight || inLineOfSight(level, pos.getCenter(), player.getEyePosition())) {
result.add(player.getUUID());
}
}
return List.copyOf(result);
}
static boolean inLineOfSight(Level level, Vec3 target, Vec3 from) {
BlockHitResult hit = level.clip(new ClipContext(from, target, ClipContext.Block.VISUAL, ClipContext.Fluid.NONE, (Entity) null));
return hit.getBlockPos().equals(BlockPos.containing(target)) || hit.getType() == HitResult.Type.MISS;
}
interface EntitySelector {
EntitySelector SELECT_FROM_LEVEL = (level, predicate) -> level.getPlayers(predicate::test);
List<? extends Player> getPlayers(ServerLevel level, Predicate<? super Player> predicate);
}
}
@@ -0,0 +1,62 @@
package com.craisinlord.antarchy.content.block.entity.undertrial;
import net.minecraft.core.BlockPos;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.level.Level;
import java.util.function.Supplier;
public final class UndertrialSounds {
public static final Entry TRIAL_SPAWNER_SPAWN_MOB = new Entry("block.trial_spawner.spawn_mob", () -> SoundEvents.FIRECHARGE_USE);
public static final Entry TRIAL_SPAWNER_DETECT_PLAYER = new Entry("block.trial_spawner.detect_player", () -> SoundEvents.RESPAWN_ANCHOR_CHARGE);
public static final Entry TRIAL_SPAWNER_EJECT_ITEM = new Entry("block.trial_spawner.eject_item", () -> SoundEvents.DISPENSER_DISPENSE);
public static final Entry TRIAL_SPAWNER_OPEN_SHUTTER = new Entry("block.trial_spawner.open_shutter", () -> SoundEvents.IRON_TRAPDOOR_OPEN);
public static final Entry TRIAL_SPAWNER_CLOSE_SHUTTER = new Entry("block.trial_spawner.close_shutter", () -> SoundEvents.IRON_TRAPDOOR_CLOSE);
public static final Entry TRIAL_SPAWNER_OMINOUS_ACTIVATE = new Entry("block.trial_spawner.ominous_activate", () -> SoundEvents.RESPAWN_ANCHOR_SET_SPAWN);
public static final Entry TRIAL_SPAWNER_SPAWN_ITEM_BEGIN = new Entry("block.trial_spawner.spawn_item_begin", () -> SoundEvents.AMETHYST_BLOCK_CHIME);
public static final Entry VAULT_AMBIENT = new Entry("block.vault.ambient", () -> null);
public static final Entry VAULT_DEACTIVATE = new Entry("block.vault.deactivate", () -> SoundEvents.IRON_DOOR_CLOSE);
public static final Entry VAULT_INSERT_ITEM = new Entry("block.vault.insert_item", () -> SoundEvents.CHAIN_PLACE);
public static final Entry VAULT_INSERT_ITEM_FAIL = new Entry("block.vault.insert_item_fail", () -> SoundEvents.DISPENSER_FAIL);
public static final Entry VAULT_REJECT_REWARDED_PLAYER = new Entry("block.vault.reject_rewarded_player", () -> SoundEvents.DISPENSER_FAIL);
public static final Entry VAULT_OPEN_SHUTTER = new Entry("block.vault.open_shutter", () -> SoundEvents.IRON_TRAPDOOR_OPEN);
public static final Entry VAULT_CLOSE_SHUTTER = new Entry("block.vault.close_shutter", () -> SoundEvents.IRON_TRAPDOOR_CLOSE);
public static final Entry VAULT_EJECT_ITEM = new Entry("block.vault.eject_item", () -> SoundEvents.DISPENSER_DISPENSE);
private UndertrialSounds() {
}
public static void playServer(ServerLevel level, BlockPos pos, Entry entry, SoundSource source, float volume, float pitch) {
SoundEvent sound = entry.get();
if (sound != null) {
level.playSound(null, pos, sound, source, volume, pitch);
}
}
public static void playLocal(Level level, BlockPos pos, Entry entry, SoundSource source, float volume, float pitch, boolean distanceDelay) {
SoundEvent sound = entry.get();
if (sound != null) {
level.playLocalSound(pos, sound, source, volume, pitch, distanceDelay);
}
}
public static final class Entry {
private final ResourceLocation id;
private final Supplier<SoundEvent> fallback;
private Entry(String path, Supplier<SoundEvent> fallback) {
this.id = new ResourceLocation("minecraft", path);
this.fallback = fallback;
}
public SoundEvent get() {
SoundEvent registered = BuiltInRegistries.SOUND_EVENT.getOptional(this.id).orElse(null);
return registered != null ? registered : this.fallback.get();
}
}
}
@@ -0,0 +1,102 @@
package com.craisinlord.antarchy.content.block.entity.undertrial;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.NbtOps;
import net.minecraft.nbt.Tag;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.random.SimpleWeightedRandomList;
import net.minecraft.util.random.WeightedEntry;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.SpawnData;
import java.util.Optional;
public record UndertrialSpawnData(CompoundTag entityToSpawn, Optional<SpawnData.CustomSpawnRules> customSpawnRules,
Optional<UndertrialEquipmentTable> equipment) {
public static final String ENTITY_TAG = "entity";
public UndertrialSpawnData() {
this(new CompoundTag(), Optional.empty(), Optional.empty());
}
public CompoundTag getEntityToSpawn() {
return this.entityToSpawn;
}
public Optional<SpawnData.CustomSpawnRules> getCustomSpawnRules() {
return this.customSpawnRules;
}
public Optional<UndertrialEquipmentTable> getEquipment() {
return this.equipment;
}
public static boolean isValidPosition(SpawnData.CustomSpawnRules rules, BlockPos pos, ServerLevel level) {
return rules.blockLightLimit().isValueInRange(level.getBrightness(LightLayer.BLOCK, pos))
&& rules.skyLightLimit().isValueInRange(level.getBrightness(LightLayer.SKY, pos));
}
public static Optional<UndertrialSpawnData> load(Tag tag) {
if (!(tag instanceof CompoundTag compound) || !compound.contains(ENTITY_TAG, Tag.TAG_COMPOUND)) {
return Optional.empty();
}
Optional<SpawnData.CustomSpawnRules> rules = Optional.empty();
if (compound.contains("custom_spawn_rules")) {
Optional<SpawnData.CustomSpawnRules> parsed = SpawnData.CustomSpawnRules.CODEC
.parse(NbtOps.INSTANCE, compound.get("custom_spawn_rules")).result();
if (parsed.isEmpty()) {
return Optional.empty();
}
rules = parsed;
}
Optional<UndertrialEquipmentTable> equipment = Optional.empty();
if (compound.contains("equipment")) {
equipment = UndertrialEquipmentTable.load(compound.get("equipment"));
if (equipment.isEmpty()) {
return Optional.empty();
}
}
return Optional.of(new UndertrialSpawnData(compound.getCompound(ENTITY_TAG), rules, equipment));
}
public CompoundTag save() {
CompoundTag tag = new CompoundTag();
tag.put(ENTITY_TAG, this.entityToSpawn);
this.customSpawnRules.flatMap(rules -> SpawnData.CustomSpawnRules.CODEC.encodeStart(NbtOps.INSTANCE, rules).result())
.ifPresent(encoded -> tag.put("custom_spawn_rules", encoded));
this.equipment.ifPresent(table -> tag.put("equipment", table.save()));
return tag;
}
public static Optional<SimpleWeightedRandomList<UndertrialSpawnData>> loadList(Tag tag) {
if (!(tag instanceof ListTag list)) {
return Optional.empty();
}
SimpleWeightedRandomList.Builder<UndertrialSpawnData> builder = SimpleWeightedRandomList.builder();
for (Tag element : list) {
if (!(element instanceof CompoundTag entry) || !entry.contains("weight", Tag.TAG_ANY_NUMERIC)) {
return Optional.empty();
}
Optional<UndertrialSpawnData> data = load(entry.get("data"));
int weight = entry.getInt("weight");
if (data.isEmpty() || weight < 0) {
return Optional.empty();
}
builder.add(data.get(), weight);
}
return Optional.of(builder.build());
}
public static ListTag saveList(SimpleWeightedRandomList<UndertrialSpawnData> list) {
ListTag tag = new ListTag();
for (WeightedEntry.Wrapper<UndertrialSpawnData> wrapper : list.unwrap()) {
CompoundTag entry = new CompoundTag();
entry.put("data", wrapper.getData().save());
entry.putInt("weight", wrapper.getWeight().asInt());
tag.add(entry);
}
return tag;
}
}
@@ -0,0 +1,282 @@
package com.craisinlord.antarchy.content.block.entity.undertrial;
import com.craisinlord.antarchy.content.block.UndertrialSpawnerBlock;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.dispenser.DefaultDispenseItemBehavior;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
import net.minecraft.world.Difficulty;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.MobSpawnType;
import net.minecraft.world.entity.SpawnPlacements;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.storage.loot.LootParams;
import net.minecraft.world.level.storage.loot.LootTable;
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets;
import net.minecraft.world.phys.Vec3;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
public final class UndertrialSpawner {
public static final String NORMAL_CONFIG_TAG_NAME = "normal_config";
public static final String OMINOUS_CONFIG_TAG_NAME = "ominous_config";
public static final int DETECT_PLAYER_SPAWN_BUFFER = 40;
public static final int DEFAULT_TARGET_COOLDOWN_LENGTH = 36000;
public static final int DEFAULT_PLAYER_SCAN_RANGE = 14;
private static final int MAX_MOB_TRACKING_DISTANCE = 47;
private static final int MAX_MOB_TRACKING_DISTANCE_SQR = Mth.square(MAX_MOB_TRACKING_DISTANCE);
private final UndertrialSpawnerConfig normalConfig;
private final UndertrialSpawnerConfig ominousConfig;
private final UndertrialSpawnerData data;
private final int requiredPlayerRange;
private final int targetCooldownLength;
private final StateAccessor stateAccessor;
private final UndertrialPlayerDetector playerDetector;
private final UndertrialPlayerDetector.EntitySelector entitySelector;
private boolean overridePeacefulAndMobSpawnRule;
private boolean isOminous;
public UndertrialSpawner(StateAccessor stateAccessor, UndertrialPlayerDetector playerDetector,
UndertrialPlayerDetector.EntitySelector entitySelector) {
this(UndertrialSpawnerConfig.DEFAULT, UndertrialSpawnerConfig.DEFAULT, new UndertrialSpawnerData(),
DEFAULT_TARGET_COOLDOWN_LENGTH, DEFAULT_PLAYER_SCAN_RANGE, stateAccessor, playerDetector, entitySelector);
}
public UndertrialSpawner(UndertrialSpawnerConfig normalConfig, UndertrialSpawnerConfig ominousConfig, UndertrialSpawnerData data,
int targetCooldownLength, int requiredPlayerRange, StateAccessor stateAccessor,
UndertrialPlayerDetector playerDetector, UndertrialPlayerDetector.EntitySelector entitySelector) {
this.normalConfig = normalConfig;
this.ominousConfig = ominousConfig;
this.data = data;
this.targetCooldownLength = targetCooldownLength;
this.requiredPlayerRange = requiredPlayerRange;
this.stateAccessor = stateAccessor;
this.playerDetector = playerDetector;
this.entitySelector = entitySelector;
}
public UndertrialSpawner load(CompoundTag tag) {
UndertrialSpawnerConfig normal = tag.contains(NORMAL_CONFIG_TAG_NAME, Tag.TAG_COMPOUND)
? UndertrialSpawnerConfig.load(tag.getCompound(NORMAL_CONFIG_TAG_NAME)) : UndertrialSpawnerConfig.DEFAULT;
UndertrialSpawnerConfig ominous = tag.contains(OMINOUS_CONFIG_TAG_NAME, Tag.TAG_COMPOUND)
? UndertrialSpawnerConfig.load(tag.getCompound(OMINOUS_CONFIG_TAG_NAME)) : UndertrialSpawnerConfig.DEFAULT;
UndertrialSpawnerData loadedData = UndertrialSpawnerData.load(tag);
int cooldown = DEFAULT_TARGET_COOLDOWN_LENGTH;
if (tag.contains("target_cooldown_length", Tag.TAG_ANY_NUMERIC) && tag.getInt("target_cooldown_length") >= 0) {
cooldown = tag.getInt("target_cooldown_length");
}
int range = DEFAULT_PLAYER_SCAN_RANGE;
if (tag.contains("required_player_range", Tag.TAG_ANY_NUMERIC)) {
int value = tag.getInt("required_player_range");
if (value >= 1 && value <= 128) {
range = value;
}
}
return new UndertrialSpawner(normal, ominous, loadedData, cooldown, range, this.stateAccessor, this.playerDetector, this.entitySelector);
}
public CompoundTag save() {
CompoundTag tag = new CompoundTag();
if (!this.normalConfig.equals(UndertrialSpawnerConfig.DEFAULT)) {
tag.put(NORMAL_CONFIG_TAG_NAME, this.normalConfig.save());
}
UndertrialSpawnerConfig ominous = this.getOminousConfigForSerialization();
if (!ominous.equals(UndertrialSpawnerConfig.DEFAULT)) {
tag.put(OMINOUS_CONFIG_TAG_NAME, ominous.save());
}
this.data.save(tag);
if (this.targetCooldownLength != DEFAULT_TARGET_COOLDOWN_LENGTH) {
tag.putInt("target_cooldown_length", this.targetCooldownLength);
}
if (this.requiredPlayerRange != DEFAULT_PLAYER_SCAN_RANGE) {
tag.putInt("required_player_range", this.requiredPlayerRange);
}
return tag;
}
public UndertrialSpawnerConfig getConfig() {
return this.isOminous ? this.ominousConfig : this.normalConfig;
}
public UndertrialSpawnerConfig getNormalConfig() {
return this.normalConfig;
}
public UndertrialSpawnerConfig getOminousConfig() {
return this.ominousConfig;
}
private UndertrialSpawnerConfig getOminousConfigForSerialization() {
return !this.ominousConfig.equals(this.normalConfig) ? this.ominousConfig : UndertrialSpawnerConfig.DEFAULT;
}
public void applyOminous(ServerLevel level, BlockPos pos) {
level.setBlock(pos, level.getBlockState(pos).setValue(UndertrialSpawnerBlock.OMINOUS, true), 3);
UndertrialSpawnerEffects.becomeOminous(level, pos, pos, 1);
this.isOminous = true;
this.data.resetAfterBecomingOminous(this, level, pos);
}
public void removeOminous(ServerLevel level, BlockPos pos) {
level.setBlock(pos, level.getBlockState(pos).setValue(UndertrialSpawnerBlock.OMINOUS, false), 3);
this.isOminous = false;
}
public boolean isOminous() {
return this.isOminous;
}
public UndertrialSpawnerData getData() {
return this.data;
}
public int getTargetCooldownLength() {
return this.targetCooldownLength;
}
public int getRequiredPlayerRange() {
return this.requiredPlayerRange;
}
public UndertrialSpawnerState getState() {
return this.stateAccessor.getState();
}
public void setState(Level level, UndertrialSpawnerState state) {
this.stateAccessor.setState(level, state);
}
public void markUpdated() {
this.stateAccessor.markUpdated();
}
public UndertrialPlayerDetector getPlayerDetector() {
return this.playerDetector;
}
public UndertrialPlayerDetector.EntitySelector getEntitySelector() {
return this.entitySelector;
}
public boolean canSpawnInLevel(Level level) {
if (this.overridePeacefulAndMobSpawnRule) {
return true;
}
return level.getDifficulty() != Difficulty.PEACEFUL && level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING);
}
public Optional<UUID> spawnMob(ServerLevel level, BlockPos pos) {
RandomSource random = level.getRandom();
UndertrialSpawnData spawnData = this.data.getOrCreateNextSpawnData(this, level.getRandom());
CompoundTag entityTag = spawnData.entityToSpawn();
ListTag posList = entityTag.getList("Pos", Tag.TAG_DOUBLE);
Optional<EntityType<?>> type = EntityType.by(entityTag);
if (type.isEmpty()) {
return Optional.empty();
}
int size = posList.size();
double x = size >= 1 ? posList.getDouble(0)
: pos.getX() + (random.nextDouble() - random.nextDouble()) * this.getConfig().spawnRange() + 0.5D;
double y = size >= 2 ? posList.getDouble(1) : pos.getY() + random.nextInt(3) - 1;
double z = size >= 3 ? posList.getDouble(2)
: pos.getZ() + (random.nextDouble() - random.nextDouble()) * this.getConfig().spawnRange() + 0.5D;
if (!level.noCollision(type.get().getAABB(x, y, z))) {
return Optional.empty();
}
Vec3 spawnPos = new Vec3(x, y, z);
if (!UndertrialPlayerDetector.inLineOfSight(level, pos.getCenter(), spawnPos)) {
return Optional.empty();
}
BlockPos spawnBlockPos = BlockPos.containing(spawnPos);
if (!SpawnPlacements.checkSpawnRules(type.get(), level, MobSpawnType.SPAWNER, spawnBlockPos, level.getRandom())) {
return Optional.empty();
}
if (spawnData.getCustomSpawnRules().isPresent()
&& !UndertrialSpawnData.isValidPosition(spawnData.getCustomSpawnRules().get(), spawnBlockPos, level)) {
return Optional.empty();
}
Entity entity = EntityType.loadEntityRecursive(entityTag, level, loaded -> {
loaded.moveTo(x, y, z, random.nextFloat() * 360.0F, 0.0F);
return loaded;
});
if (entity == null) {
return Optional.empty();
}
if (entity instanceof Mob mob) {
if (!mob.checkSpawnObstruction(level)) {
return Optional.empty();
}
boolean onlyId = spawnData.getEntityToSpawn().size() == 1 && spawnData.getEntityToSpawn().contains("id", Tag.TAG_STRING);
if (onlyId) {
mob.finalizeSpawn(level, level.getCurrentDifficultyAt(mob.blockPosition()), MobSpawnType.SPAWNER, null, null);
}
mob.setPersistenceRequired();
spawnData.getEquipment().ifPresent(table -> table.equip(mob));
}
if (!level.tryAddFreshEntityWithPassengers(entity)) {
return Optional.empty();
}
int flame = this.isOminous ? UndertrialSpawnerEffects.FLAME_OMINOUS : UndertrialSpawnerEffects.FLAME_NORMAL;
UndertrialSpawnerEffects.spawnerSpawn(level, pos, flame);
UndertrialSpawnerEffects.mobSpawn(level, pos, spawnBlockPos, flame);
level.gameEvent(entity, GameEvent.ENTITY_PLACE, spawnBlockPos);
return Optional.of(entity.getUUID());
}
public void ejectReward(ServerLevel level, BlockPos pos, ResourceLocation lootTableId) {
LootTable lootTable = level.getServer().getLootData().getLootTable(lootTableId);
LootParams params = new LootParams.Builder(level).create(LootContextParamSets.EMPTY);
List<ItemStack> items = lootTable.getRandomItems(params);
if (!items.isEmpty()) {
for (ItemStack stack : items) {
DefaultDispenseItemBehavior.spawnItem(level, stack, 2, Direction.UP, Vec3.atBottomCenterOf(pos).relative(Direction.UP, 1.2D));
}
UndertrialSpawnerEffects.ejectItem(level, pos);
}
}
public void tickServer(ServerLevel level, BlockPos pos, boolean ominous) {
this.isOminous = ominous;
UndertrialSpawnerState state = this.getState();
if (this.data.currentMobs.removeIf(uuid -> shouldMobBeUntracked(level, pos, uuid))) {
this.data.nextMobSpawnsAt = level.getGameTime() + this.getConfig().ticksBetweenSpawn();
}
UndertrialSpawnerState next = state.tickAndGetNext(pos, this, level);
if (next != state) {
this.setState(level, next);
}
}
private static boolean shouldMobBeUntracked(ServerLevel level, BlockPos pos, UUID uuid) {
Entity entity = level.getEntity(uuid);
return entity == null
|| !entity.isAlive()
|| !entity.level().dimension().equals(level.dimension())
|| entity.blockPosition().distSqr(pos) > MAX_MOB_TRACKING_DISTANCE_SQR;
}
public void overridePeacefulAndMobSpawnRule() {
this.overridePeacefulAndMobSpawnRule = true;
}
public interface StateAccessor {
void setState(Level level, UndertrialSpawnerState state);
UndertrialSpawnerState getState();
void markUpdated();
}
}
@@ -0,0 +1,157 @@
package com.craisinlord.antarchy.content.block.entity.undertrial;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.random.SimpleWeightedRandomList;
import net.minecraft.util.random.WeightedEntry;
import java.util.Optional;
public record UndertrialSpawnerConfig(
int spawnRange,
float totalMobs,
float simultaneousMobs,
float totalMobsAddedPerPlayer,
float simultaneousMobsAddedPerPlayer,
int ticksBetweenSpawn,
SimpleWeightedRandomList<UndertrialSpawnData> spawnPotentialsDefinition,
SimpleWeightedRandomList<ResourceLocation> lootTablesToEject,
ResourceLocation itemsToDropWhenOminous
) {
public static final ResourceLocation SPAWNER_TRIAL_CHAMBER_CONSUMABLES = new ResourceLocation("minecraft", "spawners/trial_chamber/consumables");
public static final ResourceLocation SPAWNER_TRIAL_CHAMBER_KEY = new ResourceLocation("minecraft", "spawners/trial_chamber/key");
public static final ResourceLocation SPAWNER_TRIAL_ITEMS_TO_DROP_WHEN_OMINOUS = new ResourceLocation("minecraft", "spawners/trial_chamber/items_to_drop_when_ominous");
public static final UndertrialSpawnerConfig DEFAULT = new UndertrialSpawnerConfig(
4,
6.0F,
2.0F,
2.0F,
1.0F,
40,
SimpleWeightedRandomList.empty(),
SimpleWeightedRandomList.<ResourceLocation>builder().add(SPAWNER_TRIAL_CHAMBER_CONSUMABLES, 1).add(SPAWNER_TRIAL_CHAMBER_KEY, 1).build(),
SPAWNER_TRIAL_ITEMS_TO_DROP_WHEN_OMINOUS
);
public int calculateTargetTotalMobs(int additionalPlayers) {
return (int) Math.floor(this.totalMobs + this.totalMobsAddedPerPlayer * additionalPlayers);
}
public int calculateTargetSimultaneousMobs(int additionalPlayers) {
return (int) Math.floor(this.simultaneousMobs + this.simultaneousMobsAddedPerPlayer * additionalPlayers);
}
public long ticksBetweenItemSpawners() {
return 160L;
}
public static UndertrialSpawnerConfig load(CompoundTag tag) {
int spawnRange = DEFAULT.spawnRange;
if (tag.contains("spawn_range", Tag.TAG_ANY_NUMERIC)) {
int value = tag.getInt("spawn_range");
if (value >= 1 && value <= 128) {
spawnRange = value;
}
}
float totalMobs = nonNegativeFloat(tag, "total_mobs", DEFAULT.totalMobs);
float simultaneousMobs = nonNegativeFloat(tag, "simultaneous_mobs", DEFAULT.simultaneousMobs);
float totalMobsAddedPerPlayer = nonNegativeFloat(tag, "total_mobs_added_per_player", DEFAULT.totalMobsAddedPerPlayer);
float simultaneousMobsAddedPerPlayer = nonNegativeFloat(tag, "simultaneous_mobs_added_per_player", DEFAULT.simultaneousMobsAddedPerPlayer);
int ticksBetweenSpawn = DEFAULT.ticksBetweenSpawn;
if (tag.contains("ticks_between_spawn", Tag.TAG_ANY_NUMERIC) && tag.getInt("ticks_between_spawn") >= 0) {
ticksBetweenSpawn = tag.getInt("ticks_between_spawn");
}
SimpleWeightedRandomList<UndertrialSpawnData> potentials = DEFAULT.spawnPotentialsDefinition;
if (tag.contains("spawn_potentials")) {
potentials = UndertrialSpawnData.loadList(tag.get("spawn_potentials")).orElse(DEFAULT.spawnPotentialsDefinition);
}
SimpleWeightedRandomList<ResourceLocation> lootTables = DEFAULT.lootTablesToEject;
if (tag.contains("loot_tables_to_eject")) {
lootTables = loadLootTables(tag.get("loot_tables_to_eject")).orElse(DEFAULT.lootTablesToEject);
}
ResourceLocation itemsToDrop = DEFAULT.itemsToDropWhenOminous;
if (tag.contains("items_to_drop_when_ominous", Tag.TAG_STRING)) {
ResourceLocation parsed = ResourceLocation.tryParse(tag.getString("items_to_drop_when_ominous"));
if (parsed != null) {
itemsToDrop = parsed;
}
}
return new UndertrialSpawnerConfig(spawnRange, totalMobs, simultaneousMobs, totalMobsAddedPerPlayer,
simultaneousMobsAddedPerPlayer, ticksBetweenSpawn, potentials, lootTables, itemsToDrop);
}
private static float nonNegativeFloat(CompoundTag tag, String key, float fallback) {
if (tag.contains(key, Tag.TAG_ANY_NUMERIC)) {
float value = tag.getFloat(key);
if (value >= 0.0F) {
return value;
}
}
return fallback;
}
public CompoundTag save() {
CompoundTag tag = new CompoundTag();
if (this.spawnRange != DEFAULT.spawnRange) {
tag.putInt("spawn_range", this.spawnRange);
}
if (this.totalMobs != DEFAULT.totalMobs) {
tag.putFloat("total_mobs", this.totalMobs);
}
if (this.simultaneousMobs != DEFAULT.simultaneousMobs) {
tag.putFloat("simultaneous_mobs", this.simultaneousMobs);
}
if (this.totalMobsAddedPerPlayer != DEFAULT.totalMobsAddedPerPlayer) {
tag.putFloat("total_mobs_added_per_player", this.totalMobsAddedPerPlayer);
}
if (this.simultaneousMobsAddedPerPlayer != DEFAULT.simultaneousMobsAddedPerPlayer) {
tag.putFloat("simultaneous_mobs_added_per_player", this.simultaneousMobsAddedPerPlayer);
}
if (this.ticksBetweenSpawn != DEFAULT.ticksBetweenSpawn) {
tag.putInt("ticks_between_spawn", this.ticksBetweenSpawn);
}
if (this.spawnPotentialsDefinition != DEFAULT.spawnPotentialsDefinition) {
tag.put("spawn_potentials", UndertrialSpawnData.saveList(this.spawnPotentialsDefinition));
}
if (this.lootTablesToEject != DEFAULT.lootTablesToEject) {
tag.put("loot_tables_to_eject", saveLootTables(this.lootTablesToEject));
}
if (!this.itemsToDropWhenOminous.equals(DEFAULT.itemsToDropWhenOminous)) {
tag.putString("items_to_drop_when_ominous", this.itemsToDropWhenOminous.toString());
}
return tag;
}
public static Optional<SimpleWeightedRandomList<ResourceLocation>> loadLootTables(Tag tag) {
if (!(tag instanceof ListTag list)) {
return Optional.empty();
}
SimpleWeightedRandomList.Builder<ResourceLocation> builder = SimpleWeightedRandomList.builder();
for (Tag element : list) {
if (!(element instanceof CompoundTag entry) || !entry.contains("data", Tag.TAG_STRING)
|| !entry.contains("weight", Tag.TAG_ANY_NUMERIC)) {
return Optional.empty();
}
ResourceLocation id = ResourceLocation.tryParse(entry.getString("data"));
int weight = entry.getInt("weight");
if (id == null || weight < 0) {
return Optional.empty();
}
builder.add(id, weight);
}
return Optional.of(builder.build());
}
public static ListTag saveLootTables(SimpleWeightedRandomList<ResourceLocation> list) {
ListTag tag = new ListTag();
for (WeightedEntry.Wrapper<ResourceLocation> wrapper : list.unwrap()) {
CompoundTag entry = new CompoundTag();
entry.putString("data", wrapper.getData().toString());
entry.putInt("weight", wrapper.getWeight().asInt());
tag.add(entry);
}
return tag;
}
}
@@ -0,0 +1,320 @@
package com.craisinlord.antarchy.content.block.entity.undertrial;
import com.mojang.datafixers.util.Pair;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import net.minecraft.core.BlockPos;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.IntArrayTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.nbt.Tag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
import net.minecraft.util.random.SimpleWeightedRandomList;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.storage.loot.LootParams;
import net.minecraft.world.level.storage.loot.LootTable;
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.function.Function;
public class UndertrialSpawnerData {
public static final String TAG_SPAWN_DATA = "spawn_data";
private static final String TAG_NEXT_MOB_SPAWNS_AT = "next_mob_spawns_at";
private static final int DELAY_BETWEEN_PLAYER_SCANS = 20;
protected final Set<UUID> detectedPlayers = new HashSet<>();
protected final Set<UUID> currentMobs = new HashSet<>();
protected long cooldownEndsAt;
protected long nextMobSpawnsAt;
protected int totalMobsSpawned;
protected Optional<UndertrialSpawnData> nextSpawnData;
protected Optional<ResourceLocation> ejectingLootTable;
protected Entity displayEntity;
private SimpleWeightedRandomList<ItemStack> dispensing;
public UndertrialSpawnerData() {
this(Set.of(), Set.of(), 0L, 0L, 0, Optional.empty(), Optional.empty());
}
public UndertrialSpawnerData(Set<UUID> detectedPlayers, Set<UUID> currentMobs, long cooldownEndsAt, long nextMobSpawnsAt,
int totalMobsSpawned, Optional<UndertrialSpawnData> nextSpawnData,
Optional<ResourceLocation> ejectingLootTable) {
this.detectedPlayers.addAll(detectedPlayers);
this.currentMobs.addAll(currentMobs);
this.cooldownEndsAt = cooldownEndsAt;
this.nextMobSpawnsAt = nextMobSpawnsAt;
this.totalMobsSpawned = totalMobsSpawned;
this.nextSpawnData = nextSpawnData;
this.ejectingLootTable = ejectingLootTable;
}
public static UndertrialSpawnerData load(CompoundTag tag) {
Set<UUID> detected = loadUuidSet(tag.get("registered_players"));
Set<UUID> mobs = loadUuidSet(tag.get("current_mobs"));
long cooldownEndsAt = tag.contains("cooldown_ends_at", Tag.TAG_ANY_NUMERIC) ? tag.getLong("cooldown_ends_at") : 0L;
long nextMobSpawnsAt = tag.contains(TAG_NEXT_MOB_SPAWNS_AT, Tag.TAG_ANY_NUMERIC) ? tag.getLong(TAG_NEXT_MOB_SPAWNS_AT) : 0L;
int totalMobsSpawned = tag.contains("total_mobs_spawned", Tag.TAG_ANY_NUMERIC) && tag.getInt("total_mobs_spawned") >= 0
? tag.getInt("total_mobs_spawned") : 0;
Optional<UndertrialSpawnData> spawnData = tag.contains(TAG_SPAWN_DATA)
? UndertrialSpawnData.load(tag.get(TAG_SPAWN_DATA)) : Optional.empty();
Optional<ResourceLocation> ejecting = tag.contains("ejecting_loot_table", Tag.TAG_STRING)
? Optional.ofNullable(ResourceLocation.tryParse(tag.getString("ejecting_loot_table"))) : Optional.empty();
return new UndertrialSpawnerData(detected, mobs, cooldownEndsAt, nextMobSpawnsAt, totalMobsSpawned, spawnData, ejecting);
}
public void save(CompoundTag tag) {
if (!this.detectedPlayers.isEmpty()) {
tag.put("registered_players", saveUuidSet(this.detectedPlayers));
}
if (!this.currentMobs.isEmpty()) {
tag.put("current_mobs", saveUuidSet(this.currentMobs));
}
if (this.cooldownEndsAt != 0L) {
tag.putLong("cooldown_ends_at", this.cooldownEndsAt);
}
if (this.nextMobSpawnsAt != 0L) {
tag.putLong(TAG_NEXT_MOB_SPAWNS_AT, this.nextMobSpawnsAt);
}
if (this.totalMobsSpawned != 0) {
tag.putInt("total_mobs_spawned", this.totalMobsSpawned);
}
this.nextSpawnData.ifPresent(data -> tag.put(TAG_SPAWN_DATA, data.save()));
this.ejectingLootTable.ifPresent(id -> tag.putString("ejecting_loot_table", id.toString()));
}
private static Set<UUID> loadUuidSet(Tag tag) {
Set<UUID> result = new HashSet<>();
if (!(tag instanceof ListTag list)) {
return result;
}
for (Tag element : list) {
if (!(element instanceof IntArrayTag array) || array.size() != 4) {
return new HashSet<>();
}
result.add(NbtUtils.loadUUID(array));
}
return result;
}
private static ListTag saveUuidSet(Set<UUID> uuids) {
ListTag list = new ListTag();
for (UUID uuid : uuids) {
list.add(NbtUtils.createUUID(uuid));
}
return list;
}
public void reset() {
this.detectedPlayers.clear();
this.totalMobsSpawned = 0;
this.nextMobSpawnsAt = 0L;
this.cooldownEndsAt = 0L;
this.currentMobs.clear();
this.nextSpawnData = Optional.empty();
}
public boolean hasMobToSpawn(UndertrialSpawner spawner, RandomSource random) {
boolean hasId = this.getOrCreateNextSpawnData(spawner, random).getEntityToSpawn().contains("id", Tag.TAG_STRING);
return hasId || !spawner.getConfig().spawnPotentialsDefinition().isEmpty();
}
public boolean hasFinishedSpawningAllMobs(UndertrialSpawnerConfig config, int additionalPlayers) {
return this.totalMobsSpawned >= config.calculateTargetTotalMobs(additionalPlayers);
}
public boolean haveAllCurrentMobsDied() {
return this.currentMobs.isEmpty();
}
public boolean isReadyToSpawnNextMob(ServerLevel level, UndertrialSpawnerConfig config, int additionalPlayers) {
return level.getGameTime() >= this.nextMobSpawnsAt
&& this.currentMobs.size() < config.calculateTargetSimultaneousMobs(additionalPlayers);
}
public int countAdditionalPlayers(BlockPos pos) {
return Math.max(0, this.detectedPlayers.size() - 1);
}
public void tryDetectPlayers(ServerLevel level, BlockPos pos, UndertrialSpawner spawner) {
if ((pos.asLong() + level.getGameTime()) % DELAY_BETWEEN_PLAYER_SCANS != 0L) {
return;
}
if (spawner.getState().equals(UndertrialSpawnerState.COOLDOWN) && spawner.isOminous()) {
return;
}
List<UUID> players = spawner.getPlayerDetector()
.detect(level, spawner.getEntitySelector(), pos, spawner.getRequiredPlayerRange(), true);
boolean becameOminous;
if (!spawner.isOminous() && !players.isEmpty()) {
Optional<Pair<Player, Boolean>> omenPlayer = findPlayerWithOminousEffect(level, players);
omenPlayer.ifPresent(pair -> {
Player player = pair.getFirst();
if (pair.getSecond()) {
UndertrialOmen.transformBadOmenIntoTrialOmen(player);
}
UndertrialSpawnerEffects.becomeOminous(level, pos, BlockPos.containing(player.getEyePosition()), 0);
spawner.applyOminous(level, pos);
});
becameOminous = omenPlayer.isPresent();
} else {
becameOminous = false;
}
if (!spawner.getState().equals(UndertrialSpawnerState.COOLDOWN) || becameOminous) {
boolean firstDetection = spawner.getData().detectedPlayers.isEmpty();
List<UUID> newPlayers = firstDetection ? players
: spawner.getPlayerDetector().detect(level, spawner.getEntitySelector(), pos, spawner.getRequiredPlayerRange(), false);
if (this.detectedPlayers.addAll(newPlayers)) {
this.nextMobSpawnsAt = Math.max(level.getGameTime() + UndertrialSpawner.DETECT_PLAYER_SPAWN_BUFFER, this.nextMobSpawnsAt);
if (!becameOminous) {
UndertrialSpawnerEffects.detectPlayer(level, pos, spawner.isOminous(), this.detectedPlayers.size());
}
}
}
}
private static Optional<Pair<Player, Boolean>> findPlayerWithOminousEffect(ServerLevel level, List<UUID> players) {
Player badOmenPlayer = null;
for (UUID uuid : players) {
Player player = level.getPlayerByUUID(uuid);
if (player != null) {
if (UndertrialOmen.hasTrialOmen(player)) {
return Optional.of(Pair.of(player, false));
}
if (UndertrialOmen.hasBadOmen(player)) {
badOmenPlayer = player;
}
}
}
return Optional.ofNullable(badOmenPlayer).map(player -> Pair.of(player, true));
}
public void resetAfterBecomingOminous(UndertrialSpawner spawner, ServerLevel level, BlockPos spawnerPos) {
for (UUID uuid : this.currentMobs) {
Entity entity = level.getEntity(uuid);
if (entity != null) {
UndertrialSpawnerEffects.mobSpawn(level, spawnerPos, entity.blockPosition(), UndertrialSpawnerEffects.FLAME_NORMAL);
if (entity instanceof Mob mob) {
dropPreservedEquipment(mob);
}
entity.remove(Entity.RemovalReason.DISCARDED);
}
}
if (!spawner.getOminousConfig().spawnPotentialsDefinition().isEmpty()) {
this.nextSpawnData = Optional.empty();
}
this.totalMobsSpawned = 0;
this.currentMobs.clear();
this.nextMobSpawnsAt = level.getGameTime() + spawner.getOminousConfig().ticksBetweenSpawn();
spawner.markUpdated();
this.cooldownEndsAt = level.getGameTime() + spawner.getOminousConfig().ticksBetweenItemSpawners();
}
private static void dropPreservedEquipment(Mob mob) {
CompoundTag saved = mob.saveWithoutId(new CompoundTag());
ListTag hand = saved.getList("HandDropChances", Tag.TAG_FLOAT);
ListTag armor = saved.getList("ArmorDropChances", Tag.TAG_FLOAT);
for (EquipmentSlot slot : EquipmentSlot.values()) {
ItemStack stack = mob.getItemBySlot(slot);
if (stack.isEmpty()) {
continue;
}
ListTag chances = slot.getType() == EquipmentSlot.Type.HAND ? hand : armor;
double chance = slot.getIndex() < chances.size() ? chances.getFloat(slot.getIndex()) : 0.0D;
if (chance > 1.0D) {
mob.setItemSlot(slot, ItemStack.EMPTY);
mob.spawnAtLocation(stack);
}
}
}
public boolean isReadyToOpenShutter(ServerLevel level, float delay, int targetCooldownLength) {
long cooldownStartedAt = this.cooldownEndsAt - targetCooldownLength;
return (float) level.getGameTime() >= (float) cooldownStartedAt + delay;
}
public boolean isReadyToEjectItems(ServerLevel level, float interval, int targetCooldownLength) {
long cooldownStartedAt = this.cooldownEndsAt - targetCooldownLength;
return (float) (level.getGameTime() - cooldownStartedAt) % interval == 0.0F;
}
public boolean isCooldownFinished(ServerLevel level) {
return level.getGameTime() >= this.cooldownEndsAt;
}
public void setEntityId(UndertrialSpawner spawner, RandomSource random, EntityType<?> entityType) {
this.getOrCreateNextSpawnData(spawner, random).getEntityToSpawn()
.putString("id", BuiltInRegistries.ENTITY_TYPE.getKey(entityType).toString());
}
protected UndertrialSpawnData getOrCreateNextSpawnData(UndertrialSpawner spawner, RandomSource random) {
if (this.nextSpawnData.isPresent()) {
return this.nextSpawnData.get();
}
SimpleWeightedRandomList<UndertrialSpawnData> potentials = spawner.getConfig().spawnPotentialsDefinition();
Optional<UndertrialSpawnData> picked = potentials.isEmpty()
? this.nextSpawnData
: potentials.getRandom(random).map(wrapper -> wrapper.getData());
this.nextSpawnData = Optional.of(picked.orElseGet(UndertrialSpawnData::new));
spawner.markUpdated();
return this.nextSpawnData.get();
}
public Entity getOrCreateDisplayEntity(UndertrialSpawner spawner, Level level, UndertrialSpawnerState state) {
if (!state.hasSpinningMob()) {
return null;
}
if (this.displayEntity == null) {
CompoundTag entityTag = this.getOrCreateNextSpawnData(spawner, level.getRandom()).getEntityToSpawn();
if (entityTag.contains("id", Tag.TAG_STRING)) {
this.displayEntity = EntityType.loadEntityRecursive(entityTag, level, Function.identity());
}
}
return this.displayEntity;
}
public CompoundTag getUpdateTag(UndertrialSpawnerState state) {
CompoundTag tag = new CompoundTag();
if (state == UndertrialSpawnerState.ACTIVE) {
tag.putLong(TAG_NEXT_MOB_SPAWNS_AT, this.nextMobSpawnsAt);
}
this.nextSpawnData.ifPresent(data -> tag.put(TAG_SPAWN_DATA, data.save()));
return tag;
}
SimpleWeightedRandomList<ItemStack> getDispensingItems(ServerLevel level, UndertrialSpawnerConfig config, BlockPos pos) {
if (this.dispensing != null) {
return this.dispensing;
}
LootTable lootTable = level.getServer().getLootData().getLootTable(config.itemsToDropWhenOminous());
LootParams params = new LootParams.Builder(level).create(LootContextParamSets.EMPTY);
ObjectArrayList<ItemStack> items = lootTable.getRandomItems(params, lowResolutionPosition(level, pos));
if (items.isEmpty()) {
return SimpleWeightedRandomList.empty();
}
SimpleWeightedRandomList.Builder<ItemStack> builder = SimpleWeightedRandomList.builder();
for (ItemStack stack : items) {
builder.add(stack.copyWithCount(1), stack.getCount());
}
this.dispensing = builder.build();
return this.dispensing;
}
private static long lowResolutionPosition(ServerLevel level, BlockPos pos) {
BlockPos lowRes = new BlockPos(Mth.floor(pos.getX() / 30.0F), Mth.floor(pos.getY() / 20.0F), Mth.floor(pos.getZ() / 30.0F));
return level.getSeed() + lowRes.asLong();
}
}
@@ -0,0 +1,186 @@
package com.craisinlord.antarchy.content.block.entity.undertrial;
import com.craisinlord.antarchy.Antarchy;
import net.minecraft.core.BlockPos;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.core.particles.SimpleParticleType;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
public final class UndertrialSpawnerEffects {
public static final int FLAME_NORMAL = 0;
public static final int FLAME_OMINOUS = 1;
private static final int SPAWNER_SPAWN = 1;
private static final int MOB_SPAWN = 2;
private static final int DETECT_PLAYER = 3;
private static final int DETECT_PLAYER_OMINOUS = 4;
private static final int EJECT_ITEM = 5;
private static final int BECOME_OMINOUS = 6;
private static final int OFFSET_BITS = 9;
private static final int OFFSET_MASK = (1 << OFFSET_BITS) - 1;
private static final int OFFSET_BIAS = 1 << (OFFSET_BITS - 1);
private static final int FLAG_SHIFT = OFFSET_BITS * 3;
private UndertrialSpawnerEffects() {
}
public static void spawnerSpawn(ServerLevel level, BlockPos spawnerPos, int flame) {
send(level, spawnerPos, SPAWNER_SPAWN, flame);
}
public static void mobSpawn(ServerLevel level, BlockPos spawnerPos, BlockPos mobPos, int flame) {
send(level, spawnerPos, MOB_SPAWN, packOffset(spawnerPos, mobPos) | (flame << FLAG_SHIFT));
}
public static void detectPlayer(ServerLevel level, BlockPos spawnerPos, boolean ominous, int playerCount) {
send(level, spawnerPos, ominous ? DETECT_PLAYER_OMINOUS : DETECT_PLAYER, playerCount);
}
public static void ejectItem(ServerLevel level, BlockPos spawnerPos) {
send(level, spawnerPos, EJECT_ITEM, 0);
}
public static void becomeOminous(ServerLevel level, BlockPos spawnerPos, BlockPos effectPos, int data) {
send(level, spawnerPos, BECOME_OMINOUS, packOffset(spawnerPos, effectPos) | ((data == 0 ? 0 : 1) << FLAG_SHIFT));
}
private static void send(ServerLevel level, BlockPos spawnerPos, int id, int param) {
BlockState state = level.getBlockState(spawnerPos);
level.blockEvent(spawnerPos, state.getBlock(), id, param);
}
private static int packOffset(BlockPos origin, BlockPos target) {
int dx = clampOffset(target.getX() - origin.getX());
int dy = clampOffset(target.getY() - origin.getY());
int dz = clampOffset(target.getZ() - origin.getZ());
return (dx + OFFSET_BIAS) | ((dy + OFFSET_BIAS) << OFFSET_BITS) | ((dz + OFFSET_BIAS) << (OFFSET_BITS * 2));
}
private static int clampOffset(int value) {
return Math.max(-OFFSET_BIAS, Math.min(OFFSET_BIAS - 1, value));
}
private static BlockPos unpackOffset(BlockPos origin, int param) {
int dx = (param & OFFSET_MASK) - OFFSET_BIAS;
int dy = ((param >> OFFSET_BITS) & OFFSET_MASK) - OFFSET_BIAS;
int dz = ((param >> (OFFSET_BITS * 2)) & OFFSET_MASK) - OFFSET_BIAS;
return origin.offset(dx, dy, dz);
}
public static boolean handle(Level level, BlockPos spawnerPos, int id, int param) {
if (!level.isClientSide) {
return id >= SPAWNER_SPAWN && id <= BECOME_OMINOUS;
}
RandomSource random = level.random;
switch (id) {
case SPAWNER_SPAWN:
addSpawnParticles(level, spawnerPos, random, flameParticle(param));
return true;
case MOB_SPAWN: {
BlockPos mobPos = unpackOffset(spawnerPos, param);
UndertrialSounds.playLocal(level, mobPos, UndertrialSounds.TRIAL_SPAWNER_SPAWN_MOB, SoundSource.BLOCKS, 1.0F,
(random.nextFloat() - random.nextFloat()) * 0.2F + 1.0F, true);
addSpawnParticles(level, mobPos, random, flameParticle((param >> FLAG_SHIFT) & 1));
return true;
}
case DETECT_PLAYER:
case DETECT_PLAYER_OMINOUS:
UndertrialSounds.playLocal(level, spawnerPos, UndertrialSounds.TRIAL_SPAWNER_DETECT_PLAYER, SoundSource.BLOCKS, 1.0F,
(random.nextFloat() - random.nextFloat()) * 0.2F + 1.0F, true);
addDetectPlayerParticles(level, spawnerPos, random, param, detectedPlayerParticle(id == DETECT_PLAYER_OMINOUS));
return true;
case EJECT_ITEM:
UndertrialSounds.playLocal(level, spawnerPos, UndertrialSounds.TRIAL_SPAWNER_EJECT_ITEM, SoundSource.BLOCKS, 1.0F,
(random.nextFloat() - random.nextFloat()) * 0.2F + 1.0F, true);
addEjectItemParticles(level, spawnerPos, random);
return true;
case BECOME_OMINOUS: {
BlockPos effectPos = unpackOffset(spawnerPos, param);
boolean loud = ((param >> FLAG_SHIFT) & 1) != 0;
UndertrialSounds.playLocal(level, effectPos, UndertrialSounds.TRIAL_SPAWNER_OMINOUS_ACTIVATE, SoundSource.BLOCKS,
loud ? 1.0F : 0.3F, (random.nextFloat() - random.nextFloat()) * 0.2F + 1.0F, true);
addDetectPlayerParticles(level, effectPos, random, 0, detectedPlayerParticle(true));
addBecomeOminousParticles(level, effectPos, random);
return true;
}
default:
return false;
}
}
private static SimpleParticleType flameParticle(int flame) {
return flame == FLAME_OMINOUS ? ParticleTypes.SOUL_FIRE_FLAME : ParticleTypes.FLAME;
}
private static ParticleOptions detectedPlayerParticle(boolean ominous) {
SimpleParticleType detection = antarchyParticle("undertrial_spawner_detection");
if (detection != null) {
return detection;
}
return ominous ? ParticleTypes.SOUL_FIRE_FLAME : ParticleTypes.FLAME;
}
private static ParticleOptions omenParticle() {
SimpleParticleType omen = antarchyParticle("undertrial_omen");
return omen != null ? omen : ParticleTypes.SOUL;
}
private static SimpleParticleType antarchyParticle(String path) {
return BuiltInRegistries.PARTICLE_TYPE.get(new ResourceLocation(Antarchy.MODID, path)) instanceof SimpleParticleType simple
? simple : null;
}
public static void addSpawnParticles(Level level, BlockPos pos, RandomSource random, SimpleParticleType flame) {
for (int i = 0; i < 20; i++) {
double x = pos.getX() + 0.5D + (random.nextDouble() - 0.5D) * 2.0D;
double y = pos.getY() + 0.5D + (random.nextDouble() - 0.5D) * 2.0D;
double z = pos.getZ() + 0.5D + (random.nextDouble() - 0.5D) * 2.0D;
level.addParticle(ParticleTypes.SMOKE, x, y, z, 0.0D, 0.0D, 0.0D);
level.addParticle(flame, x, y, z, 0.0D, 0.0D, 0.0D);
}
}
public static void addBecomeOminousParticles(Level level, BlockPos pos, RandomSource random) {
ParticleOptions omen = omenParticle();
for (int i = 0; i < 20; i++) {
double x = pos.getX() + 0.5D + (random.nextDouble() - 0.5D) * 2.0D;
double y = pos.getY() + 0.5D + (random.nextDouble() - 0.5D) * 2.0D;
double z = pos.getZ() + 0.5D + (random.nextDouble() - 0.5D) * 2.0D;
double xd = random.nextGaussian() * 0.02D;
double yd = random.nextGaussian() * 0.02D;
double zd = random.nextGaussian() * 0.02D;
level.addParticle(omen, x, y, z, xd, yd, zd);
level.addParticle(ParticleTypes.SOUL_FIRE_FLAME, x, y, z, xd, yd, zd);
}
}
public static void addDetectPlayerParticles(Level level, BlockPos pos, RandomSource random, int playerCount, ParticleOptions particle) {
for (int i = 0; i < 30 + Math.min(playerCount, 10) * 5; i++) {
double dx = (2.0F * random.nextFloat() - 1.0F) * 0.65D;
double dz = (2.0F * random.nextFloat() - 1.0F) * 0.65D;
double x = pos.getX() + 0.5D + dx;
double y = pos.getY() + 0.1D + random.nextFloat() * 0.8D;
double z = pos.getZ() + 0.5D + dz;
level.addParticle(particle, x, y, z, 0.0D, 0.0D, 0.0D);
}
}
public static void addEjectItemParticles(Level level, BlockPos pos, RandomSource random) {
for (int i = 0; i < 20; i++) {
double x = pos.getX() + 0.4D + random.nextDouble() * 0.2D;
double y = pos.getY() + 0.4D + random.nextDouble() * 0.2D;
double z = pos.getZ() + 0.4D + random.nextDouble() * 0.2D;
double xd = random.nextGaussian() * 0.02D;
double yd = random.nextGaussian() * 0.02D;
double zd = random.nextGaussian() * 0.02D;
level.addParticle(ParticleTypes.SMALL_FLAME, x, y, z, xd, yd, zd * 0.25D);
level.addParticle(ParticleTypes.SMOKE, x, y, z, xd, yd, zd);
}
}
}
@@ -0,0 +1,211 @@
package com.craisinlord.antarchy.content.block.entity.undertrial;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.Mth;
import net.minecraft.util.StringRepresentable;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraft.Util;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
public enum UndertrialSpawnerState implements StringRepresentable {
INACTIVE("inactive", 0, -1.0D, false),
WAITING_FOR_PLAYERS("waiting_for_players", 4, 200.0D, true),
ACTIVE("active", 8, 1000.0D, true),
WAITING_FOR_REWARD_EJECTION("waiting_for_reward_ejection", 8, -1.0D, false),
EJECTING_REWARD("ejecting_reward", 8, -1.0D, false),
COOLDOWN("cooldown", 0, -1.0D, false);
private static final float DELAY_BEFORE_EJECT_AFTER_KILLING_LAST_MOB = 40.0F;
private static final int TIME_BETWEEN_EACH_EJECTION = Mth.floor(30.0F);
private final String name;
private final int lightLevel;
private final double spinningMobSpeed;
private final boolean isCapableOfSpawning;
UndertrialSpawnerState(String name, int lightLevel, double spinningMobSpeed, boolean isCapableOfSpawning) {
this.name = name;
this.lightLevel = lightLevel;
this.spinningMobSpeed = spinningMobSpeed;
this.isCapableOfSpawning = isCapableOfSpawning;
}
UndertrialSpawnerState tickAndGetNext(BlockPos pos, UndertrialSpawner spawner, ServerLevel level) {
UndertrialSpawnerData data = spawner.getData();
UndertrialSpawnerConfig config = spawner.getConfig();
switch (this) {
case INACTIVE:
return data.getOrCreateDisplayEntity(spawner, level, WAITING_FOR_PLAYERS) == null ? this : WAITING_FOR_PLAYERS;
case WAITING_FOR_PLAYERS:
if (!spawner.canSpawnInLevel(level)) {
data.reset();
return this;
}
if (!data.hasMobToSpawn(spawner, level.random)) {
return INACTIVE;
}
data.tryDetectPlayers(level, pos, spawner);
return data.detectedPlayers.isEmpty() ? this : ACTIVE;
case ACTIVE: {
if (!spawner.canSpawnInLevel(level)) {
data.reset();
return WAITING_FOR_PLAYERS;
}
if (!data.hasMobToSpawn(spawner, level.random)) {
return INACTIVE;
}
int additionalPlayers = data.countAdditionalPlayers(pos);
data.tryDetectPlayers(level, pos, spawner);
if (spawner.isOminous()) {
spawnOminousItem(level, pos, spawner);
}
if (data.hasFinishedSpawningAllMobs(config, additionalPlayers)) {
if (data.haveAllCurrentMobsDied()) {
data.cooldownEndsAt = level.getGameTime() + spawner.getTargetCooldownLength();
data.totalMobsSpawned = 0;
data.nextMobSpawnsAt = 0L;
return WAITING_FOR_REWARD_EJECTION;
}
} else if (data.isReadyToSpawnNextMob(level, config, additionalPlayers)) {
spawner.spawnMob(level, pos).ifPresent(uuid -> {
data.currentMobs.add(uuid);
data.totalMobsSpawned++;
data.nextMobSpawnsAt = level.getGameTime() + config.ticksBetweenSpawn();
config.spawnPotentialsDefinition().getRandom(level.getRandom()).ifPresent(wrapper -> {
data.nextSpawnData = Optional.of(wrapper.getData());
spawner.markUpdated();
});
});
}
return this;
}
case WAITING_FOR_REWARD_EJECTION:
if (data.isReadyToOpenShutter(level, DELAY_BEFORE_EJECT_AFTER_KILLING_LAST_MOB, spawner.getTargetCooldownLength())) {
UndertrialSounds.playServer(level, pos, UndertrialSounds.TRIAL_SPAWNER_OPEN_SHUTTER, SoundSource.BLOCKS, 1.0F, 1.0F);
return EJECTING_REWARD;
}
return this;
case EJECTING_REWARD:
if (!data.isReadyToEjectItems(level, TIME_BETWEEN_EACH_EJECTION, spawner.getTargetCooldownLength())) {
return this;
}
if (data.detectedPlayers.isEmpty()) {
UndertrialSounds.playServer(level, pos, UndertrialSounds.TRIAL_SPAWNER_CLOSE_SHUTTER, SoundSource.BLOCKS, 1.0F, 1.0F);
data.ejectingLootTable = Optional.empty();
return COOLDOWN;
}
if (data.ejectingLootTable.isEmpty()) {
data.ejectingLootTable = config.lootTablesToEject().getRandomValue(level.getRandom());
}
data.ejectingLootTable.ifPresent(lootTable -> spawner.ejectReward(level, pos, lootTable));
data.detectedPlayers.remove(data.detectedPlayers.iterator().next());
return this;
case COOLDOWN:
default:
data.tryDetectPlayers(level, pos, spawner);
if (!data.detectedPlayers.isEmpty()) {
data.totalMobsSpawned = 0;
data.nextMobSpawnsAt = 0L;
return ACTIVE;
}
if (data.isCooldownFinished(level)) {
spawner.removeOminous(level, pos);
data.reset();
return WAITING_FOR_PLAYERS;
}
return this;
}
}
private void spawnOminousItem(ServerLevel level, BlockPos pos, UndertrialSpawner spawner) {
UndertrialSpawnerData data = spawner.getData();
UndertrialSpawnerConfig config = spawner.getConfig();
ItemStack stack = data.getDispensingItems(level, config, pos).getRandomValue(level.random).orElse(ItemStack.EMPTY);
if (stack.isEmpty() || level.getGameTime() < data.cooldownEndsAt) {
return;
}
calculatePositionToSpawnItem(level, pos, spawner, data).ifPresent(position -> {
ItemEntity item = new ItemEntity(level, position.x, position.y, position.z, stack.copy());
item.setDeltaMovement(Vec3.ZERO);
level.addFreshEntity(item);
float pitch = (level.getRandom().nextFloat() - level.getRandom().nextFloat()) * 0.2F + 1.0F;
UndertrialSounds.playServer(level, BlockPos.containing(position), UndertrialSounds.TRIAL_SPAWNER_SPAWN_ITEM_BEGIN, SoundSource.BLOCKS, 1.0F, pitch);
data.cooldownEndsAt = level.getGameTime() + spawner.getOminousConfig().ticksBetweenItemSpawners();
});
}
private static Optional<Vec3> calculatePositionToSpawnItem(ServerLevel level, BlockPos pos, UndertrialSpawner spawner, UndertrialSpawnerData data) {
List<Player> players = new ArrayList<>();
for (UUID uuid : data.detectedPlayers) {
Player player = level.getPlayerByUUID(uuid);
if (player != null && !player.isCreative() && !player.isSpectator() && player.isAlive()
&& player.distanceToSqr(pos.getCenter()) <= Mth.square(spawner.getRequiredPlayerRange())) {
players.add(player);
}
}
if (players.isEmpty()) {
return Optional.empty();
}
Entity entity = selectEntityToSpawnItemAbove(players, data.currentMobs, spawner, pos, level);
return entity == null ? Optional.empty() : calculatePositionAbove(entity, level);
}
private static Optional<Vec3> calculatePositionAbove(Entity entity, ServerLevel level) {
Vec3 start = entity.position();
Vec3 end = start.relative(Direction.UP, entity.getBbHeight() + 2.0F + level.random.nextInt(4));
BlockHitResult hit = level.clip(new ClipContext(start, end, ClipContext.Block.VISUAL, ClipContext.Fluid.NONE, null));
Vec3 position = hit.getBlockPos().getCenter().relative(Direction.DOWN, 1.0D);
BlockPos blockPos = BlockPos.containing(position);
return !level.getBlockState(blockPos).getCollisionShape(level, blockPos).isEmpty() ? Optional.empty() : Optional.of(position);
}
private static Entity selectEntityToSpawnItemAbove(List<Player> players, Set<UUID> mobs, UndertrialSpawner spawner, BlockPos pos, ServerLevel level) {
List<Entity> livingMobs = new ArrayList<>();
for (UUID uuid : mobs) {
Entity mob = level.getEntity(uuid);
if (mob != null && mob.isAlive() && mob.distanceToSqr(pos.getCenter()) <= Mth.square(spawner.getRequiredPlayerRange())) {
livingMobs.add(mob);
}
}
List<? extends Entity> candidates = level.random.nextBoolean() ? livingMobs : players;
if (candidates.isEmpty()) {
return null;
}
return candidates.size() == 1 ? candidates.get(0) : Objects.requireNonNull(Util.getRandom(candidates, level.random));
}
public int lightLevel() {
return this.lightLevel;
}
public double spinningMobSpeed() {
return this.spinningMobSpeed;
}
public boolean hasSpinningMob() {
return this.spinningMobSpeed >= 0.0D;
}
public boolean isCapableOfSpawning() {
return this.isCapableOfSpawning;
}
@Override
public String getSerializedName() {
return this.name;
}
}
@@ -0,0 +1,22 @@
package com.craisinlord.antarchy.content.block.entity.undervault;
import net.minecraft.util.Mth;
public class UnderVaultClientData {
public static final float ROTATION_SPEED = 10.0F;
private float currentSpin;
private float previousSpin;
public float currentSpin() {
return this.currentSpin;
}
public float previousSpin() {
return this.previousSpin;
}
void updateDisplayItemSpin() {
this.previousSpin = this.currentSpin;
this.currentSpin = Mth.wrapDegrees(this.currentSpin + ROTATION_SPEED);
}
}
@@ -0,0 +1,67 @@
package com.craisinlord.antarchy.content.block.entity.undervault;
import com.craisinlord.antarchy.content.block.entity.undertrial.UndertrialPlayerDetector;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack;
import java.util.Optional;
public record UnderVaultConfig(
ResourceLocation lootTable,
double activationRange,
double deactivationRange,
ItemStack keyItem,
Optional<ResourceLocation> overrideLootTableToDisplay,
UndertrialPlayerDetector playerDetector,
UndertrialPlayerDetector.EntitySelector entitySelector
) {
public static final String TAG_NAME = "config";
public static final ResourceLocation TRIAL_CHAMBERS_REWARD = new ResourceLocation("minecraft", "chests/trial_chambers/reward");
public static final UnderVaultConfig DEFAULT = new UnderVaultConfig(TRIAL_CHAMBERS_REWARD, 4.0D, 4.5D, ItemStack.EMPTY,
Optional.empty(), UndertrialPlayerDetector.INCLUDING_CREATIVE_PLAYERS, UndertrialPlayerDetector.EntitySelector.SELECT_FROM_LEVEL);
public UnderVaultConfig(ResourceLocation lootTable, double activationRange, double deactivationRange, ItemStack keyItem,
Optional<ResourceLocation> overrideLootTableToDisplay) {
this(lootTable, activationRange, deactivationRange, keyItem, overrideLootTableToDisplay,
DEFAULT.playerDetector(), DEFAULT.entitySelector());
}
public static Optional<UnderVaultConfig> load(CompoundTag tag) {
ResourceLocation lootTable = DEFAULT.lootTable;
if (tag.contains("loot_table", Tag.TAG_STRING)) {
ResourceLocation parsed = ResourceLocation.tryParse(tag.getString("loot_table"));
if (parsed != null) {
lootTable = parsed;
}
}
double activation = tag.contains("activation_range", Tag.TAG_ANY_NUMERIC) ? tag.getDouble("activation_range") : DEFAULT.activationRange;
double deactivation = tag.contains("deactivation_range", Tag.TAG_ANY_NUMERIC) ? tag.getDouble("deactivation_range") : DEFAULT.deactivationRange;
ItemStack key = tag.contains("key_item", Tag.TAG_COMPOUND) ? ItemStack.of(tag.getCompound("key_item")) : ItemStack.EMPTY;
Optional<ResourceLocation> override = tag.contains("override_loot_table_to_display", Tag.TAG_STRING)
? Optional.ofNullable(ResourceLocation.tryParse(tag.getString("override_loot_table_to_display"))) : Optional.empty();
if (activation > deactivation) {
return Optional.empty();
}
return Optional.of(new UnderVaultConfig(lootTable, activation, deactivation, key, override));
}
public CompoundTag save() {
CompoundTag tag = new CompoundTag();
if (!this.lootTable.equals(DEFAULT.lootTable)) {
tag.putString("loot_table", this.lootTable.toString());
}
if (this.activationRange != DEFAULT.activationRange) {
tag.putDouble("activation_range", this.activationRange);
}
if (this.deactivationRange != DEFAULT.deactivationRange) {
tag.putDouble("deactivation_range", this.deactivationRange);
}
if (!this.keyItem.isEmpty()) {
tag.put("key_item", this.keyItem.save(new CompoundTag()));
}
this.overrideLootTableToDisplay.ifPresent(id -> tag.putString("override_loot_table_to_display", id.toString()));
return tag;
}
}
@@ -0,0 +1,61 @@
package com.craisinlord.antarchy.content.block.entity.undervault;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.world.level.Level;
public final class UnderVaultData {
private final UnderVaultServerData serverData = new UnderVaultServerData();
private final UnderVaultSharedData sharedData = new UnderVaultSharedData();
private final UnderVaultClientData clientData = new UnderVaultClientData();
private UnderVaultConfig config = UnderVaultConfig.DEFAULT;
private Level level;
public void setLevel(Level level) {
this.level = level;
}
public Level getLevel() {
return this.level;
}
public CompoundTag save() {
CompoundTag tag = new CompoundTag();
tag.put(UnderVaultConfig.TAG_NAME, this.config.save());
tag.put(UnderVaultSharedData.TAG_NAME, this.sharedData.save());
tag.put(UnderVaultServerData.TAG_NAME, this.serverData.save());
return tag;
}
public void load(CompoundTag tag) {
if (tag.contains(UnderVaultServerData.TAG_NAME, Tag.TAG_COMPOUND)) {
this.serverData.set(UnderVaultServerData.load(tag.getCompound(UnderVaultServerData.TAG_NAME)));
}
if (tag.contains(UnderVaultConfig.TAG_NAME, Tag.TAG_COMPOUND)) {
UnderVaultConfig.load(tag.getCompound(UnderVaultConfig.TAG_NAME)).ifPresent(loaded -> this.config = loaded);
}
if (tag.contains(UnderVaultSharedData.TAG_NAME, Tag.TAG_COMPOUND)) {
this.sharedData.set(UnderVaultSharedData.load(tag.getCompound(UnderVaultSharedData.TAG_NAME)));
}
}
public UnderVaultServerData getServerData() {
return this.level != null && !this.level.isClientSide ? this.serverData : null;
}
public UnderVaultSharedData getSharedData() {
return this.sharedData;
}
public UnderVaultClientData getClientData() {
return this.clientData;
}
public UnderVaultConfig getConfig() {
return this.config;
}
public void setConfig(UnderVaultConfig config) {
this.config = config;
}
}
@@ -0,0 +1,44 @@
package com.craisinlord.antarchy.content.block.entity.undervault;
import com.craisinlord.antarchy.content.block.entity.undertrial.UndertrialSounds;
import com.craisinlord.antarchy.content.block.entity.undertrial.UndertrialSpawnerEffects;
import net.minecraft.core.BlockPos;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.Level;
public final class UnderVaultEffects {
private static final int DEACTIVATE = 1;
private static final int EJECT_ITEM = 2;
private UnderVaultEffects() {
}
public static void deactivate(ServerLevel level, BlockPos pos, boolean ominous) {
level.blockEvent(pos, level.getBlockState(pos).getBlock(), DEACTIVATE, ominous ? 1 : 0);
}
public static void ejectItem(ServerLevel level, BlockPos pos) {
level.blockEvent(pos, level.getBlockState(pos).getBlock(), EJECT_ITEM, 0);
}
public static boolean handle(Level level, BlockPos pos, int id, int param) {
if (!level.isClientSide) {
return id == DEACTIVATE || id == EJECT_ITEM;
}
RandomSource random = level.random;
if (id == DEACTIVATE) {
UnderVaultLogic.Client.emitDeactivationParticles(level, pos, param == 0 ? ParticleTypes.SMALL_FLAME : ParticleTypes.SOUL_FIRE_FLAME);
UndertrialSounds.playLocal(level, pos, UndertrialSounds.VAULT_DEACTIVATE, SoundSource.BLOCKS, 1.0F,
(random.nextFloat() - random.nextFloat()) * 0.2F + 1.0F, true);
return true;
}
if (id == EJECT_ITEM) {
UndertrialSpawnerEffects.addEjectItemParticles(level, pos, random);
return true;
}
return false;
}
}
@@ -0,0 +1,261 @@
package com.craisinlord.antarchy.content.block.entity.undervault;
import com.craisinlord.antarchy.content.block.UnderVaultBlock;
import com.craisinlord.antarchy.content.block.entity.undertrial.UndertrialSounds;
import net.minecraft.Util;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundSource;
import net.minecraft.stats.Stats;
import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.storage.loot.BuiltInLootTables;
import net.minecraft.world.level.storage.loot.LootParams;
import net.minecraft.world.level.storage.loot.LootTable;
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets;
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
import net.minecraft.world.phys.Vec3;
import java.util.List;
import java.util.Set;
import java.util.UUID;
public final class UnderVaultLogic {
private UnderVaultLogic() {
}
public static final class Client {
private static final int PARTICLE_TICK_RATE = 20;
private static final float IDLE_PARTICLE_CHANCE = 0.5F;
private static final float AMBIENT_SOUND_CHANCE = 0.02F;
private static final int ACTIVATION_PARTICLE_COUNT = 20;
private static final int DEACTIVATION_PARTICLE_COUNT = 20;
private Client() {
}
public static void tick(Level level, BlockPos pos, BlockState state, UnderVaultClientData clientData, UnderVaultSharedData sharedData) {
clientData.updateDisplayItemSpin();
if (level.getGameTime() % PARTICLE_TICK_RATE == 0L) {
emitConnectionParticlesForNearbyPlayers(level, pos, state, sharedData);
}
emitIdleParticles(level, pos, sharedData, state.getValue(UnderVaultBlock.OMINOUS) ? ParticleTypes.SOUL_FIRE_FLAME : ParticleTypes.SMALL_FLAME);
playIdleSounds(level, pos, sharedData);
}
public static void emitActivationParticles(Level level, BlockPos pos, BlockState state, UnderVaultSharedData sharedData, ParticleOptions particle) {
emitConnectionParticlesForNearbyPlayers(level, pos, state, sharedData);
RandomSource random = level.random;
for (int i = 0; i < ACTIVATION_PARTICLE_COUNT; i++) {
Vec3 position = randomPosInsideCage(pos, random);
level.addParticle(ParticleTypes.SMOKE, position.x(), position.y(), position.z(), 0.0D, 0.0D, 0.0D);
level.addParticle(particle, position.x(), position.y(), position.z(), 0.0D, 0.0D, 0.0D);
}
}
public static void emitDeactivationParticles(Level level, BlockPos pos, ParticleOptions particle) {
RandomSource random = level.random;
for (int i = 0; i < DEACTIVATION_PARTICLE_COUNT; i++) {
Vec3 position = randomPosCenterOfCage(pos, random);
Vec3 velocity = new Vec3(random.nextGaussian() * 0.02D, random.nextGaussian() * 0.02D, random.nextGaussian() * 0.02D);
level.addParticle(particle, position.x(), position.y(), position.z(), velocity.x(), velocity.y(), velocity.z());
}
}
private static void emitIdleParticles(Level level, BlockPos pos, UnderVaultSharedData sharedData, ParticleOptions particle) {
RandomSource random = level.getRandom();
if (random.nextFloat() <= IDLE_PARTICLE_CHANCE) {
Vec3 position = randomPosInsideCage(pos, random);
level.addParticle(ParticleTypes.SMOKE, position.x(), position.y(), position.z(), 0.0D, 0.0D, 0.0D);
if (shouldDisplayActiveEffects(sharedData)) {
level.addParticle(particle, position.x(), position.y(), position.z(), 0.0D, 0.0D, 0.0D);
}
}
}
private static void emitConnectionParticlesForPlayer(Level level, Vec3 keyhole, Player player) {
RandomSource random = level.random;
Vec3 toPlayer = keyhole.vectorTo(player.position().add(0.0D, player.getBbHeight() / 2.0F, 0.0D));
int count = Mth.nextInt(random, 2, 5);
for (int i = 0; i < count; i++) {
Vec3 offset = toPlayer.offsetRandom(random, 1.0F);
level.addParticle(ParticleTypes.ENCHANT, keyhole.x(), keyhole.y(), keyhole.z(), offset.x(), offset.y(), offset.z());
}
}
private static void emitConnectionParticlesForNearbyPlayers(Level level, BlockPos pos, BlockState state, UnderVaultSharedData sharedData) {
Set<UUID> players = sharedData.getConnectedPlayers();
if (players.isEmpty()) {
return;
}
Vec3 keyhole = keyholePos(pos, state.getValue(UnderVaultBlock.FACING));
for (UUID uuid : players) {
Player player = level.getPlayerByUUID(uuid);
if (player != null && isWithinConnectionRange(pos, sharedData, player)) {
emitConnectionParticlesForPlayer(level, keyhole, player);
}
}
}
private static boolean isWithinConnectionRange(BlockPos pos, UnderVaultSharedData sharedData, Player player) {
return player.blockPosition().distSqr(pos) <= Mth.square(sharedData.connectedParticlesRange());
}
private static void playIdleSounds(Level level, BlockPos pos, UnderVaultSharedData sharedData) {
if (shouldDisplayActiveEffects(sharedData)) {
RandomSource random = level.getRandom();
if (random.nextFloat() <= AMBIENT_SOUND_CHANCE) {
UndertrialSounds.playLocal(level, pos, UndertrialSounds.VAULT_AMBIENT, SoundSource.BLOCKS,
random.nextFloat() * 0.25F + 0.75F, random.nextFloat() + 0.5F, false);
}
}
}
public static boolean shouldDisplayActiveEffects(UnderVaultSharedData sharedData) {
return sharedData.hasDisplayItem();
}
private static Vec3 randomPosCenterOfCage(BlockPos pos, RandomSource random) {
return Vec3.atLowerCornerOf(pos).add(Mth.nextDouble(random, 0.4D, 0.6D), Mth.nextDouble(random, 0.4D, 0.6D), Mth.nextDouble(random, 0.4D, 0.6D));
}
private static Vec3 randomPosInsideCage(BlockPos pos, RandomSource random) {
return Vec3.atLowerCornerOf(pos).add(Mth.nextDouble(random, 0.1D, 0.9D), Mth.nextDouble(random, 0.25D, 0.75D), Mth.nextDouble(random, 0.1D, 0.9D));
}
private static Vec3 keyholePos(BlockPos pos, Direction direction) {
return Vec3.atBottomCenterOf(pos).add(direction.getStepX() * 0.5D, 1.75D, direction.getStepZ() * 0.5D);
}
}
public static final class Server {
private static final int UNLOCKING_DELAY_TICKS = 14;
private static final int DISPLAY_CYCLE_TICK_RATE = 20;
private static final int INSERT_FAIL_SOUND_BUFFER_TICKS = 15;
private Server() {
}
public static void tick(ServerLevel level, BlockPos pos, BlockState state, UnderVaultConfig config,
UnderVaultServerData serverData, UnderVaultSharedData sharedData) {
UnderVaultState vaultState = state.getValue(UnderVaultBlock.STATE);
if (shouldCycleDisplayItem(level.getGameTime(), vaultState)) {
cycleDisplayItemFromLootTable(level, vaultState, config, sharedData, pos);
}
BlockState nextState = state;
if (level.getGameTime() >= serverData.stateUpdatingResumesAt()) {
nextState = state.setValue(UnderVaultBlock.STATE, vaultState.tickAndGetNext(level, pos, config, serverData, sharedData));
if (!state.equals(nextState)) {
setVaultState(level, pos, state, nextState, config, sharedData);
}
}
if (serverData.isDirty || sharedData.isDirty) {
level.blockEntityChanged(pos);
if (!state.isAir()) {
level.updateNeighbourForOutputSignal(pos, state.getBlock());
}
if (sharedData.isDirty) {
level.sendBlockUpdated(pos, state, nextState, 2);
}
serverData.isDirty = false;
sharedData.isDirty = false;
}
}
public static void tryInsertKey(ServerLevel level, BlockPos pos, BlockState state, UnderVaultConfig config,
UnderVaultServerData serverData, UnderVaultSharedData sharedData, Player player, ItemStack stack) {
UnderVaultState vaultState = state.getValue(UnderVaultBlock.STATE);
if (!canEjectReward(config, vaultState)) {
return;
}
if (!isValidToInsert(config, stack)) {
playInsertFailSound(level, serverData, pos, UndertrialSounds.VAULT_INSERT_ITEM_FAIL);
} else if (serverData.hasRewardedPlayer(player)) {
playInsertFailSound(level, serverData, pos, UndertrialSounds.VAULT_REJECT_REWARDED_PLAYER);
} else {
List<ItemStack> items = resolveItemsToEject(level, config, pos, player);
if (!items.isEmpty()) {
player.awardStat(Stats.ITEM_USED.get(stack.getItem()));
if (!player.getAbilities().instabuild) {
stack.shrink(config.keyItem().getCount());
}
unlock(level, state, pos, config, serverData, sharedData, items);
serverData.addToRewardedPlayers(player);
sharedData.updateConnectedPlayersWithinRange(level, pos, serverData, config, config.deactivationRange());
}
}
}
static void setVaultState(ServerLevel level, BlockPos pos, BlockState oldState, BlockState newState,
UnderVaultConfig config, UnderVaultSharedData sharedData) {
UnderVaultState from = oldState.getValue(UnderVaultBlock.STATE);
UnderVaultState to = newState.getValue(UnderVaultBlock.STATE);
level.setBlock(pos, newState, 3);
from.onTransition(level, pos, to, config, sharedData, newState.getValue(UnderVaultBlock.OMINOUS));
}
static void cycleDisplayItemFromLootTable(ServerLevel level, UnderVaultState state, UnderVaultConfig config,
UnderVaultSharedData sharedData, BlockPos pos) {
if (!canEjectReward(config, state)) {
sharedData.setDisplayItem(ItemStack.EMPTY);
} else {
ItemStack stack = getRandomDisplayItemFromLootTable(level, pos, config.overrideLootTableToDisplay().orElse(config.lootTable()));
sharedData.setDisplayItem(stack);
}
}
private static ItemStack getRandomDisplayItemFromLootTable(ServerLevel level, BlockPos pos, ResourceLocation lootTableId) {
LootTable lootTable = level.getServer().getLootData().getLootTable(lootTableId);
LootParams params = new LootParams.Builder(level)
.withParameter(LootContextParams.ORIGIN, Vec3.atCenterOf(pos))
.create(LootContextParamSets.CHEST);
List<ItemStack> items = lootTable.getRandomItems(params);
return items.isEmpty() ? ItemStack.EMPTY : Util.getRandom(items, level.getRandom());
}
private static void unlock(ServerLevel level, BlockState state, BlockPos pos, UnderVaultConfig config,
UnderVaultServerData serverData, UnderVaultSharedData sharedData, List<ItemStack> items) {
serverData.setItemsToEject(items);
sharedData.setDisplayItem(serverData.getNextItemToEject());
serverData.pauseStateUpdatingUntil(level.getGameTime() + UNLOCKING_DELAY_TICKS);
setVaultState(level, pos, state, state.setValue(UnderVaultBlock.STATE, UnderVaultState.UNLOCKING), config, sharedData);
}
private static List<ItemStack> resolveItemsToEject(ServerLevel level, UnderVaultConfig config, BlockPos pos, Player player) {
LootTable lootTable = level.getServer().getLootData().getLootTable(config.lootTable());
LootParams params = new LootParams.Builder(level)
.withParameter(LootContextParams.ORIGIN, Vec3.atCenterOf(pos))
.withLuck(player.getLuck())
.withParameter(LootContextParams.THIS_ENTITY, player)
.create(LootContextParamSets.CHEST);
return lootTable.getRandomItems(params);
}
private static boolean canEjectReward(UnderVaultConfig config, UnderVaultState state) {
return !config.lootTable().equals(BuiltInLootTables.EMPTY) && !config.keyItem().isEmpty() && state != UnderVaultState.INACTIVE;
}
private static boolean isValidToInsert(UnderVaultConfig config, ItemStack stack) {
return ItemStack.isSameItemSameTags(stack, config.keyItem()) && stack.getCount() >= config.keyItem().getCount();
}
private static boolean shouldCycleDisplayItem(long gameTime, UnderVaultState state) {
return gameTime % DISPLAY_CYCLE_TICK_RATE == 0L && state == UnderVaultState.ACTIVE;
}
private static void playInsertFailSound(ServerLevel level, UnderVaultServerData serverData, BlockPos pos, UndertrialSounds.Entry sound) {
if (level.getGameTime() >= serverData.getLastInsertFailTimestamp() + INSERT_FAIL_SOUND_BUFFER_TICKS) {
UndertrialSounds.playServer(level, pos, sound, SoundSource.BLOCKS, 1.0F, 1.0F);
serverData.setLastInsertFailTimestamp(level.getGameTime());
}
}
}
}
@@ -0,0 +1,158 @@
package com.craisinlord.antarchy.content.block.entity.undervault;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.UUID;
public class UnderVaultServerData {
public static final String TAG_NAME = "server_data";
private static final int MAX_REWARD_PLAYERS = 128;
private final Set<UUID> rewardedPlayers = new ObjectLinkedOpenHashSet<>();
private long stateUpdatingResumesAt;
private final List<ItemStack> itemsToEject = new ObjectArrayList<>();
private long lastInsertFailTimestamp;
private int totalEjectionsNeeded;
boolean isDirty;
public static UnderVaultServerData load(CompoundTag tag) {
UnderVaultServerData data = new UnderVaultServerData();
data.rewardedPlayers.addAll(UnderVaultSharedData.loadUuidSet(tag.get("rewarded_players")));
data.stateUpdatingResumesAt = tag.contains("state_updating_resumes_at", Tag.TAG_ANY_NUMERIC) ? tag.getLong("state_updating_resumes_at") : 0L;
if (tag.contains("items_to_eject", Tag.TAG_LIST)) {
ListTag list = tag.getList("items_to_eject", Tag.TAG_COMPOUND);
List<ItemStack> items = new ObjectArrayList<>();
boolean valid = true;
for (int i = 0; i < list.size(); i++) {
ItemStack stack = ItemStack.of(list.getCompound(i));
if (stack.isEmpty()) {
valid = false;
break;
}
items.add(stack);
}
if (valid) {
data.itemsToEject.addAll(items);
}
}
data.totalEjectionsNeeded = tag.contains("total_ejections_needed", Tag.TAG_ANY_NUMERIC) ? tag.getInt("total_ejections_needed") : 0;
return data;
}
public CompoundTag save() {
CompoundTag tag = new CompoundTag();
if (!this.rewardedPlayers.isEmpty()) {
tag.put("rewarded_players", UnderVaultSharedData.saveUuidSet(this.rewardedPlayers));
}
if (this.stateUpdatingResumesAt != 0L) {
tag.putLong("state_updating_resumes_at", this.stateUpdatingResumesAt);
}
if (!this.itemsToEject.isEmpty()) {
ListTag list = new ListTag();
for (ItemStack stack : this.itemsToEject) {
list.add(stack.save(new CompoundTag()));
}
tag.put("items_to_eject", list);
}
if (this.totalEjectionsNeeded != 0) {
tag.putInt("total_ejections_needed", this.totalEjectionsNeeded);
}
return tag;
}
void setLastInsertFailTimestamp(long timestamp) {
this.lastInsertFailTimestamp = timestamp;
}
long getLastInsertFailTimestamp() {
return this.lastInsertFailTimestamp;
}
Set<UUID> getRewardedPlayers() {
return this.rewardedPlayers;
}
boolean hasRewardedPlayer(Player player) {
return this.rewardedPlayers.contains(player.getUUID());
}
public void addToRewardedPlayers(Player player) {
this.rewardedPlayers.add(player.getUUID());
if (this.rewardedPlayers.size() > MAX_REWARD_PLAYERS) {
Iterator<UUID> iterator = this.rewardedPlayers.iterator();
if (iterator.hasNext()) {
iterator.next();
iterator.remove();
}
}
this.markChanged();
}
long stateUpdatingResumesAt() {
return this.stateUpdatingResumesAt;
}
void pauseStateUpdatingUntil(long time) {
this.stateUpdatingResumesAt = time;
this.markChanged();
}
List<ItemStack> getItemsToEject() {
return this.itemsToEject;
}
void markEjectionFinished() {
this.totalEjectionsNeeded = 0;
this.markChanged();
}
void setItemsToEject(List<ItemStack> items) {
this.itemsToEject.clear();
this.itemsToEject.addAll(items);
this.totalEjectionsNeeded = this.itemsToEject.size();
this.markChanged();
}
ItemStack getNextItemToEject() {
if (this.itemsToEject.isEmpty()) {
return ItemStack.EMPTY;
}
ItemStack stack = this.itemsToEject.get(this.itemsToEject.size() - 1);
return stack != null ? stack : ItemStack.EMPTY;
}
ItemStack popNextItemToEject() {
if (this.itemsToEject.isEmpty()) {
return ItemStack.EMPTY;
}
this.markChanged();
ItemStack stack = this.itemsToEject.remove(this.itemsToEject.size() - 1);
return stack != null ? stack : ItemStack.EMPTY;
}
void set(UnderVaultServerData other) {
this.stateUpdatingResumesAt = other.stateUpdatingResumesAt();
this.itemsToEject.clear();
this.itemsToEject.addAll(other.itemsToEject);
this.rewardedPlayers.clear();
this.rewardedPlayers.addAll(other.rewardedPlayers);
}
private void markChanged() {
this.isDirty = true;
}
public float ejectionProgress() {
return this.totalEjectionsNeeded == 1 ? 1.0F
: 1.0F - Mth.inverseLerp((float) this.getItemsToEject().size(), 1.0F, (float) this.totalEjectionsNeeded);
}
}
@@ -0,0 +1,118 @@
package com.craisinlord.antarchy.content.block.entity.undervault;
import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.IntArrayTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.nbt.Tag;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.item.ItemStack;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
public class UnderVaultSharedData {
public static final String TAG_NAME = "shared_data";
private ItemStack displayItem = ItemStack.EMPTY;
private Set<UUID> connectedPlayers = new ObjectLinkedOpenHashSet<>();
private double connectedParticlesRange = UnderVaultConfig.DEFAULT.deactivationRange();
boolean isDirty;
public static UnderVaultSharedData load(CompoundTag tag) {
UnderVaultSharedData data = new UnderVaultSharedData();
data.displayItem = tag.contains("display_item", Tag.TAG_COMPOUND) ? ItemStack.of(tag.getCompound("display_item")) : ItemStack.EMPTY;
data.connectedPlayers.addAll(loadUuidSet(tag.get("connected_players")));
data.connectedParticlesRange = tag.contains("connected_particles_range", Tag.TAG_ANY_NUMERIC)
? tag.getDouble("connected_particles_range") : UnderVaultConfig.DEFAULT.deactivationRange();
return data;
}
public CompoundTag save() {
CompoundTag tag = new CompoundTag();
if (!this.displayItem.isEmpty()) {
tag.put("display_item", this.displayItem.save(new CompoundTag()));
}
if (!this.connectedPlayers.isEmpty()) {
tag.put("connected_players", saveUuidSet(this.connectedPlayers));
}
if (this.connectedParticlesRange != UnderVaultConfig.DEFAULT.deactivationRange()) {
tag.putDouble("connected_particles_range", this.connectedParticlesRange);
}
return tag;
}
static Set<UUID> loadUuidSet(Tag tag) {
Set<UUID> result = new ObjectLinkedOpenHashSet<>();
if (!(tag instanceof ListTag list)) {
return result;
}
for (Tag element : list) {
if (!(element instanceof IntArrayTag array) || array.size() != 4) {
return new ObjectLinkedOpenHashSet<>();
}
result.add(NbtUtils.loadUUID(array));
}
return result;
}
static ListTag saveUuidSet(Set<UUID> uuids) {
ListTag list = new ListTag();
for (UUID uuid : uuids) {
list.add(NbtUtils.createUUID(uuid));
}
return list;
}
public ItemStack getDisplayItem() {
return this.displayItem;
}
public boolean hasDisplayItem() {
return !this.displayItem.isEmpty();
}
public void setDisplayItem(ItemStack stack) {
if (!ItemStack.matches(this.displayItem, stack)) {
this.displayItem = stack.copy();
this.markDirty();
}
}
boolean hasConnectedPlayers() {
return !this.connectedPlayers.isEmpty();
}
Set<UUID> getConnectedPlayers() {
return this.connectedPlayers;
}
double connectedParticlesRange() {
return this.connectedParticlesRange;
}
void updateConnectedPlayersWithinRange(ServerLevel level, BlockPos pos, UnderVaultServerData serverData, UnderVaultConfig config, double range) {
Set<UUID> players = new HashSet<>();
for (UUID uuid : config.playerDetector().detect(level, config.entitySelector(), pos, range, false)) {
if (!serverData.getRewardedPlayers().contains(uuid)) {
players.add(uuid);
}
}
if (!this.connectedPlayers.equals(players)) {
this.connectedPlayers = players;
this.markDirty();
}
}
private void markDirty() {
this.isDirty = true;
}
void set(UnderVaultSharedData other) {
this.displayItem = other.displayItem;
this.connectedPlayers = other.connectedPlayers;
this.connectedParticlesRange = other.connectedParticlesRange;
}
}
@@ -0,0 +1,119 @@
package com.craisinlord.antarchy.content.block.entity.undervault;
import com.craisinlord.antarchy.content.block.entity.undertrial.UndertrialSounds;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.dispenser.DefaultDispenseItemBehavior;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.StringRepresentable;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.Vec3;
public enum UnderVaultState implements StringRepresentable {
INACTIVE("inactive", 6) {
@Override
protected void onEnter(ServerLevel level, BlockPos pos, UnderVaultConfig config, UnderVaultSharedData sharedData, boolean ominous) {
sharedData.setDisplayItem(ItemStack.EMPTY);
UnderVaultEffects.deactivate(level, pos, ominous);
}
},
ACTIVE("active", 12) {
@Override
protected void onEnter(ServerLevel level, BlockPos pos, UnderVaultConfig config, UnderVaultSharedData sharedData, boolean ominous) {
if (!sharedData.hasDisplayItem()) {
UnderVaultLogic.Server.cycleDisplayItemFromLootTable(level, this, config, sharedData, pos);
}
}
},
UNLOCKING("unlocking", 12) {
@Override
protected void onEnter(ServerLevel level, BlockPos pos, UnderVaultConfig config, UnderVaultSharedData sharedData, boolean ominous) {
UndertrialSounds.playServer(level, pos, UndertrialSounds.VAULT_INSERT_ITEM, SoundSource.BLOCKS, 1.0F, 1.0F);
}
},
EJECTING("ejecting", 12) {
@Override
protected void onEnter(ServerLevel level, BlockPos pos, UnderVaultConfig config, UnderVaultSharedData sharedData, boolean ominous) {
UndertrialSounds.playServer(level, pos, UndertrialSounds.VAULT_OPEN_SHUTTER, SoundSource.BLOCKS, 1.0F, 1.0F);
}
@Override
protected void onExit(ServerLevel level, BlockPos pos, UnderVaultConfig config, UnderVaultSharedData sharedData) {
UndertrialSounds.playServer(level, pos, UndertrialSounds.VAULT_CLOSE_SHUTTER, SoundSource.BLOCKS, 1.0F, 1.0F);
}
};
private static final int UPDATE_CONNECTED_PLAYERS_TICK_RATE = 20;
private static final int DELAY_BETWEEN_EJECTIONS_TICKS = 20;
private static final int DELAY_AFTER_LAST_EJECTION_TICKS = 20;
private static final int DELAY_BEFORE_FIRST_EJECTION_TICKS = 20;
private final String stateName;
private final int lightLevel;
UnderVaultState(String stateName, int lightLevel) {
this.stateName = stateName;
this.lightLevel = lightLevel;
}
@Override
public String getSerializedName() {
return this.stateName;
}
public int lightLevel() {
return this.lightLevel;
}
public UnderVaultState tickAndGetNext(ServerLevel level, BlockPos pos, UnderVaultConfig config, UnderVaultServerData serverData,
UnderVaultSharedData sharedData) {
switch (this) {
case INACTIVE:
return updateStateForConnectedPlayers(level, pos, config, serverData, sharedData, config.activationRange());
case ACTIVE:
return updateStateForConnectedPlayers(level, pos, config, serverData, sharedData, config.deactivationRange());
case UNLOCKING:
serverData.pauseStateUpdatingUntil(level.getGameTime() + DELAY_BEFORE_FIRST_EJECTION_TICKS);
return EJECTING;
case EJECTING:
default:
if (serverData.getItemsToEject().isEmpty()) {
serverData.markEjectionFinished();
return updateStateForConnectedPlayers(level, pos, config, serverData, sharedData, config.deactivationRange());
}
float progress = serverData.ejectionProgress();
this.ejectResultItem(level, pos, serverData.popNextItemToEject(), progress);
sharedData.setDisplayItem(serverData.getNextItemToEject());
boolean finished = serverData.getItemsToEject().isEmpty();
int delay = finished ? DELAY_AFTER_LAST_EJECTION_TICKS : DELAY_BETWEEN_EJECTIONS_TICKS;
serverData.pauseStateUpdatingUntil(level.getGameTime() + delay);
return EJECTING;
}
}
private static UnderVaultState updateStateForConnectedPlayers(ServerLevel level, BlockPos pos, UnderVaultConfig config,
UnderVaultServerData serverData, UnderVaultSharedData sharedData,
double range) {
sharedData.updateConnectedPlayersWithinRange(level, pos, serverData, config, range);
serverData.pauseStateUpdatingUntil(level.getGameTime() + UPDATE_CONNECTED_PLAYERS_TICK_RATE);
return sharedData.hasConnectedPlayers() ? ACTIVE : INACTIVE;
}
public void onTransition(ServerLevel level, BlockPos pos, UnderVaultState next, UnderVaultConfig config,
UnderVaultSharedData sharedData, boolean ominous) {
this.onExit(level, pos, config, sharedData);
next.onEnter(level, pos, config, sharedData, ominous);
}
protected void onEnter(ServerLevel level, BlockPos pos, UnderVaultConfig config, UnderVaultSharedData sharedData, boolean ominous) {
}
protected void onExit(ServerLevel level, BlockPos pos, UnderVaultConfig config, UnderVaultSharedData sharedData) {
}
private void ejectResultItem(ServerLevel level, BlockPos pos, ItemStack stack, float progress) {
DefaultDispenseItemBehavior.spawnItem(level, stack, 2, Direction.UP, Vec3.atBottomCenterOf(pos).relative(Direction.UP, 1.2D));
UnderVaultEffects.ejectItem(level, pos);
UndertrialSounds.playServer(level, pos, UndertrialSounds.VAULT_EJECT_ITEM, SoundSource.BLOCKS, 1.0F, 0.8F + 0.4F * progress);
}
}
@@ -1,11 +1,29 @@
package com.craisinlord.antarchy.content.boss; package com.craisinlord.antarchy.content.boss;
import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.AntarchyTags;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.Mob;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public final class BossCombatUtil { public final class BossCombatUtil {
private BossCombatUtil() {} private BossCombatUtil() {}
private static final Map<UUID, MagicWindowState> MAGIC_WINDOWS = new HashMap<>();
private static final Map<UUID, Long> MAGIC_WARD_EXPIRY_TICK = new HashMap<>();
private static final Map<UUID, Integer> MAGIC_WARD_BREACH_COUNTS = new HashMap<>();
private static final class MagicWindowState {
long windowStartTick;
float accumulated;
}
public static boolean isOutOfDamageRange(Mob boss, double range) { public static boolean isOutOfDamageRange(Mob boss, double range) {
if (range <= 0.0D) { if (range <= 0.0D) {
return false; return false;
@@ -13,17 +31,63 @@ public final class BossCombatUtil {
return boss.level().getNearestPlayer(boss, range) == null; return boss.level().getNearestPlayer(boss, range) == null;
} }
/** public static void clampHalfHealthCrossing(LivingEntity boss, float preHitHealth) {
* Caps a single hit so it cannot bring the boss from above half of its max health
* down past that threshold in one shot. Once the boss is at or below half health,
* hits are no longer capped.
*/
public static float capSingleHitAtHalfHealth(LivingEntity boss, float amount) {
float halfHealth = boss.getMaxHealth() * 0.5F; float halfHealth = boss.getMaxHealth() * 0.5F;
float currentHealth = boss.getHealth(); if (preHitHealth > halfHealth && boss.getHealth() < halfHealth) {
if (currentHealth > halfHealth && currentHealth - amount < halfHealth) { boss.setHealth(halfHealth);
return currentHealth - halfHealth;
} }
return amount; }
public static boolean isMagicBurstSource(DamageSource source) {
if (source.is(AntarchyTags.DamageType.ANTARCHY_MAGIC_BURST)) {
return true;
}
ResourceLocation typeId = source.typeHolder().unwrapKey().map(ResourceKey::location).orElse(null);
if (typeId == null) {
return false;
}
for (String namespace : AntarchySettings.magicBurstDamageNamespaces()) {
if (typeId.getNamespace().equals(namespace)) {
return true;
}
}
return false;
}
public static float trackMagicBurstWindow(LivingEntity boss, float amount, int windowTicks) {
long now = boss.level().getGameTime();
MagicWindowState state = MAGIC_WINDOWS.computeIfAbsent(boss.getUUID(), id -> new MagicWindowState());
if (now - state.windowStartTick >= windowTicks) {
state.windowStartTick = now;
state.accumulated = 0.0F;
}
state.accumulated += amount;
return state.accumulated;
}
public static float remainingWindowBudget(LivingEntity boss, float windowCap) {
MagicWindowState state = MAGIC_WINDOWS.get(boss.getUUID());
if (state == null) {
return windowCap;
}
long now = boss.level().getGameTime();
if (now - state.windowStartTick >= AntarchySettings.bossMagicWindowTicks()) {
return windowCap;
}
return Math.max(0.0F, windowCap - state.accumulated);
}
public static boolean isMagicWarded(LivingEntity boss) {
Long expiryTick = MAGIC_WARD_EXPIRY_TICK.get(boss.getUUID());
return expiryTick != null && boss.level().getGameTime() < expiryTick;
}
public static void triggerMagicWard(LivingEntity boss, int durationTicks) {
MAGIC_WARD_EXPIRY_TICK.put(boss.getUUID(), boss.level().getGameTime() + durationTicks);
MAGIC_WARD_BREACH_COUNTS.remove(boss.getUUID());
}
public static int recordMagicWindowBreach(LivingEntity boss) {
return MAGIC_WARD_BREACH_COUNTS.merge(boss.getUUID(), 1, Integer::sum);
} }
} }
@@ -0,0 +1,15 @@
package com.craisinlord.antarchy.content.client;
import com.craisinlord.antarchy.content.entity.nightmare.NightmareEntity;
import com.craisinlord.antos.api.client.archive.ArchiveEntityPreviewRegistry;
import net.minecraft.resources.ResourceLocation;
public final class AntarchyArchivePreviews {
private AntarchyArchivePreviews() {}
public static void register() {
ArchiveEntityPreviewRegistry.register(new ResourceLocation("antarchy", "nightmare"), entity -> {
if (entity instanceof NightmareEntity nightmare) nightmare.setArchivePreviewFlying();
});
}
}
@@ -0,0 +1,27 @@
package com.craisinlord.antarchy.content.client;
import com.craisinlord.antarchy.content.network.AntarchyGamePayload;
import com.craisinlord.antarchy.content.network.AntarchyGameResultPayload;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import net.minecraft.core.BlockPos;
public final class AntarchyGameClientState {
private static final Map<String, String> GAME_STATES = new ConcurrentHashMap<>();
private AntarchyGameClientState() { }
public static void update(AntarchyGameResultPayload result) {
String[] envelope = result.data().split("\u0000", 3);
if (envelope.length < 3) return;
if (envelope[0].equals(Integer.toString(AntarchyGamePayload.BASILISK_STATE))
|| envelope[0].equals(Integer.toString(AntarchyGamePayload.ANTMAN_STATE))) {
GAME_STATES.put(key(result.pos(), envelope[0]),
result.success() ? envelope[2] : "");
}
}
public static String getGameState(BlockPos pos, int action) { return GAME_STATES.get(key(pos, Integer.toString(action))); }
public static void clearGameState(BlockPos pos, int action) { GAME_STATES.remove(key(pos, Integer.toString(action))); }
private static String key(BlockPos pos, String action) { return pos.asLong() + "|" + action; }
}
@@ -1,92 +0,0 @@
package com.craisinlord.antarchy.content.client;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.function.BooleanSupplier;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.phys.Vec3;
public final class CameraShakeClientState {
public static final double TORETERROR_RANGE = 48.0D;
public static final float TORETERROR_STRENGTH = 1.0F;
public static final double NIGHTMARE_RANGE = 32.0D;
public static final float NIGHTMARE_STRENGTH = 1.35F;
private record Source(double range, float strength, BooleanSupplier active) {
}
private record Impact(Vec3 position, float intensity, int remainingTicks, int totalTicks, float radius) {
private Impact ticked() {
return new Impact(position, intensity, remainingTicks - 1, totalTicks, radius);
}
}
private static final Map<LivingEntity, Source> SOURCES = new HashMap<>();
private static final java.util.List<Impact> IMPACTS = new java.util.ArrayList<>();
private CameraShakeClientState() {
}
public static void register(LivingEntity entity, double range, float strength, BooleanSupplier active) {
SOURCES.putIfAbsent(entity, new Source(range, strength, active));
}
public static float getStrength(Vec3 cameraPos) {
float total = 0.0F;
Iterator<Map.Entry<LivingEntity, Source>> iterator = SOURCES.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<LivingEntity, Source> entry = iterator.next();
LivingEntity entity = entry.getKey();
Source source = entry.getValue();
if (entity.isRemoved() || !entity.isAlive() || !source.active().getAsBoolean()) {
iterator.remove();
continue;
}
double distance = Math.sqrt(cameraPos.distanceToSqr(entity.position().add(0.0D, entity.getBbHeight() * 0.5D, 0.0D)));
if (distance > source.range()) {
continue;
}
total += (float) ((1.0D - distance / source.range()) * source.strength());
}
Iterator<Impact> impactIterator = IMPACTS.iterator();
while (impactIterator.hasNext()) {
Impact impact = impactIterator.next();
if (impact.remainingTicks() <= 0) {
impactIterator.remove();
continue;
}
double distance = Math.sqrt(cameraPos.distanceToSqr(impact.position()));
if (distance > impact.radius()) {
continue;
}
total += (float) ((1.0D - distance / impact.radius()) * impact.intensity() * (impact.remainingTicks() / (float) Math.max(1, impact.totalTicks())));
}
return total;
}
public static void triggerImpact(Vec3 position, float intensity, int durationTicks, float radius) {
int ticks = Math.max(1, durationTicks);
IMPACTS.add(new Impact(position, intensity, ticks, ticks, Math.max(1.0F, radius)));
}
public static void tick() {
for (int i = IMPACTS.size() - 1; i >= 0; i--) {
Impact impact = IMPACTS.get(i);
if (impact.remainingTicks() <= 1) {
IMPACTS.remove(i);
} else {
IMPACTS.set(i, impact.ticked());
}
}
}
public static void clear() {
SOURCES.clear();
IMPACTS.clear();
}
}
@@ -1,146 +0,0 @@
package com.craisinlord.antarchy.content.client;
import com.craisinlord.antarchy.content.time.TimeDilationFieldSnapshot;
import com.craisinlord.antarchy.content.time.TimeDilationFieldSnapshotSampler;
import com.craisinlord.antarchy.content.time.TimeDilationMath;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
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.util.Mth;
public final class ClientTimeDilationTicker {
private static volatile List<TimeDilationFieldSnapshot> activeFields = List.of();
private static ClientLevel activeLevel;
private static final Map<ItemEntity, ItemSpinState> ITEM_SPIN_STATES = new WeakHashMap<>();
private static final Map<LivingEntity, AttackAnimationState> ATTACK_ANIMATION_STATES = new WeakHashMap<>();
private static final Map<Entity, AnimationClockState> ANIMATION_CLOCKS = new WeakHashMap<>();
private ClientTimeDilationTicker() {
}
public static void tick(ClientLevel level) {
if (activeLevel != level) {
activeLevel = level;
activeFields = List.of();
ITEM_SPIN_STATES.clear();
ATTACK_ANIMATION_STATES.clear();
ANIMATION_CLOCKS.clear();
com.craisinlord.antarchy.content.time.TimeDilationApi.clearSyncedClientRates();
}
}
public static float dilateAnimationTime(Entity entity, float vanillaTime) {
double rate = com.craisinlord.antarchy.content.time.TimeDilationApi.getRate(entity);
if (rate >= TimeDilationMath.NORMAL_RATE) {
ANIMATION_CLOCKS.remove(entity);
return vanillaTime;
}
AnimationClockState state = ANIMATION_CLOCKS.computeIfAbsent(entity,
ignored -> new AnimationClockState(vanillaTime));
float delta = vanillaTime - state.lastVanillaTime;
if (delta >= 0.0F) {
state.temporalTime += delta * (float) rate;
}
state.lastVanillaTime = vanillaTime;
return state.temporalTime;
}
public static float dilateAttackAnimation(LivingEntity entity, float partialTick, float vanillaAnimation) {
double rate = com.craisinlord.antarchy.content.time.TimeDilationApi.getRate(entity);
if (rate >= TimeDilationMath.NORMAL_RATE) {
ATTACK_ANIMATION_STATES.remove(entity);
return vanillaAnimation;
}
AttackAnimationState state = ATTACK_ANIMATION_STATES.computeIfAbsent(
entity, ignored -> new AttackAnimationState(entity.tickCount, vanillaAnimation)
);
if (state.lastTick != entity.tickCount) {
state.previous = state.current;
state.current += (vanillaAnimation - state.current) * (float) rate;
state.lastTick = entity.tickCount;
}
return state.previous + (state.current - state.previous) * partialTick;
}
public static float dilateRotation(LivingEntity entity, float previous, float current, float partialTick) {
double rate = com.craisinlord.antarchy.content.time.TimeDilationApi.getRate(entity);
if (rate >= TimeDilationMath.NORMAL_RATE) {
return Mth.rotLerp(partialTick, previous, current);
}
return previous + Mth.wrapDegrees(current - previous) * partialTick * (float) rate;
}
public static float dilatePitch(LivingEntity entity, float previous, float current, float partialTick) {
double rate = com.craisinlord.antarchy.content.time.TimeDilationApi.getRate(entity);
if (rate >= TimeDilationMath.NORMAL_RATE) {
return Mth.lerp(partialTick, previous, current);
}
return previous + (current - previous) * partialTick * (float) rate;
}
public static float dilateWalkAmount(LivingEntity entity, float amount) {
double rate = com.craisinlord.antarchy.content.time.TimeDilationApi.getRate(entity);
return rate >= TimeDilationMath.NORMAL_RATE ? amount : amount * (float) rate;
}
public static float dilateItemSpin(ItemEntity item, float vanillaSpin) {
double rate = com.craisinlord.antarchy.content.time.TimeDilationApi.getRate(item);
if (rate >= TimeDilationMath.NORMAL_RATE) {
ITEM_SPIN_STATES.remove(item);
return vanillaSpin;
}
ItemSpinState state = ITEM_SPIN_STATES.computeIfAbsent(item, ignored -> new ItemSpinState(vanillaSpin));
float rawDelta = vanillaSpin - state.lastVanillaSpin;
state.lastVanillaSpin = vanillaSpin;
state.temporalSpin += rawDelta * (float) rate;
return state.temporalSpin;
}
private static final class ItemSpinState {
private float lastVanillaSpin;
private float temporalSpin;
private ItemSpinState(float initialSpin) {
this.lastVanillaSpin = initialSpin;
this.temporalSpin = initialSpin;
}
}
private static final class AttackAnimationState {
private int lastTick;
private float previous;
private float current;
private AttackAnimationState(int tick, float initial) {
this.lastTick = tick;
this.previous = initial;
this.current = initial;
}
}
private static final class AnimationClockState {
private float lastVanillaTime;
private float temporalTime;
private AnimationClockState(float initialTime) {
this.lastVanillaTime = initialTime;
this.temporalTime = initialTime;
}
}
public static double rateAt(double x, double y, double z) {
List<TimeDilationFieldSnapshot> fields = activeFields;
if (fields.isEmpty()) {
return TimeDilationMath.NORMAL_RATE;
}
return TimeDilationFieldSnapshotSampler.sample(fields, x, y, z);
}
public static void applyFields(List<TimeDilationFieldSnapshot> fields) {
activeFields = List.copyOf(fields);
}
}
@@ -1,62 +0,0 @@
package com.craisinlord.antarchy.content.client;
import com.craisinlord.antarchy.content.effect.RoyalEffectHooks;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Iterator;
import java.util.Map;
import java.util.WeakHashMap;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.effect.MobEffect;
public final class ContractionAfterimages {
public static final int MAX_SAMPLES = 10;
public static final int SAMPLE_LIFETIME_TICKS = 13;
private static final Map<LivingEntity, Deque<Sample>> HISTORY = new WeakHashMap<>();
private ContractionAfterimages() {}
public static void tick(ClientLevel level) {
MobEffect contracted = RoyalEffectHooks.contractedHolder();
int now = (int) (level.getGameTime() & 0x7fffffffL);
Iterator<Map.Entry<LivingEntity, Deque<Sample>>> iterator = HISTORY.entrySet().iterator();
while (iterator.hasNext()) {
LivingEntity tracked = iterator.next().getKey();
if (tracked == null || tracked.isRemoved() || !tracked.isAlive() || contracted == null
|| !tracked.hasEffect(contracted)) {
iterator.remove();
}
}
if (contracted == null) return;
for (Entity entity : level.entitiesForRendering()) {
if (!(entity instanceof LivingEntity living) || living.isInvisible() || !living.hasEffect(contracted)) continue;
Deque<Sample> samples = HISTORY.computeIfAbsent(living, ignored -> new ArrayDeque<>());
samples.addFirst(new Sample(living, now));
while (samples.size() > MAX_SAMPLES) samples.removeLast();
}
}
public static Deque<Sample> samples(LivingEntity entity) { return HISTORY.get(entity); }
public static float fade(Sample sample, int now) {
return Math.max(0.0F, 1.0F - (now - sample.recordedTick) / (float) SAMPLE_LIFETIME_TICKS);
}
public static void clear() { HISTORY.clear(); }
public static final class Sample {
public final double x, y, z;
public final float bodyYaw, headYaw, xRot, limbPos, limbSpeed, ageInTicks;
public final int recordedTick;
Sample(LivingEntity entity, int recordedTick) {
this.x = entity.getX(); this.y = entity.getY(); this.z = entity.getZ();
this.bodyYaw = entity.yBodyRot; this.headYaw = entity.getYHeadRot(); this.xRot = entity.getXRot();
this.limbPos = entity.walkAnimation.position();
this.limbSpeed = Math.min(entity.walkAnimation.speed(), 1.0F);
this.ageInTicks = entity.tickCount; this.recordedTick = recordedTick;
}
}
}
@@ -0,0 +1,128 @@
package com.craisinlord.antarchy.content.client;
import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.AntarchySoundEvents;
import com.craisinlord.antarchy.content.entity.HoverboardEntity;
import com.craisinlord.antarchy.mixins.LivingEntityJumpingAccessor;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.sounds.AbstractTickableSoundInstance;
import net.minecraft.client.resources.sounds.SoundInstance;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.Entity;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public final class HoverboardSoundSystem {
private static final float MIN_PITCH = 0.75F;
private static final float MAX_PITCH = 1.6F;
private static final float MIN_VOLUME = 0.45F;
private static final float MAX_VOLUME = 0.8F;
private static final Map<Integer, IdleLoopSound> ACTIVE = new HashMap<>();
private HoverboardSoundSystem() {
}
public static void tick() {
Minecraft mc = Minecraft.getInstance();
if (mc.level == null) {
stopAll(mc);
return;
}
if (mc.isPaused()) {
return;
}
Set<Integer> activeIds = new HashSet<>();
for (Entity entity : mc.level.entitiesForRendering()) {
if (!(entity instanceof HoverboardEntity hoverboard) || !hoverboard.isVehicle()) {
continue;
}
int id = hoverboard.getId();
activeIds.add(id);
IdleLoopSound sound = ACTIVE.get(id);
if (sound == null || !mc.getSoundManager().isActive(sound)) {
sound = new IdleLoopSound(hoverboard);
ACTIVE.put(id, sound);
mc.getSoundManager().play(sound);
}
}
ACTIVE.entrySet().removeIf(entry -> {
if (activeIds.contains(entry.getKey())) {
return false;
}
mc.getSoundManager().stop(entry.getValue());
return true;
});
}
private static void stopAll(Minecraft mc) {
ACTIVE.values().forEach(mc.getSoundManager()::stop);
ACTIVE.clear();
}
private static final class IdleLoopSound extends AbstractTickableSoundInstance {
private final HoverboardEntity hoverboard;
private double lastX;
private double lastZ;
private IdleLoopSound(HoverboardEntity hoverboard) {
super(AntarchySoundEvents.HOVERBOARD_IDLE.get(), SoundSource.NEUTRAL, RandomSource.create());
this.hoverboard = hoverboard;
this.looping = true;
this.delay = 0;
this.relative = false;
this.attenuation = SoundInstance.Attenuation.LINEAR;
this.volume = MIN_VOLUME;
this.pitch = MIN_PITCH;
this.x = hoverboard.getX();
this.y = hoverboard.getY();
this.z = hoverboard.getZ();
this.lastX = this.x;
this.lastZ = this.z;
}
@Override
public void tick() {
if (this.hoverboard.isRemoved() || !this.hoverboard.isVehicle()) {
this.stop();
return;
}
double dx = this.hoverboard.getX() - this.lastX;
double dz = this.hoverboard.getZ() - this.lastZ;
double speed = Math.sqrt(dx * dx + dz * dz);
this.lastX = this.hoverboard.getX();
this.lastZ = this.hoverboard.getZ();
this.x = this.hoverboard.getX();
this.y = this.hoverboard.getY();
this.z = this.hoverboard.getZ();
double maxSpeed = Math.max(AntarchySettings.hoverboardMaxSpeed(), 0.0001D);
float speedRatio = (float) Mth.clamp(speed / maxSpeed, 0.0D, 1.0D);
boolean jumping = false;
Entity passenger = this.hoverboard.getControllingPassenger();
if (passenger instanceof net.minecraft.world.entity.player.Player player) {
jumping = ((LivingEntityJumpingAccessor) player).antarchy$isJumping();
}
boolean movingUpward = this.hoverboard.getDeltaMovement().y > 0.02D;
float liftRatio = jumping || movingUpward ? 1.0F : 0.0F;
this.volume = Mth.lerp(speedRatio, MIN_VOLUME, MAX_VOLUME);
this.pitch = Mth.lerp(speedRatio, MIN_PITCH, MAX_PITCH)
+ Mth.lerp(liftRatio, 0.0F, 0.2F);
}
@Override
public boolean canStartSilent() {
return true;
}
}
}
@@ -0,0 +1,36 @@
package com.craisinlord.antarchy.content.client;
public final class KingJudgmentFlashClientState {
private static int flashTicks;
private static int flashDuration;
private KingJudgmentFlashClientState() {
}
public static void trigger(int ticks) {
int duration = Math.max(0, ticks);
if (duration >= flashTicks) {
flashTicks = duration;
flashDuration = duration;
}
}
public static void tick() {
if (flashTicks > 0) {
flashTicks--;
}
}
public static float alpha() {
if (flashTicks <= 0 || flashDuration <= 0) {
return 0.0F;
}
float remaining = flashTicks / (float) flashDuration;
return Math.min(0.92F, 0.92F * remaining * remaining);
}
public static void clear() {
flashTicks = 0;
flashDuration = 0;
}
}
@@ -0,0 +1,17 @@
package com.craisinlord.antarchy.content.client;
import net.minecraft.client.gui.GuiGraphics;
public final class KingJudgmentFlashHudRenderer {
private KingJudgmentFlashHudRenderer() {
}
public static void render(GuiGraphics guiGraphics) {
int alpha = Math.round(KingJudgmentFlashClientState.alpha() * 255.0F);
if (alpha <= 0) {
return;
}
guiGraphics.fill(0, 0, guiGraphics.guiWidth(), guiGraphics.guiHeight(),
alpha << 24 | 0x00FFFFFF);
}
}
@@ -0,0 +1,53 @@
package com.craisinlord.antarchy.content.client;
import com.craisinlord.antarchy.content.network.PortalGunMoonAimPayload;
import com.craisinlord.antarchy.content.portalgun.PortalGunMoonMath;
import java.lang.ref.WeakReference;
import java.util.function.Consumer;
import net.minecraft.client.Camera;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.world.phys.Vec3;
import org.joml.Matrix4f;
import org.joml.Quaterniond;
import org.joml.Vector3d;
import org.joml.Vector3f;
public final class MoonSkyTracker {
private static final long MAX_AGE_MILLIS = 1500L;
private static final double AIM_COSINE = Math.cos(Math.toRadians(PortalGunMoonMath.AIM_TOLERANCE_DEGREES));
private static Vec3 direction;
private static WeakReference<ClientLevel> level = new WeakReference<>(null);
private static long recordedAt;
private static Consumer<PortalGunMoonAimPayload> sender = payload -> {};
private MoonSkyTracker() {
}
public static void setSender(Consumer<PortalGunMoonAimPayload> payloadSender) {
sender = payloadSender;
}
public static void recordSphericalMoon(ClientLevel renderedLevel, Camera camera, Matrix4f skyMatrix, double theta, double phi) {
Vector3d local = new Quaterniond().rotateY(theta).mul(new Quaterniond().rotateX(phi)).transform(new Vector3d(0.0D, 1.0D, 0.0D));
Vector3f view = skyMatrix.transformDirection(new Vector3f((float) local.x, (float) local.y, (float) local.z));
if (view.lengthSquared() < 1.0E-8F) {
return;
}
Vector3f world = camera.rotation().transform(view.normalize());
direction = new Vec3(world.x, world.y, world.z).normalize();
level = new WeakReference<>(renderedLevel);
recordedAt = System.currentTimeMillis();
}
public static void report() {
Minecraft minecraft = Minecraft.getInstance();
if (minecraft.player == null) {
return;
}
boolean tracked = direction != null && level.get() == minecraft.level && System.currentTimeMillis() - recordedAt <= MAX_AGE_MILLIS;
boolean aiming = tracked && minecraft.gameRenderer.getMainCamera().getLookVector().dot(
new Vector3f((float) direction.x, (float) direction.y, (float) direction.z)) >= AIM_COSINE;
sender.accept(new PortalGunMoonAimPayload(tracked, aiming));
}
}
@@ -2,7 +2,6 @@ package com.craisinlord.antarchy.content.client;
import com.craisinlord.antarchy.config.AntarchySettings; import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.item.NightmareSwordItem; import com.craisinlord.antarchy.content.item.NightmareSwordItem;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
@@ -16,14 +15,6 @@ public final class NightmareSwordTooltipHelper {
float damage = player != null float damage = player != null
? NightmareSwordItem.calculateDamage(player) ? NightmareSwordItem.calculateDamage(player)
: (float) AntarchySettings.nightmareSwordBaseDamage(); : (float) AntarchySettings.nightmareSwordBaseDamage();
return Component.translatable("tooltip.antarchy.nightmare_sword_damage", formatDamage(damage)).withStyle(ChatFormatting.RED); return NightmareSwordItem.damageLine(damage);
}
private static String formatDamage(float damage) {
float rounded = Math.round(damage * 10.0F) / 10.0F;
if (rounded == (int) rounded) {
return String.valueOf((int) rounded);
}
return String.valueOf(rounded);
} }
} }
@@ -0,0 +1,95 @@
package com.craisinlord.antarchy.content.client;
import com.craisinlord.antarchy.content.item.PortalGunItem;
import com.craisinlord.antarchy.content.network.PortalGunIndicatorPayload;
import com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity;
import com.mojang.blaze3d.systems.RenderSystem;
import java.lang.ref.WeakReference;
import java.util.EnumSet;
import java.util.Set;
import java.util.UUID;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack;
public final class PortalGunCrosshairRenderer {
private static final int WIDTH = 34;
private static final int HEIGHT = 33;
private static final int HALF_WIDTH = 17;
private static final float MISSING_BRIGHTNESS = 0.3F;
private static final float MISSING_ALPHA = 0.75F;
private static WeakReference<ClientLevel> cachedLevel = new WeakReference<>(null);
private static long cachedGameTime = Long.MIN_VALUE;
private static UUID cachedGunId;
private static Set<PortalGunPortalEntity.PortalSide> cachedPortals = Set.of();
private PortalGunCrosshairRenderer() {
}
public static void render(GuiGraphics guiGraphics) {
Minecraft minecraft = Minecraft.getInstance();
if (minecraft.player == null || minecraft.level == null || minecraft.screen != null || minecraft.options.hideGui
|| !minecraft.options.getCameraType().isFirstPerson()) {
return;
}
ItemStack held = minecraft.player.getMainHandItem();
if (!(held.getItem() instanceof PortalGunItem)) {
held = minecraft.player.getOffhandItem();
if (!(held.getItem() instanceof PortalGunItem)) {
return;
}
}
ResourceLocation crosshair = ((PortalGunItem) held.getItem()).getVariant().crosshairTexture();
UUID gunId = PortalGunItem.getGunId(held);
PortalGunIndicatorClientState.requestIfNeeded(minecraft, gunId);
Set<PortalGunPortalEntity.PortalSide> portals = portalsFor(minecraft, gunId);
PortalGunIndicatorPayload serverState = PortalGunIndicatorClientState.get(gunId);
boolean blueAvailable = serverState == null
? portals.contains(PortalGunPortalEntity.PortalSide.BLUE)
: serverState.blueAvailable();
boolean orangeAvailable = serverState == null
? portals.contains(PortalGunPortalEntity.PortalSide.ORANGE)
: serverState.orangeAvailable();
int left = (minecraft.getWindow().getGuiScaledWidth() - WIDTH) / 2;
int top = (minecraft.getWindow().getGuiScaledHeight() - HEIGHT) / 2;
RenderSystem.enableBlend();
RenderSystem.defaultBlendFunc();
drawHalf(guiGraphics, crosshair, left + 6, top, 0.0F, blueAvailable);
drawHalf(guiGraphics, crosshair, left + 11, top, HALF_WIDTH, orangeAvailable);
guiGraphics.setColor(1.0F, 1.0F, 1.0F, 1.0F);
RenderSystem.disableBlend();
}
private static void drawHalf(GuiGraphics guiGraphics, ResourceLocation crosshair, int x, int y, float u, boolean available) {
if (available) {
guiGraphics.setColor(1.0F, 1.0F, 1.0F, 1.0F);
} else {
guiGraphics.setColor(MISSING_BRIGHTNESS, MISSING_BRIGHTNESS, MISSING_BRIGHTNESS, MISSING_ALPHA);
}
guiGraphics.blit(crosshair, x, y, u, 0.0F, HALF_WIDTH, HEIGHT, WIDTH, HEIGHT);
}
private static Set<PortalGunPortalEntity.PortalSide> portalsFor(Minecraft minecraft, UUID gunId) {
if (gunId == null) {
return Set.of();
}
ClientLevel level = minecraft.level;
long gameTime = level.getGameTime();
if (cachedLevel.get() != level || cachedGameTime != gameTime || !gunId.equals(cachedGunId)) {
Set<PortalGunPortalEntity.PortalSide> portals = EnumSet.noneOf(PortalGunPortalEntity.PortalSide.class);
for (com.craisinlord.anthology.portal.PortalEntity entry : com.craisinlord.anthology.portal.PortalRegistry.all(level)) {
if (entry instanceof PortalGunPortalEntity portal && portal.isAlive() && gunId.equals(portal.getGunId())) {
portals.add(portal.getPortalSide());
}
}
cachedLevel = new WeakReference<>(level);
cachedGameTime = gameTime;
cachedGunId = gunId;
cachedPortals = Set.copyOf(portals);
}
return cachedPortals;
}
}
@@ -1,101 +0,0 @@
package com.craisinlord.antarchy.content.client;
import com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity;
import com.craisinlord.antarchy.content.portalgun.PortalGunTransformUtil;
import java.util.ArrayDeque;
import java.util.Deque;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.phys.Vec3;
public final class PortalGunEntityTransformationStack {
private final Entity entity;
private final Deque<EntityTransformation> stack = new ArrayDeque<>();
public PortalGunEntityTransformationStack(Entity entity) {
this.entity = entity;
}
public void push() {
this.stack.push(EntityTransformation.capture(this.entity));
}
public void pop() {
if (!this.stack.isEmpty()) {
this.stack.pop().restore(this.entity);
}
}
public Vec3 moveEntity(PortalGunPortalEntity sourcePortal, PortalGunPortalEntity destinationPortal, float partialTick) {
Vec3 interpolated = new Vec3(
net.minecraft.util.Mth.lerp(partialTick, this.entity.xo, this.entity.getX()),
net.minecraft.util.Mth.lerp(partialTick, this.entity.yo, this.entity.getY()),
net.minecraft.util.Mth.lerp(partialTick, this.entity.zo, this.entity.getZ())
);
Vec3 previous = new Vec3(this.entity.xo, this.entity.yo, this.entity.zo);
Vec3 transformed = destinationPortal.position().add(PortalGunTransformUtil.transformPosition(sourcePortal, destinationPortal, interpolated.subtract(sourcePortal.position())));
Vec3 transformedPrevious = destinationPortal.position().add(PortalGunTransformUtil.transformPosition(sourcePortal, destinationPortal, previous.subtract(sourcePortal.position())));
Vec3 look = PortalGunTransformUtil.transformVector(sourcePortal, destinationPortal, this.entity.getLookAngle()).normalize();
Vec3 velocity = PortalGunTransformUtil.transformVector(sourcePortal, destinationPortal, this.entity.getDeltaMovement());
float yaw = PortalGunTransformUtil.yawFromLook(look);
float pitch = PortalGunTransformUtil.pitchFromLook(look);
this.entity.setPos(transformed.x, transformed.y, transformed.z);
this.entity.xo = transformedPrevious.x;
this.entity.yo = transformedPrevious.y;
this.entity.zo = transformedPrevious.z;
this.entity.setYRot(yaw);
this.entity.setXRot(pitch);
this.entity.yRotO = yaw;
this.entity.xRotO = pitch;
this.entity.setDeltaMovement(velocity);
if (this.entity instanceof LivingEntity living) {
living.setYHeadRot(yaw);
living.setYBodyRot(yaw);
}
return transformed;
}
public void reset() {
while (!this.stack.isEmpty()) {
this.pop();
}
}
private record EntityTransformation(
double x,
double y,
double z,
double xo,
double yo,
double zo,
float yRot,
float xRot,
float yRotO,
float xRotO,
float yHeadRot,
float yBodyRot,
Vec3 deltaMovement
) {
private static EntityTransformation capture(Entity entity) {
float yHeadRot = entity instanceof LivingEntity living ? living.getYHeadRot() : entity.getYRot();
float yBodyRot = entity instanceof LivingEntity living ? living.yBodyRot : entity.getYRot();
return new EntityTransformation(entity.getX(), entity.getY(), entity.getZ(), entity.xo, entity.yo, entity.zo, entity.getYRot(), entity.getXRot(), entity.yRotO, entity.xRotO, yHeadRot, yBodyRot, entity.getDeltaMovement());
}
private void restore(Entity entity) {
entity.setPos(this.x, this.y, this.z);
entity.xo = this.xo;
entity.yo = this.yo;
entity.zo = this.zo;
entity.setYRot(this.yRot);
entity.setXRot(this.xRot);
entity.yRotO = this.yRotO;
entity.xRotO = this.xRotO;
entity.setDeltaMovement(this.deltaMovement);
if (entity instanceof LivingEntity living) {
living.setYHeadRot(this.yHeadRot);
living.setYBodyRot(this.yBodyRot);
}
}
}
}
@@ -0,0 +1,60 @@
package com.craisinlord.antarchy.content.client;
import com.craisinlord.antarchy.content.network.PortalGunIndicatorPayload;
import com.craisinlord.antarchy.content.network.PortalGunIndicatorRequestPayload;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.function.Consumer;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
public final class PortalGunIndicatorClientState {
private static final Map<UUID, PortalGunIndicatorPayload> STATES = new HashMap<>();
private static WeakReference<ClientLevel> level = new WeakReference<>(null);
private static long lastRequestTick = Long.MIN_VALUE;
private static UUID lastRequestedGun;
private static Consumer<PortalGunIndicatorRequestPayload> requestSender = payload -> {};
private PortalGunIndicatorClientState() {
}
public static void setRequestSender(Consumer<PortalGunIndicatorRequestPayload> sender) {
requestSender = sender;
}
public static void requestIfNeeded(Minecraft minecraft, UUID gunId) {
ClientLevel currentLevel = minecraft.level;
if (currentLevel == null || gunId == null || minecraft.player == null) {
return;
}
if (level.get() != currentLevel) {
level = new WeakReference<>(currentLevel);
STATES.clear();
lastRequestedGun = null;
lastRequestTick = Long.MIN_VALUE;
}
long currentTick = minecraft.player.tickCount;
if (!gunId.equals(lastRequestedGun) || currentTick - lastRequestTick >= 20L) {
lastRequestedGun = gunId;
lastRequestTick = currentTick;
requestSender.accept(new PortalGunIndicatorRequestPayload(gunId));
}
}
public static void update(PortalGunIndicatorPayload payload) {
STATES.put(payload.gunId(), payload);
}
public static PortalGunIndicatorPayload get(UUID gunId) {
return gunId == null ? null : STATES.get(gunId);
}
public static void clear() {
STATES.clear();
level = new WeakReference<>(null);
lastRequestedGun = null;
lastRequestTick = Long.MIN_VALUE;
}
}
@@ -1,139 +0,0 @@
package com.craisinlord.antarchy.content.client;
import com.craisinlord.antarchy.content.portalgun.PortalGunWorldPortalShape;
import java.util.ArrayDeque;
import java.util.Deque;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import org.joml.Matrix4f;
public final class PortalGunPortalRenderState {
private static final ThreadLocal<Deque<PortalGunWorldPortalShape>> ACTIVE_DESTINATION_SHAPES = ThreadLocal.withInitial(ArrayDeque::new);
private static final ThreadLocal<Deque<PortalGunWorldPortalShape>> ACTIVE_SOURCE_SHAPES = ThreadLocal.withInitial(ArrayDeque::new);
private static final ThreadLocal<Deque<PortalRenderContext>> ACTIVE_CONTEXTS = ThreadLocal.withInitial(ArrayDeque::new);
private static final ThreadLocal<Integer> RENDER_ALL_DEPTH = ThreadLocal.withInitial(() -> 0);
private PortalGunPortalRenderState() {
}
public static void pushPortalView(PortalGunWorldPortalShape sourceShape, PortalGunWorldPortalShape destinationShape, boolean renderAll) {
ACTIVE_SOURCE_SHAPES.get().push(sourceShape);
ACTIVE_DESTINATION_SHAPES.get().push(destinationShape);
if (renderAll) {
RENDER_ALL_DEPTH.set(RENDER_ALL_DEPTH.get() + 1);
}
}
public static void pushPortalView(PortalRenderContext context) {
ACTIVE_CONTEXTS.get().push(context);
pushPortalView(context.sourceShape(), context.destinationShape(), context.renderAll());
}
public static void popPortalView(boolean renderAll) {
Deque<PortalGunWorldPortalShape> sourceShapes = ACTIVE_SOURCE_SHAPES.get();
if (!sourceShapes.isEmpty()) {
sourceShapes.pop();
}
if (sourceShapes.isEmpty()) {
ACTIVE_SOURCE_SHAPES.remove();
}
Deque<PortalGunWorldPortalShape> destinationShapes = ACTIVE_DESTINATION_SHAPES.get();
if (!destinationShapes.isEmpty()) {
destinationShapes.pop();
}
if (destinationShapes.isEmpty()) {
ACTIVE_DESTINATION_SHAPES.remove();
}
if (renderAll) {
int depth = Math.max(0, RENDER_ALL_DEPTH.get() - 1);
if (depth == 0) {
RENDER_ALL_DEPTH.remove();
} else {
RENDER_ALL_DEPTH.set(depth);
}
}
Deque<PortalRenderContext> contexts = ACTIVE_CONTEXTS.get();
if (!contexts.isEmpty()) {
contexts.pop();
}
if (contexts.isEmpty()) {
ACTIVE_CONTEXTS.remove();
}
}
public static void pushDestinationShape(PortalGunWorldPortalShape shape) {
ACTIVE_DESTINATION_SHAPES.get().push(shape);
}
public static void popDestinationShape() {
Deque<PortalGunWorldPortalShape> shapes = ACTIVE_DESTINATION_SHAPES.get();
if (!shapes.isEmpty()) {
shapes.pop();
}
if (shapes.isEmpty()) {
ACTIVE_DESTINATION_SHAPES.remove();
}
}
public static PortalGunWorldPortalShape getDestinationShape() {
Deque<PortalGunWorldPortalShape> shapes = ACTIVE_DESTINATION_SHAPES.get();
return shapes.isEmpty() ? null : shapes.peek();
}
public static PortalGunWorldPortalShape getSourceShape() {
Deque<PortalGunWorldPortalShape> shapes = ACTIVE_SOURCE_SHAPES.get();
return shapes.isEmpty() ? null : shapes.peek();
}
public static PortalRenderContext getContext() {
Deque<PortalRenderContext> contexts = ACTIVE_CONTEXTS.get();
return contexts.isEmpty() ? null : contexts.peek();
}
public static int getRenderLevel() {
return ACTIVE_CONTEXTS.get().size();
}
public static boolean renderAll() {
return RENDER_ALL_DEPTH.get() > 0;
}
public static boolean shouldRenderBounds(AABB bounds) {
if (renderAll()) {
return true;
}
PortalRenderContext context = getContext();
if (context == null) {
PortalGunWorldPortalShape destinationShape = getDestinationShape();
PortalGunWorldPortalShape sourceShape = getSourceShape();
return destinationShape == null || shouldRenderBounds(bounds, sourceShape, destinationShape, false);
}
return shouldRenderBounds(bounds, context.sourceShape(), context.destinationShape(), context.renderAll());
}
private static boolean shouldRenderBounds(AABB bounds, PortalGunWorldPortalShape sourceShape, PortalGunWorldPortalShape destinationShape, boolean renderAll) {
if (renderAll) {
return true;
}
if (!destinationShape.intersectsFront(bounds, 0.125D)) {
return false;
}
if (!destinationShape.intersectsPortalColumn(bounds, 1.5D, 1.5D, destinationShape.halfDepth() + 96.0D)) {
return false;
}
return sourceShape == null || !sourceShape.intersectsFront(bounds, -0.02D);
}
public record PortalRenderContext(
PortalGunWorldPortalShape sourceShape,
PortalGunWorldPortalShape destinationShape,
Vec3 cameraPos,
Vec3 look,
Vec3 up,
Matrix4f viewMatrix,
Matrix4f projectionMatrix,
int renderLevel,
boolean renderAll
) {
}
}
@@ -0,0 +1,51 @@
package com.craisinlord.antarchy.content.client;
import com.craisinlord.antarchy.content.network.PortalGunResetPayload;
import java.util.function.Consumer;
import net.minecraft.client.Minecraft;
public final class PortalGunResetClientState {
private static boolean resetDown;
private static boolean attackDown;
private static boolean useDown;
private static boolean selectedSide;
private PortalGunResetClientState() {
}
public static boolean tick(Minecraft minecraft, boolean enabled, boolean resetPressed, Consumer<PortalGunResetPayload> sender) {
boolean canInput = enabled && minecraft.player != null && minecraft.level != null && minecraft.screen == null;
boolean active = canInput && resetPressed;
boolean attack = canInput && minecraft.options.keyAttack.isDown();
boolean use = canInput && minecraft.options.keyUse.isDown();
if (active && !resetDown) {
sender.accept(new PortalGunResetPayload(com.craisinlord.antarchy.content.portalgun.PortalGunResetManager.ARM));
selectedSide = false;
}
if (active && attack && !attackDown) {
sender.accept(new PortalGunResetPayload(com.craisinlord.antarchy.content.portalgun.PortalGunResetManager.RESET_BLUE));
selectedSide = true;
}
if (active && use && !useDown) {
selectedSide = true;
}
if (!active && resetDown) {
int action = !canInput || selectedSide
? com.craisinlord.antarchy.content.portalgun.PortalGunResetManager.RELEASE
: com.craisinlord.antarchy.content.portalgun.PortalGunResetManager.RESET_ALL;
sender.accept(new PortalGunResetPayload(action));
selectedSide = false;
}
resetDown = active;
attackDown = attack;
useDown = use;
return active;
}
public static void clear() {
resetDown = false;
attackDown = false;
useDown = false;
selectedSide = false;
}
}
@@ -1,123 +0,0 @@
package com.craisinlord.antarchy.content.client;
import com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity;
import com.craisinlord.antarchy.content.portalgun.PortalGunTransformUtil;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import net.minecraft.client.Minecraft;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.phys.Vec3;
public final class PortalGunRollClientState {
private static final int TELEPORT_COOLDOWN_TICKS = 40;
private static final float ROLL_DECAY = 0.85F;
private static final float ROLL_EPSILON = 0.05F;
private static final Map<UUID, Long> TELEPORT_COOLDOWNS = new HashMap<>();
private static float previousRollDegrees;
private static float rollDegrees;
private PortalGunRollClientState() {
}
public static float getRollDegrees() {
return rollDegrees;
}
public static float getRollDegrees(float partialTick) {
return previousRollDegrees + (rollDegrees - previousRollDegrees) * partialTick;
}
public static boolean isEntityInsidePortal(Minecraft minecraft, Entity entity) {
if (minecraft.level == null || entity == null) {
return false;
}
for (Entity renderEntity : minecraft.level.entitiesForRendering()) {
if (renderEntity instanceof PortalGunPortalEntity portal && portal.isAlive() && portal.intersectsEntityBounds(entity)) {
return true;
}
}
return false;
}
public static boolean isCameraInsidePortal(Minecraft minecraft) {
Entity cameraEntity = minecraft.getCameraEntity();
return cameraEntity != null && isEntityInsidePortal(minecraft, cameraEntity);
}
public static void clear() {
previousRollDegrees = 0.0F;
rollDegrees = 0.0F;
TELEPORT_COOLDOWNS.clear();
}
public static void tick(Minecraft minecraft) {
if (minecraft.level == null || minecraft.player == null) {
clear();
return;
}
Entity cameraEntity = minecraft.getCameraEntity();
if (cameraEntity == null) {
return;
}
previousRollDegrees = rollDegrees;
rollDegrees *= ROLL_DECAY;
if (Math.abs(rollDegrees) < ROLL_EPSILON) {
rollDegrees = 0.0F;
}
long gameTime = minecraft.level.getGameTime();
TELEPORT_COOLDOWNS.entrySet().removeIf(entry -> entry.getValue() <= gameTime);
for (Entity entity : minecraft.level.entitiesForRendering()) {
if (!(entity instanceof PortalGunPortalEntity portal) || !portal.isAlive()) {
continue;
}
PortalGunPortalEntity linkedPortal = portal.getLinkedPortal();
if (linkedPortal == null || !linkedPortal.isAlive()) {
continue;
}
if (!portal.shouldRenderFront(cameraEntity.position())) {
continue;
}
if (!canTeleport(cameraEntity, gameTime)) {
continue;
}
Vec3 crossingProbe = portal.resolveCrossingProbe(cameraEntity);
if (crossingProbe == null) {
continue;
}
applyPredictedTeleport(cameraEntity, portal, linkedPortal, crossingProbe, gameTime);
break;
}
}
private static boolean canTeleport(Entity entity, long gameTime) {
if (!entity.isAlive() || entity instanceof PortalGunPortalEntity || entity.isPassenger() || entity.isVehicle()) {
return false;
}
long cooldownUntil = TELEPORT_COOLDOWNS.getOrDefault(entity.getUUID(), 0L);
return cooldownUntil <= gameTime;
}
private static void applyPredictedTeleport(Entity entity, PortalGunPortalEntity sourcePortal, PortalGunPortalEntity destinationPortal, Vec3 currentProbe, long gameTime) {
Vec3 transformedLook = PortalGunTransformUtil.transformVector(sourcePortal, destinationPortal, entity.getLookAngle()).normalize();
Vec3 transformedUp = PortalGunTransformUtil.transformVector(sourcePortal, destinationPortal, PortalGunTransformUtil.upVectorFromLookAndRoll(entity.getLookAngle(), rollDegrees)).normalize();
Vec3 relativeProbe = currentProbe.subtract(sourcePortal.position());
Vec3 transformedProbe = PortalGunTransformUtil.transformPosition(sourcePortal, destinationPortal, relativeProbe);
Vec3 transformedEntityOffset = PortalGunTransformUtil.transformVector(sourcePortal, destinationPortal, entity.position().subtract(currentProbe));
Vec3 destinationNormal = destinationPortal.getNormalVec().normalize();
double exitClearance = Math.max(0.35D, entity.getBbWidth() * 0.5D + 0.16D);
Vec3 exitProbe = destinationPortal.position().add(transformedProbe).add(destinationNormal.scale(exitClearance - transformedProbe.dot(destinationNormal)));
Vec3 exitPos = exitProbe.add(transformedEntityOffset);
Vec3 transformedMotion = PortalGunTransformUtil.transformVector(sourcePortal, destinationPortal, entity.getDeltaMovement());
double outward = transformedMotion.dot(destinationNormal);
if (outward < 0.42D) {
transformedMotion = transformedMotion.add(destinationNormal.scale(0.42D - outward));
}
rollDegrees = PortalGunTransformUtil.rollFromOrientation(transformedLook, transformedUp);
entity.teleportTo(exitPos.x, exitPos.y, exitPos.z);
entity.setDeltaMovement(transformedMotion);
entity.setYRot(PortalGunTransformUtil.yawFromLook(transformedLook));
entity.setXRot(PortalGunTransformUtil.pitchFromLook(transformedLook));
TELEPORT_COOLDOWNS.put(entity.getUUID(), gameTime + TELEPORT_COOLDOWN_TICKS);
}
}
Loaded 100 of 5212 files, more files were not shown because too many files have changed in this diff. Show more