fixed missing tags
added many underside structures tweaked king and queen AI fixed undervault and UndertrialSpawnerBlock
This commit is contained in:
1 parent
8812938d79
commit
377f3785af
76 files changed
+1503
-1000
No files matched your search
+186
@@ -0,0 +1,186 @@
|
||||
package com.craisinlord.antarchy.config;
|
||||
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public final class AntarchyConfigCatalog {
|
||||
public enum Section {
|
||||
MOBS,
|
||||
TOOLS,
|
||||
MISC
|
||||
}
|
||||
|
||||
public enum ValueType {
|
||||
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 AntarchyConfigCatalog() {
|
||||
}
|
||||
|
||||
public static List<Definition> definitions() {
|
||||
return DEFINITIONS;
|
||||
}
|
||||
|
||||
public static Map<String, Definition> definitionsByName() {
|
||||
Map<String, Definition> result = new LinkedHashMap<>();
|
||||
for (Definition definition : DEFINITIONS) {
|
||||
result.put(definition.name(), definition);
|
||||
}
|
||||
return Map.copyOf(result);
|
||||
}
|
||||
|
||||
private static List<Definition> buildDefinitions() {
|
||||
Map<String, Method> getters = Arrays.stream(AntarchySettings.class.getMethods())
|
||||
.filter(AntarchyConfigCatalog::isPublicStatic)
|
||||
.filter(method -> method.getParameterCount() == 0)
|
||||
.filter(method -> method.getReturnType() != Void.TYPE)
|
||||
.collect(java.util.stream.Collectors.toMap(
|
||||
Method::getName,
|
||||
method -> method,
|
||||
(first, ignored) -> first,
|
||||
LinkedHashMap::new));
|
||||
|
||||
return Arrays.stream(AntarchySettings.class.getMethods())
|
||||
.filter(AntarchyConfigCatalog::isPublicStatic)
|
||||
.filter(method -> method.getName().startsWith("set"))
|
||||
.filter(method -> method.getParameterCount() == 1)
|
||||
.sorted(java.util.Comparator.comparing(Method::getName))
|
||||
.map(setter -> definitionFor(setter, getters))
|
||||
.filter(java.util.Objects::nonNull)
|
||||
.toList();
|
||||
}
|
||||
|
||||
private static Definition definitionFor(Method setter, Map<String, Method> getters) {
|
||||
String name = decapitalize(setter.getName().substring(3));
|
||||
Method getter = getters.get(name);
|
||||
if (getter == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Class<?> setterType = setter.getParameterTypes()[0];
|
||||
ValueType valueType = valueTypeFor(setterType, getter.getReturnType());
|
||||
if (valueType == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Definition(name, sectionFor(name), valueType, setterType, getter, setter);
|
||||
}
|
||||
|
||||
private static ValueType valueTypeFor(Class<?> setterType, Class<?> getterType) {
|
||||
if (setterType == boolean.class && getterType == boolean.class) {
|
||||
return ValueType.BOOLEAN;
|
||||
}
|
||||
if (setterType == int.class && getterType == int.class) {
|
||||
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;
|
||||
}
|
||||
|
||||
private static boolean isPublicStatic(Method method) {
|
||||
int modifiers = method.getModifiers();
|
||||
return Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers);
|
||||
}
|
||||
|
||||
private static String decapitalize(String value) {
|
||||
if (value.isEmpty()) {
|
||||
return value;
|
||||
}
|
||||
return Character.toLowerCase(value.charAt(0)) + value.substring(1);
|
||||
}
|
||||
|
||||
private static Section sectionFor(String name) {
|
||||
if (isMiscSetting(name)) {
|
||||
return Section.MISC;
|
||||
}
|
||||
if (isToolSetting(name)) {
|
||||
return Section.TOOLS;
|
||||
}
|
||||
return Section.MOBS;
|
||||
}
|
||||
|
||||
private static boolean isMiscSetting(String name) {
|
||||
return name.equals("disableInfinityBookPortalCreation")
|
||||
|| name.equals("rainbowAntsLeadToInfinityDimensions")
|
||||
|| name.equals("permanentPortalsEnabled")
|
||||
|| name.equals("permanentPortalsFlintAndSteelEnabled")
|
||||
|| name.equals("elythiaPortalEnabled")
|
||||
|| name.equals("thoraxisPortalEnabled")
|
||||
|| name.equals("cavarynPortalEnabled")
|
||||
|| name.equals("hushweedSporeLifetimeSeconds")
|
||||
|| name.equals("elythiaFireflyParticlesEnabled")
|
||||
|| name.equals("duplicatorTreeEnabled")
|
||||
|| name.equals("glowVinesUnderLeaves")
|
||||
|| name.equals("swingThroughGrassEnabled")
|
||||
|| name.equals("fabricKeybindingConflictFixEnabled")
|
||||
|| name.equals("experimentalSettingsPopupDisabled")
|
||||
|| name.equals("entitySpecificFireOverlayEnabled")
|
||||
|| name.equals("dreamSandEnabled")
|
||||
|| name.startsWith("dreamSand")
|
||||
|| name.equals("ichorWitherEnabled")
|
||||
|| name.startsWith("diamondMinecart")
|
||||
|| name.startsWith("hoverboard");
|
||||
}
|
||||
|
||||
private static boolean isToolSetting(String name) {
|
||||
return name.equals("sizeChangingRaysEnabled")
|
||||
|| name.startsWith("sizeRay")
|
||||
|| name.equals("shrinkingPotionDelta")
|
||||
|| name.equals("growthPotionDelta")
|
||||
|| name.startsWith("ultimate")
|
||||
|| name.startsWith("battleAxe")
|
||||
|| name.startsWith("bigBertha")
|
||||
|| name.startsWith("attitudeAdjuster")
|
||||
|| name.startsWith("scorpionWhip")
|
||||
|| 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.equals("invertProjectilesFromInvertedPlayers")
|
||||
|| name.startsWith("gravityGun")
|
||||
|| name.startsWith("critterCage")
|
||||
|| name.startsWith("minersDream")
|
||||
|| name.equals("potentNyxiteInvertedDurationSeconds")
|
||||
|| name.equals("corneaEarNightVisionSeconds")
|
||||
|| name.startsWith("american")
|
||||
|| name.startsWith("mogglesVision")
|
||||
|| name.equals("ductTapeRepairPercentPerUse")
|
||||
|| name.startsWith("fallenKingCrown");
|
||||
}
|
||||
}
|
||||
@@ -12,25 +12,26 @@ public final class 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);
|
||||
if (readGeneration(markerPath) >= RESET_GENERATION) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Path configFile : configFiles) {
|
||||
try {
|
||||
if (Files.deleteIfExists(configFile)) {
|
||||
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);
|
||||
if (Files.exists(configFile)) {
|
||||
Antarchy.LOGGER.info("Preserving config file {} during config migration (config generation {})", configFile, RESET_GENERATION);
|
||||
}
|
||||
}
|
||||
|
||||
writeGeneration(markerPath);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static void wipeIfNeeded(Path configDir, Path... configFiles) {
|
||||
migrateIfNeeded(configDir, configFiles);
|
||||
}
|
||||
|
||||
private static int readGeneration(Path markerPath) {
|
||||
if (!Files.exists(markerPath)) {
|
||||
return 0;
|
||||
|
||||
+2
-5
@@ -64,13 +64,10 @@ public final class UndertrialSpawnerBlock extends BaseEntityBlock {
|
||||
|
||||
@Override
|
||||
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> blockEntityType) {
|
||||
if (this.blockEntityType == null || blockEntityType != this.blockEntityType.get()) {
|
||||
return null;
|
||||
}
|
||||
if (level.isClientSide) {
|
||||
return (BlockEntityTicker<T>) (BlockEntityTicker<UndertrialSpawnerBlockEntity>) UndertrialSpawnerBlockEntity::clientTick;
|
||||
return createTickerHelper(blockEntityType, this.blockEntityType.get(), UndertrialSpawnerBlockEntity::clientTick);
|
||||
}
|
||||
return (BlockEntityTicker<T>) (BlockEntityTicker<UndertrialSpawnerBlockEntity>) ((tickLevel, tickPos, tickState, blockEntity) -> {
|
||||
return createTickerHelper(blockEntityType, this.blockEntityType.get(), (tickLevel, tickPos, tickState, blockEntity) -> {
|
||||
if (tickLevel instanceof net.minecraft.server.level.ServerLevel serverLevel) {
|
||||
UndertrialSpawnerBlockEntity.serverTick(serverLevel, tickPos, tickState, blockEntity);
|
||||
}
|
||||
|
||||
+8
-1
@@ -58,9 +58,16 @@ public final class QueenTrailSpawnMarkerBlockEntity extends BlockEntity {
|
||||
}
|
||||
boolean nearbyPlayer = level.players().stream().anyMatch(player -> !player.isSpectator()
|
||||
&& player.distanceToSqr(marker.spawnPos.getX() + 0.5D, marker.spawnPos.getY() + 0.5D, marker.spawnPos.getZ() + 0.5D) <= ACTIVATION_DISTANCE_SQUARED);
|
||||
if (!nearbyPlayer || !level.hasChunkAt(marker.spawnPos)) {
|
||||
if (!nearbyPlayer) {
|
||||
return;
|
||||
}
|
||||
// The Queen is large enough to span several chunks. Ensure the area around
|
||||
// the arrival point is available before checking its collision box.
|
||||
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);
|
||||
}
|
||||
}
|
||||
QueenEntity queen = QueenEntity.spawnFromUndersideTrail(level, marker.spawnPos, marker.homePos, marker.siteId, marker.yaw);
|
||||
if (queen != null) {
|
||||
marker.consumed = true;
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ public final class UnderVaultBlockEntity extends BlockEntity {
|
||||
|
||||
private static VaultConfig createConfig() {
|
||||
return new VaultConfig(ResourceKey.create(net.minecraft.core.registries.Registries.LOOT_TABLE,
|
||||
ResourceLocation.withDefaultNamespace("chests/trial_chambers/reward")), 4.0D, 4.0D,
|
||||
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "chests/undertrial_vault")), 4.0D, 4.0D,
|
||||
new ItemStack(BuiltInRegistries.ITEM.get(ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "undertrial_key"))),
|
||||
Optional.empty());
|
||||
}
|
||||
|
||||
+85
-8
@@ -5,23 +5,33 @@ import com.craisinlord.antarchy.content.block.UndertrialSpawnerBlock;
|
||||
import com.craisinlord.antarchy.Antarchy;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.particles.SimpleParticleType;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtOps;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.resources.RegistryOps;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.world.effect.MobEffect;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.entity.Mob;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner;
|
||||
import net.minecraft.world.level.block.entity.trialspawner.TrialSpawnerConfig;
|
||||
import net.minecraft.world.level.block.entity.trialspawner.TrialSpawnerState;
|
||||
import net.minecraft.world.level.storage.loot.LootTable;
|
||||
import net.minecraft.world.level.storage.loot.LootParams;
|
||||
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets;
|
||||
import net.minecraft.core.dispenser.DefaultDispenseItemBehavior;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.util.random.SimpleWeightedRandomList;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
@@ -35,11 +45,16 @@ public final class UndertrialSpawnerBlockEntity extends BlockEntity implements T
|
||||
private TrialSpawnerState previousClientState;
|
||||
private double clientSpin;
|
||||
private double clientOldSpin;
|
||||
private SimpleWeightedRandomList<ResourceKey<LootTable>> normalLootTables = SimpleWeightedRandomList.empty();
|
||||
private SimpleWeightedRandomList<ResourceKey<LootTable>> ominousLootTables = SimpleWeightedRandomList.empty();
|
||||
private Tag normalLootTablesTag;
|
||||
private Tag ominousLootTablesTag;
|
||||
|
||||
public UndertrialSpawnerBlockEntity(BlockPos pos, BlockState state, Supplier<? extends net.minecraft.world.level.block.entity.BlockEntityType<UndertrialSpawnerBlockEntity>> type) {
|
||||
super(type.get(), pos, state);
|
||||
this.trialSpawner = new TrialSpawner(this, net.minecraft.world.level.block.entity.trialspawner.PlayerDetector.INCLUDING_CREATIVE_PLAYERS,
|
||||
net.minecraft.world.level.block.entity.trialspawner.PlayerDetector.EntitySelector.SELECT_FROM_LEVEL);
|
||||
this.trialSpawner.overridePeacefulAndMobSpawnRule();
|
||||
this.previousClientState = state.getValue(UndertrialSpawnerBlock.STATE);
|
||||
}
|
||||
|
||||
@@ -48,7 +63,14 @@ public final class UndertrialSpawnerBlockEntity extends BlockEntity implements T
|
||||
for (Mob mob : level.getEntitiesOfClass(Mob.class, new AABB(pos).inflate(16.0D))) {
|
||||
before.add(mob.getUUID());
|
||||
}
|
||||
blockEntity.trialSpawner.tickServer(level, pos, state.getValue(UndertrialSpawnerBlock.OMINOUS));
|
||||
TrialSpawnerState previousState = blockEntity.getState();
|
||||
boolean ominous = state.getValue(UndertrialSpawnerBlock.OMINOUS);
|
||||
boolean rewardReady = previousState == TrialSpawnerState.EJECTING_REWARD
|
||||
&& blockEntity.trialSpawner.getData().isReadyToEjectItems(level, 30.0F, blockEntity.trialSpawner.getTargetCooldownLength());
|
||||
blockEntity.trialSpawner.tickServer(level, pos, ominous);
|
||||
if (rewardReady && blockEntity.getState() == TrialSpawnerState.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);
|
||||
@@ -102,18 +124,35 @@ public final class UndertrialSpawnerBlockEntity extends BlockEntity implements T
|
||||
@Override
|
||||
protected void loadAdditional(CompoundTag tag, net.minecraft.core.HolderLookup.Provider registries) {
|
||||
super.loadAdditional(tag, registries);
|
||||
if (tag.contains(SPAWNER_TAG)) {
|
||||
trialSpawner.codec().parse(RegistryOps.create(NbtOps.INSTANCE, registries), tag.get(SPAWNER_TAG)).result().ifPresent(decoded -> {
|
||||
trialSpawner = decoded;
|
||||
});
|
||||
}
|
||||
net.minecraft.nbt.Tag spawnerTag = tag.contains(SPAWNER_TAG) ? tag.get(SPAWNER_TAG) : tag;
|
||||
trialSpawner.codec().parse(RegistryOps.create(NbtOps.INSTANCE, registries), spawnerTag).result().ifPresent(decoded -> {
|
||||
captureLootTables(decoded, spawnerTag);
|
||||
trialSpawner = createRewardlessSpawner(decoded);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getUpdateTag(net.minecraft.core.HolderLookup.Provider registries) {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
saveAdditional(tag, registries);
|
||||
return tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveAdditional(CompoundTag tag, net.minecraft.core.HolderLookup.Provider registries) {
|
||||
super.saveAdditional(tag, registries);
|
||||
trialSpawner.codec().encodeStart(RegistryOps.create(NbtOps.INSTANCE, registries), trialSpawner).result()
|
||||
.ifPresent(encoded -> tag.put(SPAWNER_TAG, encoded));
|
||||
.ifPresent(encoded -> {
|
||||
if (encoded instanceof CompoundTag spawnerTag) {
|
||||
if (normalLootTablesTag != null) {
|
||||
spawnerTag.getCompound("normal_config").put("loot_tables_to_eject", normalLootTablesTag.copy());
|
||||
}
|
||||
if (ominousLootTablesTag != null) {
|
||||
spawnerTag.getCompound("ominous_config").put("loot_tables_to_eject", ominousLootTablesTag.copy());
|
||||
}
|
||||
tag.put(SPAWNER_TAG, spawnerTag);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -141,4 +180,42 @@ public final class UndertrialSpawnerBlockEntity extends BlockEntity implements T
|
||||
public double getClientSpin(float partialTick) {
|
||||
return this.clientOldSpin + (this.clientSpin - this.clientOldSpin) * partialTick;
|
||||
}
|
||||
|
||||
private void captureLootTables(TrialSpawner source, Tag spawnerTag) {
|
||||
normalLootTables = source.getNormalConfig().lootTablesToEject();
|
||||
ominousLootTables = source.getOminousConfig().lootTablesToEject();
|
||||
if (spawnerTag instanceof CompoundTag compound) {
|
||||
CompoundTag normalConfig = compound.getCompound("normal_config");
|
||||
CompoundTag ominousConfig = compound.getCompound("ominous_config");
|
||||
normalLootTablesTag = normalConfig.get("loot_tables_to_eject");
|
||||
ominousLootTablesTag = ominousConfig.get("loot_tables_to_eject");
|
||||
}
|
||||
}
|
||||
|
||||
private TrialSpawner createRewardlessSpawner(TrialSpawner source) {
|
||||
TrialSpawner rewardless = new TrialSpawner(withoutLootTables(source.getNormalConfig()), withoutLootTables(source.getOminousConfig()),
|
||||
source.getData(), source.getRequiredPlayerRange(), source.getTargetCooldownLength(), this,
|
||||
source.getPlayerDetector(), source.getEntitySelector());
|
||||
rewardless.overridePeacefulAndMobSpawnRule();
|
||||
return rewardless;
|
||||
}
|
||||
|
||||
private static TrialSpawnerConfig withoutLootTables(TrialSpawnerConfig config) {
|
||||
return new TrialSpawnerConfig(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<ResourceKey<LootTable>> lootTables = ominous ? ominousLootTables : normalLootTables;
|
||||
lootTables.getRandomValue(level.getRandom()).ifPresent(key -> {
|
||||
LootTable lootTable = level.getServer().reloadableRegistries().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));
|
||||
}
|
||||
level.levelEvent(3014, pos, 0);
|
||||
});
|
||||
}
|
||||
}
|
||||
-46
@@ -1,46 +0,0 @@
|
||||
package com.craisinlord.antarchy.content.client;
|
||||
|
||||
import com.craisinlord.antarchy.content.weather.ThoraxisWeatherKind;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
public final class ThoraxisWeatherClientState {
|
||||
private static final Map<ResourceLocation, ThoraxisWeatherState> STATES = new HashMap<>();
|
||||
|
||||
private ThoraxisWeatherClientState() {
|
||||
}
|
||||
|
||||
public static void apply(ResourceLocation dimension, ThoraxisWeatherKind kind, long expiresAt, int anchorX, int anchorY, int anchorZ) {
|
||||
if (kind == ThoraxisWeatherKind.NONE) {
|
||||
STATES.remove(dimension);
|
||||
return;
|
||||
}
|
||||
|
||||
STATES.put(dimension, new ThoraxisWeatherState(kind, expiresAt, new BlockPos(anchorX, anchorY, anchorZ)));
|
||||
}
|
||||
|
||||
public static ThoraxisWeatherState current(Level level) {
|
||||
if (level == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ThoraxisWeatherState state = STATES.get(level.dimension().location());
|
||||
if (state == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
long now = level.getGameTime();
|
||||
if (state.expiresAt > 0L && now > state.expiresAt) {
|
||||
STATES.remove(level.dimension().location());
|
||||
return null;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
public record ThoraxisWeatherState(ThoraxisWeatherKind kind, long expiresAt, BlockPos anchor) {
|
||||
}
|
||||
}
|
||||
+5
-3
@@ -50,7 +50,9 @@ public class RoyalBossModel extends GeoModel<RoyalBossEntity> {
|
||||
Vec3 beamEnd = animatable.getRoyalBeamEndPosition(slot);
|
||||
if (!animatable.isFiringRoyalBeam(slot) || beamEnd == null) continue;
|
||||
Vec3 origin = animatable.getRoyalBeamShootFrom(slot, partialTick);
|
||||
Vec3 direction = beamEnd.subtract(origin);
|
||||
Vec3 direction = com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil.vecWorldToPlayer(
|
||||
beamEnd.subtract(origin),
|
||||
com.craisinlord.antarchy.content.gravity.AntarchyGravityApi.getGravityDirection(animatable));
|
||||
double horizontal = Math.sqrt(direction.x * direction.x + direction.z * direction.z);
|
||||
if (direction.lengthSqr() < 1.0E-6D || horizontal < 1.0E-4D) continue;
|
||||
|
||||
@@ -65,8 +67,8 @@ public class RoyalBossModel extends GeoModel<RoyalBossEntity> {
|
||||
float pitchPerBone = pitch / chain.length;
|
||||
for (String boneName : chain) {
|
||||
this.getBone(boneName).ifPresent(bone -> {
|
||||
bone.setRotY(bone.getRotY() + yawPerBone);
|
||||
bone.setRotX(bone.getRotX() + pitchPerBone);
|
||||
bone.setRotY(yawPerBone);
|
||||
bone.setRotX(pitchPerBone);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+12
-5
@@ -13,6 +13,8 @@ import net.minecraft.commands.Commands;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.ClickEvent;
|
||||
import net.minecraft.network.chat.Style;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
@@ -67,11 +69,16 @@ public final class QueenLocateCommand {
|
||||
}
|
||||
BlockPos spawn = marker.getSpawnPos();
|
||||
int distance = Mth.floor(Math.sqrt(distanceSquared(originX, originZ, site)));
|
||||
source.sendSuccess(() -> Component.literal(
|
||||
"Nearest Queen spawn in antarchy:thoraxis: ["
|
||||
+ spawn.getX() + ", " + spawn.getY() + ", " + spawn.getZ()
|
||||
+ "] (" + distance + " blocks away)"
|
||||
), false);
|
||||
String coordinates = "[" + spawn.getX() + ", " + spawn.getY() + ", " + spawn.getZ() + "]";
|
||||
String teleportCommand = "/execute in " + THORAXIS.location() + " run tp @s "
|
||||
+ spawn.getX() + " " + spawn.getY() + " " + spawn.getZ();
|
||||
source.sendSuccess(() -> Component.literal("Nearest Queen spawn in " + THORAXIS.location() + ": ")
|
||||
.append(Component.literal(coordinates)
|
||||
.withStyle(Style.EMPTY
|
||||
.withColor(net.minecraft.ChatFormatting.AQUA)
|
||||
.withUnderlined(true)
|
||||
.withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, teleportCommand))))
|
||||
.append(Component.literal(" (" + distance + " blocks away)")), false);
|
||||
return distance;
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -117,7 +117,8 @@ public class BedBugEntity extends Animal implements GeoEntity {
|
||||
}
|
||||
|
||||
public static boolean canSpawn(EntityType<BedBugEntity> entityType, ServerLevelAccessor level, MobSpawnType spawnReason, BlockPos pos, RandomSource random) {
|
||||
if (spawnReason == MobSpawnType.SPAWN_EGG || spawnReason == MobSpawnType.SPAWNER || spawnReason == MobSpawnType.COMMAND) {
|
||||
if (spawnReason == MobSpawnType.SPAWN_EGG || spawnReason == MobSpawnType.SPAWNER
|
||||
|| spawnReason == MobSpawnType.TRIAL_SPAWNER || spawnReason == MobSpawnType.COMMAND) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+5
-4
@@ -100,8 +100,8 @@ public class ManticoreEntity extends Monster implements GeoEntity {
|
||||
public static AttributeSupplier.Builder createAttributes() {
|
||||
return Mob.createMobAttributes()
|
||||
.add(Attributes.MAX_HEALTH, AntarchySettings.manticoreHealth())
|
||||
.add(Attributes.MOVEMENT_SPEED, 0.3D)
|
||||
.add(Attributes.FLYING_SPEED, 1.2D)
|
||||
.add(Attributes.MOVEMENT_SPEED, 0.45D)
|
||||
.add(Attributes.FLYING_SPEED, 2.0D)
|
||||
.add(Attributes.ATTACK_DAMAGE, AntarchySettings.manticoreAttackDamage())
|
||||
.add(Attributes.FOLLOW_RANGE, 28.0D)
|
||||
.add(Attributes.KNOCKBACK_RESISTANCE, 0.2D);
|
||||
@@ -109,7 +109,8 @@ public class ManticoreEntity extends Monster implements GeoEntity {
|
||||
|
||||
public static boolean canSpawn(EntityType<ManticoreEntity> type, ServerLevelAccessor level, MobSpawnType spawnReason, BlockPos pos, RandomSource random) {
|
||||
if (spawnReason == MobSpawnType.SPAWN_EGG || spawnReason == MobSpawnType.SPAWNER
|
||||
|| spawnReason == MobSpawnType.COMMAND || spawnReason == MobSpawnType.MOB_SUMMONED) {
|
||||
|| spawnReason == MobSpawnType.TRIAL_SPAWNER || spawnReason == MobSpawnType.COMMAND
|
||||
|| spawnReason == MobSpawnType.MOB_SUMMONED) {
|
||||
return true;
|
||||
}
|
||||
if (pos.getY() >= 0) {
|
||||
@@ -486,7 +487,7 @@ public class ManticoreEntity extends Monster implements GeoEntity {
|
||||
private final ManticoreEntity manticore;
|
||||
|
||||
ManticoreAttackGoal(ManticoreEntity manticore) {
|
||||
super(manticore, 1.1D, true);
|
||||
super(manticore, 1.6D, true);
|
||||
this.manticore = manticore;
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -107,6 +107,7 @@ public class ScorpionEntity extends Monster implements GeoEntity {
|
||||
MobSpawnType spawnReason, BlockPos pos, RandomSource random) {
|
||||
if (spawnReason == MobSpawnType.SPAWN_EGG
|
||||
|| spawnReason == MobSpawnType.SPAWNER
|
||||
|| spawnReason == MobSpawnType.TRIAL_SPAWNER
|
||||
|| spawnReason == MobSpawnType.COMMAND) {
|
||||
return true;
|
||||
}
|
||||
|
||||
+3
-1
@@ -114,6 +114,9 @@ public class LucidEntity extends Monster implements GeoEntity {
|
||||
|
||||
public static boolean canSpawn(EntityType<LucidEntity> entityType, ServerLevelAccessor level,
|
||||
MobSpawnType spawnReason, BlockPos pos, RandomSource random) {
|
||||
if (spawnReason == MobSpawnType.TRIAL_SPAWNER) {
|
||||
return level.getDifficulty() != Difficulty.PEACEFUL;
|
||||
}
|
||||
return level.getDifficulty() != Difficulty.PEACEFUL
|
||||
&& pos.getY() <= 250
|
||||
&& level.isEmptyBlock(pos)
|
||||
@@ -571,4 +574,3 @@ public class LucidEntity extends Monster implements GeoEntity {
|
||||
|
||||
|
||||
|
||||
|
||||
+1
-3
@@ -35,9 +35,7 @@ public class LucidEyeProjectileEntity extends ThrowableItemProjectile {
|
||||
|
||||
@Override
|
||||
protected double getDefaultGravity() {
|
||||
// Gravity is expressed in the projectile's local frame, so the generic
|
||||
// Underside hook mirrors this pearl's special rising arc below Y=0.
|
||||
return -0.03D;
|
||||
return 0.03D;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
@@ -260,6 +260,9 @@ public class NightmareEntity extends Monster implements GeoEntity {
|
||||
}
|
||||
|
||||
public static boolean canSpawn(EntityType<NightmareEntity> entityType, ServerLevelAccessor level, MobSpawnType spawnReason, BlockPos pos, RandomSource random) {
|
||||
if (spawnReason == MobSpawnType.TRIAL_SPAWNER) {
|
||||
return level.getDifficulty() != Difficulty.PEACEFUL;
|
||||
}
|
||||
boolean posEmpty = level.isEmptyBlock(pos);
|
||||
boolean floorSpawn = level.getBlockState(pos.below()).isFaceSturdy(level, pos.below(), Direction.UP) && level.isEmptyBlock(pos.above());
|
||||
boolean ceilingSpawn = level.getBlockState(pos.above()).isFaceSturdy(level, pos.above(), Direction.DOWN) && level.isEmptyBlock(pos.below());
|
||||
|
||||
+1
-1
@@ -275,7 +275,7 @@ public class DimensionalTearEntity extends Entity implements GeoEntity {
|
||||
if (target != null && target.isAlive()) {
|
||||
manticore.setTarget(target);
|
||||
}
|
||||
manticore.setDeltaMovement(this.getViewVector(1.0F).scale(0.2D).add(0.0D, 0.08D, 0.0D));
|
||||
manticore.setDeltaMovement(this.getViewVector(1.0F).scale(0.7D).add(0.0D, 0.18D, 0.0D));
|
||||
manticore.setNoGravity(false);
|
||||
level.addFreshEntity(manticore);
|
||||
}
|
||||
|
||||
-2
@@ -868,8 +868,6 @@ public class KingEntity extends RoyalBossEntity {
|
||||
new com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackScheduler.Action() {
|
||||
@Override public void onStart() {
|
||||
KingEntity.this.triggerAnim(RoyalHead.Slot.LEFT.controllerName(), "shoot");
|
||||
KingEntity.this.playRoyalSound(SoundEvents.FIRECHARGE_USE, 0.8F);
|
||||
KingEntity.this.playRoyalSound(SoundEvents.GHAST_WARN, 1.2F);
|
||||
}
|
||||
@Override public void onActive(int elapsedTicks) {
|
||||
Vec3 origin = KingEntity.this.headAnchor(KingEntity.this.royalHead(RoyalHead.Slot.LEFT));
|
||||
|
||||
+20
-6
@@ -59,6 +59,7 @@ public class QueenEntity extends RoyalBossEntity {
|
||||
private static final int MOMENTUM_LOCK_COOLDOWN = 420;
|
||||
private static final int MOMENTUM_LOCK_DURATION = 90;
|
||||
private static final double MOMENTUM_LOCK_RADIUS = 26.0D;
|
||||
private static final float MOMENTUM_LOCK_EARLY_HEALTH_THRESHOLD = 0.80F;
|
||||
private static final int CRUSHING_GRAVITY_COOLDOWN = 360;
|
||||
private static final int CRUSHING_GRAVITY_DURATION = 120;
|
||||
private static final double CRUSHING_GRAVITY_RADIUS = 18.0D;
|
||||
@@ -252,8 +253,6 @@ public class QueenEntity extends RoyalBossEntity {
|
||||
@Override public void onStart() {
|
||||
head.startShoot();
|
||||
QueenEntity.this.triggerAnim(slot.controllerName(), "shoot");
|
||||
QueenEntity.this.playRoyalSound(net.minecraft.sounds.SoundEvents.FIRECHARGE_USE, 0.75F);
|
||||
QueenEntity.this.playRoyalSound(net.minecraft.sounds.SoundEvents.GHAST_WARN, 1.35F);
|
||||
}
|
||||
@Override public void onActive(int elapsedTicks) {
|
||||
Vec3 origin = QueenEntity.this.headAnchor(head);
|
||||
@@ -381,11 +380,21 @@ public class QueenEntity extends RoyalBossEntity {
|
||||
private int spawnManticoreTears(ServerLevel level, LivingEntity target, int count) {
|
||||
int pairs = Math.max(1, Math.min(3, (count + 1) / 2));
|
||||
int created = 0;
|
||||
Vec3 towardTarget = target.position().subtract(this.position()).multiply(1.0D, 0.0D, 1.0D);
|
||||
if (towardTarget.lengthSqr() < 1.0E-4D) {
|
||||
towardTarget = this.getViewVector(1.0F).multiply(1.0D, 0.0D, 1.0D);
|
||||
}
|
||||
towardTarget = towardTarget.normalize();
|
||||
Vec3 behindTarget = target.position().add(towardTarget.scale(8.0D));
|
||||
Vec3 lateral = new Vec3(-towardTarget.z, 0.0D, towardTarget.x);
|
||||
double vertical = AntarchyGravityApi.isGravityInverted(this) ? -2.0D : 2.0D;
|
||||
for (int i = 0; i < pairs; i++) {
|
||||
double angle = this.random.nextDouble() * Mth.TWO_PI;
|
||||
double distance = Math.max(8.0D, AntarchySettings.queenManticoreSummonRange() * 0.65D);
|
||||
Vec3 firstPos = this.position().add(Math.cos(angle) * distance, 1.0D, Math.sin(angle) * distance);
|
||||
Vec3 secondPos = this.position().add(Math.cos(angle + Math.PI) * distance, 1.0D, Math.sin(angle + Math.PI) * distance);
|
||||
double spread = (i - (pairs - 1) * 0.5D) * 5.0D;
|
||||
Vec3 pairCenter = behindTarget.add(lateral.scale(spread)).add(0.0D, vertical, 0.0D);
|
||||
Vec3 firstPos = pairCenter.add(lateral.scale(3.0D));
|
||||
Vec3 secondPos = pairCenter.add(lateral.scale(-3.0D));
|
||||
DimensionalTearEntity first = DimensionalTearEntity.createQueenManticoreTear(level, firstPos,
|
||||
(float) Math.toDegrees(angle), 240, this.getUUID(), Math.min(3, count));
|
||||
DimensionalTearEntity second = DimensionalTearEntity.createQueenManticoreTear(level, secondPos,
|
||||
@@ -417,7 +426,7 @@ public class QueenEntity extends RoyalBossEntity {
|
||||
Phase phase = this.phase();
|
||||
boolean majorBusy = this.royalEffects.active("momentum_lock") || this.royalEffects.active("crushing_gravity");
|
||||
boolean allowOverlap = phase != Phase.ONE;
|
||||
String[] candidates = phase == Phase.ONE
|
||||
String[] candidates = phase == Phase.ONE && !this.isMomentumLockAvailableEarly()
|
||||
? new String[] {"gravity_stomp", "black_hole"}
|
||||
: new String[] {"gravity_stomp", "black_hole", "momentum_lock", "crushing_gravity", "acceleration"};
|
||||
String selected = this.attackScheduler.chooseWeighted(candidates, id -> {
|
||||
@@ -490,6 +499,11 @@ public class QueenEntity extends RoyalBossEntity {
|
||||
};
|
||||
}
|
||||
|
||||
private boolean isMomentumLockAvailableEarly() {
|
||||
return this.getMaxHealth() > 0.0F
|
||||
&& this.getHealth() / this.getMaxHealth() <= MOMENTUM_LOCK_EARLY_HEALTH_THRESHOLD;
|
||||
}
|
||||
|
||||
private void tickFinalAcceleration() {
|
||||
if (this.phase() != Phase.THREE) {
|
||||
return;
|
||||
@@ -517,7 +531,7 @@ public class QueenEntity extends RoyalBossEntity {
|
||||
|
||||
private void castBlackHole(ServerLevel level, LivingEntity target) {
|
||||
double vertical = 2.0D + this.random.nextDouble() * 2.0D;
|
||||
if (AntarchyGravityApi.isGravityInverted(target)) {
|
||||
if (AntarchyGravityApi.isGravityInverted(this)) {
|
||||
vertical = -vertical;
|
||||
}
|
||||
Vec3 anchor = target.position().add(
|
||||
|
||||
+1
-1
@@ -301,7 +301,7 @@ public class RoyalBlackHoleEntity extends Entity implements GeoEntity {
|
||||
}
|
||||
|
||||
Vec3 center = this.effectCenter();
|
||||
Vec3 terrainOrigin = this.position();
|
||||
Vec3 terrainOrigin = center;
|
||||
double radius = this.effectRadius();
|
||||
int pulledThisTick = 0;
|
||||
for (int attempt = 0; attempt < BLOCK_SUCTION_ATTEMPTS && pulledThisTick < BLOCKS_PER_SUCTION
|
||||
|
||||
+18
-8
@@ -11,6 +11,7 @@ import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamElement;
|
||||
import com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackLane;
|
||||
import com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackScheduler;
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil;
|
||||
import com.craisinlord.antarchy.content.worldgen.thoraxis.ThoraxisUndersideManager;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@@ -26,6 +27,7 @@ import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.BossEvent;
|
||||
import net.minecraft.world.damagesource.DamageSource;
|
||||
import net.minecraft.world.damagesource.DamageTypes;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
@@ -586,6 +588,7 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
||||
int index = head.slot().ordinal();
|
||||
head.setBeamActive(false);
|
||||
head.stopShoot();
|
||||
this.stopTriggeredAnim(head.slot().controllerName(), null);
|
||||
this.beamControllers[index].stop();
|
||||
this.entityData.set(BEAM_ACTIVE[index], false);
|
||||
this.entityData.set(BEAM_ELEMENT[index], RoyalBeamElement.GENERIC.ordinal());
|
||||
@@ -874,10 +877,12 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
||||
double yaw = this.yBodyRot * Mth.DEG_TO_RAD;
|
||||
Vec3 forward = new Vec3(-Math.sin(yaw), 0.0D, Math.cos(yaw));
|
||||
Vec3 right = new Vec3(forward.z, 0.0D, -forward.x);
|
||||
return new Vec3(
|
||||
this.getX() + forward.x * spec.forwardOffset() + right.x * spec.lateralOffset(),
|
||||
this.getY() + spec.yOffset(),
|
||||
this.getZ() + forward.z * spec.forwardOffset() + right.z * spec.lateralOffset());
|
||||
Vec3 localOffset = new Vec3(
|
||||
forward.x * spec.forwardOffset() + right.x * spec.lateralOffset(),
|
||||
spec.yOffset(),
|
||||
forward.z * spec.forwardOffset() + right.z * spec.lateralOffset());
|
||||
return this.position().add(AntarchyGravityRotationUtil.vecPlayerToWorld(localOffset,
|
||||
AntarchyGravityApi.getGravityDirection(this)));
|
||||
}
|
||||
|
||||
protected Vec3 beamAnchor(RoyalHead head) {
|
||||
@@ -894,10 +899,12 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
||||
case RIGHT -> BEAM_MUZZLE_LATERAL;
|
||||
};
|
||||
double vertical = slot == RoyalHead.Slot.CENTER ? BEAM_MUZZLE_CENTER_Y : BEAM_MUZZLE_SIDE_Y;
|
||||
return new Vec3(
|
||||
x + forward.x * BEAM_MUZZLE_FORWARD + right.x * lateral,
|
||||
y + vertical,
|
||||
z + forward.z * BEAM_MUZZLE_FORWARD + right.z * lateral);
|
||||
Vec3 localOffset = new Vec3(
|
||||
forward.x * BEAM_MUZZLE_FORWARD + right.x * lateral,
|
||||
vertical,
|
||||
forward.z * BEAM_MUZZLE_FORWARD + right.z * lateral);
|
||||
return new Vec3(x, y, z).add(AntarchyGravityRotationUtil.vecPlayerToWorld(localOffset,
|
||||
AntarchyGravityApi.getGravityDirection(this)));
|
||||
}
|
||||
|
||||
protected double royalBeamMinimumRange() {
|
||||
@@ -989,6 +996,9 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
||||
|
||||
@Override
|
||||
public boolean hurt(DamageSource source, float amount) {
|
||||
if (source.is(DamageTypes.GENERIC_KILL)) {
|
||||
return super.hurt(source, amount);
|
||||
}
|
||||
float cappedAmount = (float) Math.min(amount, AntarchySettings.royalBossMaxSingleHitDamage());
|
||||
return super.hurt(source, cappedAmount);
|
||||
}
|
||||
|
||||
-46
@@ -1,46 +0,0 @@
|
||||
package com.craisinlord.antarchy.content.network;
|
||||
|
||||
import com.craisinlord.antarchy.Antarchy;
|
||||
import com.craisinlord.antarchy.content.weather.ThoraxisWeatherKind;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public record ThoraxisWeatherPayload(
|
||||
String dimensionId,
|
||||
String weatherId,
|
||||
long expiresAt,
|
||||
int anchorX,
|
||||
int anchorY,
|
||||
int anchorZ
|
||||
) implements CustomPacketPayload {
|
||||
public static final Type<ThoraxisWeatherPayload> TYPE =
|
||||
new Type<>(ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "thoraxis_weather"));
|
||||
|
||||
public static final StreamCodec<ByteBuf, ThoraxisWeatherPayload> STREAM_CODEC = StreamCodec.composite(
|
||||
ByteBufCodecs.STRING_UTF8,
|
||||
ThoraxisWeatherPayload::dimensionId,
|
||||
ByteBufCodecs.STRING_UTF8,
|
||||
ThoraxisWeatherPayload::weatherId,
|
||||
ByteBufCodecs.VAR_LONG,
|
||||
ThoraxisWeatherPayload::expiresAt,
|
||||
ByteBufCodecs.VAR_INT,
|
||||
ThoraxisWeatherPayload::anchorX,
|
||||
ByteBufCodecs.VAR_INT,
|
||||
ThoraxisWeatherPayload::anchorY,
|
||||
ByteBufCodecs.VAR_INT,
|
||||
ThoraxisWeatherPayload::anchorZ,
|
||||
ThoraxisWeatherPayload::new
|
||||
);
|
||||
|
||||
public ThoraxisWeatherPayload(ResourceLocation dimensionId, ThoraxisWeatherKind kind, long expiresAt, int anchorX, int anchorY, int anchorZ) {
|
||||
this(dimensionId.toString(), kind.id(), expiresAt, anchorX, anchorY, anchorZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type<ThoraxisWeatherPayload> type() {
|
||||
return TYPE;
|
||||
}
|
||||
}
|
||||
+4
@@ -153,6 +153,10 @@ public class TimeDilationFieldEntity extends Entity {
|
||||
return this.entityData.get(RADIUS);
|
||||
}
|
||||
|
||||
public double influenceRadius() {
|
||||
return this.chronosphere ? this.fieldRadius() * 2.0D : this.fieldRadius();
|
||||
}
|
||||
|
||||
public double fieldRadiusSqr() {
|
||||
double radius = this.fieldRadius();
|
||||
return radius * radius;
|
||||
|
||||
+17
-2
@@ -40,8 +40,23 @@ public final class TimeDilationFieldSampler {
|
||||
double dy = center.y - entity.getY();
|
||||
double dz = center.z - entity.getZ();
|
||||
double distanceSqr = dx * dx + dy * dy + dz * dz;
|
||||
if (distanceSqr < field.fieldRadiusSqr()) {
|
||||
double falloff = TimeDilationMath.gaussianFalloff(Math.sqrt(distanceSqr), field.fieldRadius());
|
||||
double distance = Math.sqrt(distanceSqr);
|
||||
double radius = field.fieldRadius();
|
||||
double falloff;
|
||||
if (field.isChronosphere()) {
|
||||
if (distance >= radius * 2.0D) {
|
||||
continue;
|
||||
}
|
||||
falloff = distance <= radius
|
||||
? 1.0D
|
||||
: TimeDilationMath.gaussianFalloff(distance - radius, radius);
|
||||
} else {
|
||||
if (distanceSqr >= field.fieldRadiusSqr()) {
|
||||
continue;
|
||||
}
|
||||
falloff = TimeDilationMath.gaussianFalloff(distance, radius);
|
||||
}
|
||||
if (falloff > 0.0D) {
|
||||
combinedRate *= TimeDilationMath.localFieldRate(field.effectiveFieldRate(), falloff);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -83,7 +83,7 @@ public final class TimeDilationManager {
|
||||
|
||||
private static void discoverFieldEntities(ServerLevel level, List<TimeDilationFieldEntity> fields, TrackingState tracking) {
|
||||
for (TimeDilationFieldEntity field : fields) {
|
||||
double radius = field.fieldRadius();
|
||||
double radius = field.influenceRadius();
|
||||
var center = field.position();
|
||||
var area = new net.minecraft.world.phys.AABB(
|
||||
center.x - radius, center.y - radius, center.z - radius,
|
||||
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
package com.craisinlord.antarchy.content.weather;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public enum ThoraxisWeatherKind {
|
||||
NONE("none"),
|
||||
INVERSION_STORM("inversion_storm"),
|
||||
BLOOD_RAIN("blood_rain"),
|
||||
SANDSTORM("sandstorm");
|
||||
|
||||
private final String id;
|
||||
|
||||
ThoraxisWeatherKind(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String id() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return this != NONE;
|
||||
}
|
||||
|
||||
public static ThoraxisWeatherKind byId(String value) {
|
||||
if (value == null) {
|
||||
return NONE;
|
||||
}
|
||||
|
||||
for (ThoraxisWeatherKind kind : values()) {
|
||||
if (kind.id.equalsIgnoreCase(value)) {
|
||||
return kind;
|
||||
}
|
||||
}
|
||||
|
||||
return NONE;
|
||||
}
|
||||
|
||||
public static Optional<ThoraxisWeatherKind> parse(String value) {
|
||||
ThoraxisWeatherKind kind = byId(value);
|
||||
return kind == NONE ? Optional.empty() : Optional.of(kind);
|
||||
}
|
||||
}
|
||||
-304
@@ -1,304 +0,0 @@
|
||||
package com.craisinlord.antarchy.content.weather;
|
||||
|
||||
import com.craisinlord.antarchy.Antarchy;
|
||||
import com.craisinlord.antarchy.content.AntarchyObjects;
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection;
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityTransition;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.particles.BlockParticleOption;
|
||||
import net.minecraft.core.particles.ParticleTypes;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.LightningBolt;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.UUID;
|
||||
|
||||
public final class ThoraxisWeatherManager {
|
||||
private static final ResourceLocation THORAXIS_DIMENSION = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "thoraxis");
|
||||
private static final ResourceKey<Biome> THORAXIS_WASTES = ResourceKey.create(
|
||||
net.minecraft.core.registries.Registries.BIOME,
|
||||
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "nightmare_wastes")
|
||||
);
|
||||
private static final ResourceKey<Biome> DREAM_DUNES = ResourceKey.create(
|
||||
net.minecraft.core.registries.Registries.BIOME,
|
||||
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "dream_dunes")
|
||||
);
|
||||
private static final ResourceKey<Biome> LUCID_POOLS = ResourceKey.create(
|
||||
net.minecraft.core.registries.Registries.BIOME,
|
||||
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "lucid_pools")
|
||||
);
|
||||
private static final int WEATHER_RECHECK_MIN_TICKS = 400;
|
||||
private static final int WEATHER_RECHECK_MAX_TICKS = 900;
|
||||
private static final int STORM_MIN_TICKS = 600;
|
||||
private static final int STORM_MAX_TICKS = 1800;
|
||||
private static final int INVERSION_STRIKE_INTERVAL = 600;
|
||||
private static final int INVERSION_GRAVITY_TICKS = 220;
|
||||
private static final int INVERSION_EFFECT_TICKS = 200;
|
||||
private static final int WEATHER_PARTICLE_INTERVAL = 4;
|
||||
private static final double WEATHER_RADIUS = 48.0D;
|
||||
|
||||
private static final WeakHashMap<ServerLevel, WeatherState> STATES = new WeakHashMap<>();
|
||||
|
||||
private ThoraxisWeatherManager() {
|
||||
}
|
||||
|
||||
public static ThoraxisWeatherSnapshot tick(ServerLevel level) {
|
||||
if (!isThoraxis(level)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
WeatherState state = STATES.computeIfAbsent(level, ignored -> new WeatherState());
|
||||
long now = level.getGameTime();
|
||||
RandomSource random = level.getRandom();
|
||||
|
||||
if (state.kind.isActive()) {
|
||||
runActiveWeather(level, state, now);
|
||||
if (now >= state.expiresAt) {
|
||||
state.clear(now + randomCooldown(random));
|
||||
return snapshot(level, state);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
if (now < state.nextDecisionAt) {
|
||||
return null;
|
||||
}
|
||||
|
||||
WeatherKindSelection selection = chooseWeather(level, random);
|
||||
if (selection.kind == ThoraxisWeatherKind.NONE) {
|
||||
state.nextDecisionAt = now + randomCooldown(random);
|
||||
return null;
|
||||
}
|
||||
|
||||
state.start(selection.kind, selection.anchor, now, now + randomDuration(random));
|
||||
runActiveWeather(level, state, now);
|
||||
return snapshot(level, state);
|
||||
}
|
||||
|
||||
public static ThoraxisWeatherSnapshot snapshot(ServerLevel level) {
|
||||
WeatherState state = STATES.get(level);
|
||||
if (state == null) {
|
||||
return new ThoraxisWeatherSnapshot(level.dimension().location(), ThoraxisWeatherKind.NONE, 0L, BlockPos.ZERO);
|
||||
}
|
||||
|
||||
return snapshot(level, state);
|
||||
}
|
||||
|
||||
public static ThoraxisWeatherSnapshot force(ServerLevel level, ThoraxisWeatherKind kind, BlockPos anchor, long durationTicks) {
|
||||
if (!isThoraxis(level)) {
|
||||
return new ThoraxisWeatherSnapshot(level.dimension().location(), ThoraxisWeatherKind.NONE, 0L, BlockPos.ZERO);
|
||||
}
|
||||
|
||||
WeatherState state = STATES.computeIfAbsent(level, ignored -> new WeatherState());
|
||||
long now = level.getGameTime();
|
||||
if (kind == null || !kind.isActive()) {
|
||||
state.clear(now + randomCooldown(level.getRandom()));
|
||||
return snapshot(level, state);
|
||||
}
|
||||
|
||||
long expiresAt = durationTicks <= 0L ? now + randomDuration(level.getRandom()) : now + durationTicks;
|
||||
state.start(kind, anchor == null ? BlockPos.ZERO : anchor, now, expiresAt);
|
||||
runActiveWeather(level, state, now);
|
||||
return snapshot(level, state);
|
||||
}
|
||||
|
||||
public static ThoraxisWeatherSnapshot clear(ServerLevel level) {
|
||||
if (!isThoraxis(level)) {
|
||||
return new ThoraxisWeatherSnapshot(level.dimension().location(), ThoraxisWeatherKind.NONE, 0L, BlockPos.ZERO);
|
||||
}
|
||||
|
||||
WeatherState state = STATES.computeIfAbsent(level, ignored -> new WeatherState());
|
||||
state.clear(level.getGameTime() + randomCooldown(level.getRandom()));
|
||||
return snapshot(level, state);
|
||||
}
|
||||
|
||||
private static ThoraxisWeatherSnapshot snapshot(ServerLevel level, WeatherState state) {
|
||||
return new ThoraxisWeatherSnapshot(level.dimension().location(), state.kind, state.expiresAt, state.anchor);
|
||||
}
|
||||
|
||||
private static void runActiveWeather(ServerLevel level, WeatherState state, long now) {
|
||||
switch (state.kind) {
|
||||
case INVERSION_STORM -> tickInversionStorm(level, state, now);
|
||||
case BLOOD_RAIN -> tickBloodRain(level, state, now);
|
||||
case SANDSTORM -> tickSandstorm(level, state, now);
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void tickInversionStorm(ServerLevel level, WeatherState state, long now) {
|
||||
cleanupExpiredForcedInversions(level, state, now);
|
||||
if (now % INVERSION_STRIKE_INTERVAL != 0L) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<LivingEntity> targets = level.getEntitiesOfClass(
|
||||
LivingEntity.class,
|
||||
new net.minecraft.world.phys.AABB(state.anchor).inflate(WEATHER_RADIUS),
|
||||
entity -> entity.isAlive() && !entity.isSpectator()
|
||||
);
|
||||
|
||||
if (targets.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
LivingEntity target = targets.get(level.getRandom().nextInt(targets.size()));
|
||||
LightningBolt bolt = EntityType.LIGHTNING_BOLT.create(level);
|
||||
if (bolt != null) {
|
||||
bolt.moveTo(target.getX(), target.getY() + target.getBbHeight() * 0.5D, target.getZ());
|
||||
bolt.setVisualOnly(true);
|
||||
level.addFreshEntity(bolt);
|
||||
}
|
||||
|
||||
if (!AntarchyGravityApi.isGravityForced(target)) {
|
||||
AntarchyGravityApi.setForcedGravityDirection(target, AntarchyGravityDirection.UP, new AntarchyGravityTransition(12));
|
||||
state.forcedInversionExpiry.put(target.getUUID(), now + INVERSION_GRAVITY_TICKS);
|
||||
}
|
||||
|
||||
target.addEffect(new MobEffectInstance(AntarchyObjects.INVERTED_EFFECT.get(), INVERSION_EFFECT_TICKS, 0, false, true, true));
|
||||
}
|
||||
|
||||
private static void cleanupExpiredForcedInversions(ServerLevel level, WeatherState state, long now) {
|
||||
Iterator<Map.Entry<UUID, Long>> iterator = state.forcedInversionExpiry.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<UUID, Long> entry = iterator.next();
|
||||
if (entry.getValue() > now) {
|
||||
continue;
|
||||
}
|
||||
|
||||
LivingEntity entity = level.getEntity(entry.getKey()) instanceof LivingEntity living ? living : null;
|
||||
if (entity != null && entity.isAlive() && AntarchyGravityApi.isGravityForced(entity)) {
|
||||
AntarchyGravityApi.clearForcedGravity(entity);
|
||||
}
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
private static void tickBloodRain(ServerLevel level, WeatherState state, long now) {
|
||||
if (now % WEATHER_PARTICLE_INTERVAL != 0L) {
|
||||
return;
|
||||
}
|
||||
|
||||
level.sendParticles(
|
||||
new BlockParticleOption(ParticleTypes.BLOCK, Blocks.RED_SAND.defaultBlockState()),
|
||||
state.anchor.getX() + 0.5D,
|
||||
state.anchor.getY() + 28.0D,
|
||||
state.anchor.getZ() + 0.5D,
|
||||
26,
|
||||
18.0D,
|
||||
12.0D,
|
||||
18.0D,
|
||||
0.12D
|
||||
);
|
||||
level.playSound(null, state.anchor, SoundEvents.LIGHTNING_BOLT_THUNDER, net.minecraft.sounds.SoundSource.WEATHER, 0.2F, 0.8F);
|
||||
}
|
||||
|
||||
private static void tickSandstorm(ServerLevel level, WeatherState state, long now) {
|
||||
if (now % WEATHER_PARTICLE_INTERVAL != 0L) {
|
||||
return;
|
||||
}
|
||||
|
||||
level.sendParticles(
|
||||
new BlockParticleOption(ParticleTypes.BLOCK, Blocks.SAND.defaultBlockState()),
|
||||
state.anchor.getX() + 0.5D,
|
||||
state.anchor.getY() + 12.0D,
|
||||
state.anchor.getZ() + 0.5D,
|
||||
40,
|
||||
14.0D,
|
||||
6.0D,
|
||||
14.0D,
|
||||
0.10D
|
||||
);
|
||||
}
|
||||
|
||||
private static WeatherKindSelection chooseWeather(ServerLevel level, RandomSource random) {
|
||||
var players = level.players();
|
||||
if (players.isEmpty()) {
|
||||
return WeatherKindSelection.none();
|
||||
}
|
||||
|
||||
LivingEntity anchorEntity = players.get(random.nextInt(players.size()));
|
||||
BlockPos anchor = anchorEntity.blockPosition();
|
||||
var biome = level.getBiome(anchor);
|
||||
|
||||
if (biome.is(DREAM_DUNES)) {
|
||||
return new WeatherKindSelection(ThoraxisWeatherKind.SANDSTORM, anchor);
|
||||
}
|
||||
|
||||
if (biome.is(LUCID_POOLS)) {
|
||||
return random.nextFloat() < 0.35F
|
||||
? new WeatherKindSelection(ThoraxisWeatherKind.BLOOD_RAIN, anchor)
|
||||
: WeatherKindSelection.none();
|
||||
}
|
||||
|
||||
if (biome.is(THORAXIS_WASTES)) {
|
||||
float roll = random.nextFloat();
|
||||
if (roll < 0.58F) {
|
||||
return new WeatherKindSelection(ThoraxisWeatherKind.INVERSION_STORM, anchor);
|
||||
}
|
||||
if (roll < 0.88F) {
|
||||
return new WeatherKindSelection(ThoraxisWeatherKind.BLOOD_RAIN, anchor);
|
||||
}
|
||||
}
|
||||
|
||||
return WeatherKindSelection.none();
|
||||
}
|
||||
|
||||
private static int randomDuration(RandomSource random) {
|
||||
return STORM_MIN_TICKS + random.nextInt(STORM_MAX_TICKS - STORM_MIN_TICKS + 1);
|
||||
}
|
||||
|
||||
private static int randomCooldown(RandomSource random) {
|
||||
return WEATHER_RECHECK_MIN_TICKS + random.nextInt(WEATHER_RECHECK_MAX_TICKS - WEATHER_RECHECK_MIN_TICKS + 1);
|
||||
}
|
||||
|
||||
private static boolean isThoraxis(ServerLevel level) {
|
||||
return level.dimension().location().equals(THORAXIS_DIMENSION);
|
||||
}
|
||||
|
||||
private record WeatherKindSelection(ThoraxisWeatherKind kind, BlockPos anchor) {
|
||||
private static WeatherKindSelection none() {
|
||||
return new WeatherKindSelection(ThoraxisWeatherKind.NONE, BlockPos.ZERO);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class WeatherState {
|
||||
private ThoraxisWeatherKind kind = ThoraxisWeatherKind.NONE;
|
||||
private long expiresAt;
|
||||
private long nextDecisionAt;
|
||||
private long startedAt;
|
||||
private BlockPos anchor = BlockPos.ZERO;
|
||||
private final Map<UUID, Long> forcedInversionExpiry = new java.util.HashMap<>();
|
||||
|
||||
private void start(ThoraxisWeatherKind kind, BlockPos anchor, long startedAt, long expiresAt) {
|
||||
this.kind = kind;
|
||||
this.anchor = anchor;
|
||||
this.startedAt = startedAt;
|
||||
this.expiresAt = expiresAt;
|
||||
this.nextDecisionAt = expiresAt;
|
||||
}
|
||||
|
||||
private void clear(long nextDecisionAt) {
|
||||
this.kind = ThoraxisWeatherKind.NONE;
|
||||
this.anchor = BlockPos.ZERO;
|
||||
this.expiresAt = 0L;
|
||||
this.startedAt = 0L;
|
||||
this.nextDecisionAt = nextDecisionAt;
|
||||
this.forcedInversionExpiry.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
package com.craisinlord.antarchy.content.weather;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public record ThoraxisWeatherSnapshot(
|
||||
ResourceLocation dimension,
|
||||
ThoraxisWeatherKind kind,
|
||||
long expiresAt,
|
||||
BlockPos anchor
|
||||
) {
|
||||
public boolean isActive() {
|
||||
return this.kind != ThoraxisWeatherKind.NONE;
|
||||
}
|
||||
}
|
||||
+39
-23
@@ -6,6 +6,7 @@ import com.craisinlord.antarchy.content.entity.royal.KingEntity;
|
||||
import com.mojang.serialization.Codec;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.WorldGenLevel;
|
||||
@@ -23,10 +24,14 @@ import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/** Places the authored King's Tree as independently generated chunk slices on a fixed world grid. */
|
||||
public final class KingsTreeGridFeature extends Feature<NoneFeatureConfiguration> {
|
||||
private static final Map<ServerLevel, Set<Long>> CLAIMED_TREE_KINGS = new WeakHashMap<>();
|
||||
private static final int TREE_MIN_X = -191;
|
||||
private static final int TREE_MAX_X = 192;
|
||||
private static final int TREE_MIN_Z = -227;
|
||||
@@ -110,31 +115,42 @@ public final class KingsTreeGridFeature extends Feature<NoneFeatureConfiguration
|
||||
|
||||
private static void spawnTreeKing(WorldGenLevel level, int centerX, int centerZ, int baseY) {
|
||||
var serverLevel = level.getLevel();
|
||||
Vec3 treeCenter = new Vec3(centerX + 0.5D, 0.0D, centerZ + 0.5D);
|
||||
AABB searchBox = new AABB(
|
||||
centerX - 512.0D, level.getMinBuildHeight(), centerZ - 512.0D,
|
||||
centerX + 512.0D, level.getMaxBuildHeight(), centerZ + 512.0D);
|
||||
List<KingEntity> treeKings = serverLevel.getEntitiesOfClass(KingEntity.class, searchBox,
|
||||
king -> king.isAlive() && king.isTreePatrolFor(treeCenter));
|
||||
if (!treeKings.isEmpty()) {
|
||||
// Repair older worlds that already contain duplicate tree-bound Kings.
|
||||
for (int index = 1; index < treeKings.size(); index++) {
|
||||
treeKings.get(index).discard();
|
||||
long treeKey = ((long) centerX << 32) ^ (centerZ & 0xffffffffL);
|
||||
synchronized (serverLevel) {
|
||||
synchronized (CLAIMED_TREE_KINGS) {
|
||||
if (!CLAIMED_TREE_KINGS.computeIfAbsent(serverLevel, ignored -> new java.util.HashSet<>()).add(treeKey)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
Vec3 treeCenter = new Vec3(centerX + 0.5D, 0.0D, centerZ + 0.5D);
|
||||
AABB searchBox = new AABB(
|
||||
centerX - 512.0D, level.getMinBuildHeight(), centerZ - 512.0D,
|
||||
centerX + 512.0D, level.getMaxBuildHeight(), centerZ + 512.0D);
|
||||
List<KingEntity> treeKings = serverLevel.getEntitiesOfClass(KingEntity.class, searchBox,
|
||||
king -> king.isAlive() && king.isTreePatrolFor(treeCenter));
|
||||
if (!treeKings.isEmpty()) {
|
||||
// Repair older worlds that already contain duplicate tree-bound Kings.
|
||||
for (int index = 1; index < treeKings.size(); index++) {
|
||||
treeKings.get(index).discard();
|
||||
}
|
||||
return;
|
||||
}
|
||||
KingEntity king = AntarchyObjects.KING.get().create(serverLevel);
|
||||
if (king == null) {
|
||||
synchronized (CLAIMED_TREE_KINGS) {
|
||||
CLAIMED_TREE_KINGS.getOrDefault(serverLevel, Set.of()).remove(treeKey);
|
||||
}
|
||||
return;
|
||||
}
|
||||
double minimumY = baseY + 24.0D;
|
||||
double maximumY = baseY + 304.0D;
|
||||
double spawnY = (minimumY + maximumY) * 0.5D;
|
||||
// Start just outside the central trunk, inside the tree's authored footprint.
|
||||
king.moveTo(centerX + 48.5D, spawnY, centerZ + 0.5D, 90.0F, 0.0F);
|
||||
king.setTreePatrolHome(treeCenter, minimumY, maximumY, 0.0D);
|
||||
king.setPersistenceRequired();
|
||||
serverLevel.addFreshEntity(king);
|
||||
}
|
||||
KingEntity king = AntarchyObjects.KING.get().create(serverLevel);
|
||||
if (king == null) {
|
||||
return;
|
||||
}
|
||||
double minimumY = baseY + 24.0D;
|
||||
double maximumY = baseY + 304.0D;
|
||||
double spawnY = (minimumY + maximumY) * 0.5D;
|
||||
// Start just outside the central trunk, inside the tree's authored footprint.
|
||||
king.moveTo(centerX + 48.5D, spawnY, centerZ + 0.5D, 90.0F, 0.0F);
|
||||
king.setTreePatrolHome(treeCenter, minimumY, maximumY, 0.0D);
|
||||
king.setPersistenceRequired();
|
||||
serverLevel.addFreshEntity(king);
|
||||
}
|
||||
|
||||
private static ResourceLocation tileLocation(int tileX, int tileZ) {
|
||||
|
||||
+8
-11
@@ -341,21 +341,18 @@ public final class ThoraxisUndersideManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Keeps projectile gravity positional: UP below Y=0 in Thoraxis and DOWN
|
||||
* everywhere else. World velocity is preserved when the gravity frame changes.
|
||||
* Projectiles perform their own movement in world coordinates, so they must
|
||||
* not retain an inverted entity-local movement frame. Underside gravity is
|
||||
* reversed separately when gravitational acceleration is applied.
|
||||
*/
|
||||
public static void updateProjectileGravity(Projectile projectile) {
|
||||
boolean inUnderside = isInUnderside(projectile);
|
||||
AntarchyGravityDirection desiredDirection = inUnderside
|
||||
? AntarchyGravityDirection.UP
|
||||
: AntarchyGravityDirection.DOWN;
|
||||
boolean stateMismatch = AntarchyGravityApi.getGravityDirection(projectile) != desiredDirection
|
||||
|| AntarchyGravityApi.isGravityForced(projectile) != inUnderside;
|
||||
public static void normalizeProjectileGravityFrame(Projectile projectile) {
|
||||
boolean stateMismatch = AntarchyGravityApi.getGravityDirection(projectile) != AntarchyGravityDirection.DOWN
|
||||
|| AntarchyGravityApi.isGravityForced(projectile);
|
||||
if (stateMismatch) {
|
||||
AntarchyGravityApi.setAirborneGravityDirection(
|
||||
projectile,
|
||||
desiredDirection,
|
||||
inUnderside,
|
||||
AntarchyGravityDirection.DOWN,
|
||||
false,
|
||||
AntarchyGravityTransition.INSTANT
|
||||
);
|
||||
}
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package com.craisinlord.antarchy.mixins;
|
||||
|
||||
import com.craisinlord.antarchy.content.enchantment.AntarchyEnchantments;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.world.item.enchantment.Enchantment;
|
||||
import net.minecraft.world.item.CreativeModeTabs;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
@Mixin(CreativeModeTabs.class)
|
||||
public abstract class CreativeModeTabsEnchantmentOrderMixin {
|
||||
@Redirect(
|
||||
method = {"generateEnchantmentBookTypesOnlyMaxLevel", "generateEnchantmentBookTypesAllLevels"},
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/core/HolderLookup;listElements()Ljava/util/stream/Stream;")
|
||||
)
|
||||
private static Stream<Holder.Reference<Enchantment>> antarchy$orderEnchantments(HolderLookup<Enchantment> lookup) {
|
||||
List<Holder.Reference<Enchantment>> enchantments = lookup.listElements().toList();
|
||||
List<Holder.Reference<Enchantment>> antarchyEnchantments = enchantments.stream()
|
||||
.filter(CreativeModeTabsEnchantmentOrderMixin::isAntarchyEnchantment)
|
||||
.sorted(Comparator.comparingInt(CreativeModeTabsEnchantmentOrderMixin::priority))
|
||||
.toList();
|
||||
return Stream.concat(
|
||||
antarchyEnchantments.stream(),
|
||||
enchantments.stream().filter(holder -> !isAntarchyEnchantment(holder))
|
||||
);
|
||||
}
|
||||
|
||||
private static boolean isAntarchyEnchantment(Holder.Reference<Enchantment> holder) {
|
||||
return holder.is(AntarchyEnchantments.FEATHER_RISING) || holder.is(AntarchyEnchantments.CHRONOSPHERE);
|
||||
}
|
||||
|
||||
private static int priority(Holder.Reference<Enchantment> holder) {
|
||||
return holder.is(AntarchyEnchantments.FEATHER_RISING) ? 0 : 1;
|
||||
}
|
||||
}
|
||||
-47
@@ -1,47 +0,0 @@
|
||||
package com.craisinlord.antarchy.mixins.client;
|
||||
|
||||
import com.craisinlord.antarchy.content.client.ThoraxisWeatherClientState;
|
||||
import com.craisinlord.antarchy.content.weather.ThoraxisWeatherKind;
|
||||
import net.minecraft.client.renderer.entity.LightningBoltRenderer;
|
||||
import net.minecraft.world.entity.LightningBolt;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyArgs;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.invoke.arg.Args;
|
||||
|
||||
@Mixin(LightningBoltRenderer.class)
|
||||
public abstract class LightningBoltRendererMixin {
|
||||
@Unique
|
||||
private static final ThreadLocal<Boolean> antarchy$redLightning = ThreadLocal.withInitial(() -> false);
|
||||
|
||||
@Inject(method = "render", at = @At("HEAD"))
|
||||
private void antarchy$markRedLightning(LightningBolt bolt, float entityYaw, float partialTick, com.mojang.blaze3d.vertex.PoseStack poseStack, net.minecraft.client.renderer.MultiBufferSource buffer, int packedLight, CallbackInfo ci) {
|
||||
ThoraxisWeatherClientState.ThoraxisWeatherState weather = ThoraxisWeatherClientState.current(bolt.level());
|
||||
antarchy$redLightning.set(weather != null
|
||||
&& weather.kind() == ThoraxisWeatherKind.INVERSION_STORM
|
||||
&& weather.anchor().closerToCenterThan(bolt.position(), 64.0D));
|
||||
}
|
||||
|
||||
@Inject(method = "render", at = @At("RETURN"))
|
||||
private void antarchy$clearRedLightning(LightningBolt bolt, float entityYaw, float partialTick, com.mojang.blaze3d.vertex.PoseStack poseStack, net.minecraft.client.renderer.MultiBufferSource buffer, int packedLight, CallbackInfo ci) {
|
||||
antarchy$redLightning.remove();
|
||||
}
|
||||
|
||||
@ModifyArgs(
|
||||
method = "quad",
|
||||
at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/VertexConsumer;setColor(FFFF)Lcom/mojang/blaze3d/vertex/VertexConsumer;")
|
||||
)
|
||||
private static void antarchy$tintLightning(Args args) {
|
||||
if (!Boolean.TRUE.equals(antarchy$redLightning.get())) {
|
||||
return;
|
||||
}
|
||||
|
||||
args.set(0, 0.95F);
|
||||
args.set(1, 0.12F);
|
||||
args.set(2, 0.12F);
|
||||
args.set(3, 0.35F);
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package com.craisinlord.antarchy.mixins.client;
|
||||
|
||||
import com.craisinlord.antarchy.content.client.renderer.TemporalContractionAfterimageLayer;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.model.EntityModel;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(LivingEntityRenderer.class)
|
||||
public abstract class TemporalContractionLivingRendererMixin<T extends LivingEntity, M extends EntityModel<T>> {
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void antarchy$addTemporalContractionLayer(EntityRendererProvider.Context context, M model,
|
||||
float shadowRadius, CallbackInfo callbackInfo) {
|
||||
LivingEntityRenderer<T, M> renderer = (LivingEntityRenderer<T, M>) (Object) this;
|
||||
renderer.addLayer(new TemporalContractionAfterimageLayer<>(renderer));
|
||||
}
|
||||
}
|
||||
+4
-18
@@ -1,19 +1,15 @@
|
||||
package com.craisinlord.antarchy.mixins.gravity;
|
||||
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||
import com.craisinlord.antarchy.content.worldgen.thoraxis.ThoraxisUndersideManager;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.projectile.AbstractArrow;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
||||
@Mixin(AbstractArrow.class)
|
||||
/*
|
||||
* Flips arrow gravity for inverted shooters.
|
||||
* Flips arrow gravity from the arrow's current position.
|
||||
*/
|
||||
public abstract class AbstractArrowGravityMixin {
|
||||
|
||||
@@ -21,22 +17,12 @@ public abstract class AbstractArrowGravityMixin {
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/entity/projectile/AbstractArrow;applyGravity()V"))
|
||||
private void antarchy$applyArrowGravityUpward(AbstractArrow self, Operation<Void> original) {
|
||||
Entity owner = self.getOwner();
|
||||
if (!(owner instanceof LivingEntity living)) {
|
||||
if (!ThoraxisUndersideManager.isInUnderside(self)) {
|
||||
original.call(self);
|
||||
return;
|
||||
}
|
||||
if (owner instanceof net.minecraft.world.entity.player.Player && !AntarchySettings.invertProjectilesFromInvertedPlayers()) {
|
||||
original.call(self);
|
||||
return;
|
||||
}
|
||||
if (!ThoraxisUndersideManager.shouldInvertInUnderside(living)) {
|
||||
original.call(self);
|
||||
return;
|
||||
}
|
||||
// Vanilla applies gravity as -getGravity(). Negate that acceleration to
|
||||
// mirror the projectile's arc for the inverted Underside gravity.
|
||||
// Vanilla subtracts gravity from world Y; the Underside adds it instead.
|
||||
double gravity = self.getGravity();
|
||||
self.setDeltaMovement(self.getDeltaMovement().add(0.0D, -gravity, 0.0D));
|
||||
self.setDeltaMovement(self.getDeltaMovement().add(0.0D, gravity, 0.0D));
|
||||
}
|
||||
}
|
||||
+140
-91
@@ -5,14 +5,16 @@ import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection;
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil;
|
||||
import com.craisinlord.antarchy.content.portalgun.PortalGunCollisionHelper;
|
||||
import java.util.ArrayList;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import java.util.List;
|
||||
import java.util.TreeSet;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.MoverType;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
@@ -21,7 +23,10 @@ import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyArg;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyArgs;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.invoke.arg.Args;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@@ -36,6 +41,8 @@ public abstract class EntityMoveMixin {
|
||||
private double antarchy$lastPlayerMoveY = 0.0;
|
||||
@Unique
|
||||
private AABB antarchy$moveStartBox;
|
||||
@Unique
|
||||
private Vec3 antarchy$collideWorldMovement = Vec3.ZERO;
|
||||
|
||||
@Inject(method = "move", at = @At("HEAD"))
|
||||
private void antarchy$captureMoveStart(MoverType type, Vec3 movement, CallbackInfo ci) {
|
||||
@@ -139,105 +146,119 @@ public abstract class EntityMoveMixin {
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "collide", at = @At("HEAD"), cancellable = true)
|
||||
private void antarchy$invertedStepUp(Vec3 movement, CallbackInfoReturnable<Vec3> cir) {
|
||||
Entity entity = (Entity) (Object) this;
|
||||
if (!AntarchyGravityApi.isGravityInverted(entity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
AABB aabb = entity.getBoundingBox();
|
||||
List<VoxelShape> entityShapes = entity.level().getEntityCollisions(entity, aabb.expandTowards(movement));
|
||||
Vec3 collided = movement.lengthSqr() == 0.0 ? movement : Entity.collideBoundingBox(entity, movement, aabb, entity.level(), entityShapes);
|
||||
|
||||
boolean movedX = movement.x != collided.x;
|
||||
boolean movedY = movement.y != collided.y;
|
||||
boolean movedZ = movement.z != collided.z;
|
||||
boolean pressingIntoCeiling = movedY && movement.y > 0.0D;
|
||||
boolean supportedByCeiling = entity.onGround()
|
||||
|| !entity.level().noCollision(entity, aabb.move(0.0D, 1.0E-5D, 0.0D));
|
||||
float maxUpStep = entity.maxUpStep();
|
||||
|
||||
if (!(maxUpStep > 0.0F) || !(pressingIntoCeiling || supportedByCeiling) || !(movedX || movedZ)) {
|
||||
cir.setReturnValue(PortalGunCollisionHelper.resolveCollision(entity, aabb, movement, collided));
|
||||
return;
|
||||
}
|
||||
|
||||
AABB steppedBox = pressingIntoCeiling ? aabb.move(0.0, collided.y, 0.0) : aabb;
|
||||
AABB searchBox = steppedBox.expandTowards(movement.x, -(double) maxUpStep, movement.z);
|
||||
if (!pressingIntoCeiling) {
|
||||
searchBox = searchBox.expandTowards(0.0, 1.0E-5D, 0.0);
|
||||
}
|
||||
|
||||
List<VoxelShape> stepShapes = new ArrayList<>(entityShapes);
|
||||
entity.level().getBlockCollisions(entity, searchBox).forEach(stepShapes::add);
|
||||
|
||||
float currentStepY = (float) collided.y;
|
||||
float[] candidateHeights = antarchy$collectCandidateStepDownHeights(steppedBox, stepShapes, maxUpStep, currentStepY);
|
||||
for (float candidate : candidateHeights) {
|
||||
Vec3 stepped = Entity.collideBoundingBox(entity, new Vec3(movement.x, -(double) candidate, movement.z), steppedBox, entity.level(), stepShapes);
|
||||
if (stepped.horizontalDistanceSqr() > collided.horizontalDistanceSqr()) {
|
||||
double offset = steppedBox.maxY - aabb.maxY;
|
||||
cir.setReturnValue(PortalGunCollisionHelper.resolveCollision(entity, aabb, movement, stepped.add(0.0, offset, 0.0)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Exact candidate heights can still fail for composite ceiling shapes
|
||||
// (notably corner stairs). Mirror the older three-phase step routine:
|
||||
// move away from the ceiling, cross the obstruction, then settle back
|
||||
// toward the new ceiling surface.
|
||||
Vec3 awayFromCeiling = Entity.collideBoundingBox(
|
||||
entity,
|
||||
new Vec3(0.0D, -(double) maxUpStep, 0.0D),
|
||||
steppedBox,
|
||||
entity.level(),
|
||||
stepShapes
|
||||
);
|
||||
if (awayFromCeiling.y < -1.0E-7D) {
|
||||
AABB awayBox = steppedBox.move(awayFromCeiling);
|
||||
Vec3 acrossStep = Entity.collideBoundingBox(
|
||||
entity,
|
||||
new Vec3(movement.x, 0.0D, movement.z),
|
||||
awayBox,
|
||||
entity.level(),
|
||||
stepShapes
|
||||
);
|
||||
if (acrossStep.horizontalDistanceSqr() > collided.horizontalDistanceSqr()) {
|
||||
AABB acrossBox = awayBox.move(acrossStep);
|
||||
Vec3 settleToCeiling = Entity.collideBoundingBox(
|
||||
entity,
|
||||
new Vec3(0.0D, -awayFromCeiling.y, 0.0D),
|
||||
acrossBox,
|
||||
entity.level(),
|
||||
stepShapes
|
||||
);
|
||||
double initialVerticalOffset = steppedBox.maxY - aabb.maxY;
|
||||
Vec3 stepped = acrossStep.add(
|
||||
0.0D,
|
||||
initialVerticalOffset + awayFromCeiling.y + settleToCeiling.y,
|
||||
0.0D
|
||||
);
|
||||
cir.setReturnValue(PortalGunCollisionHelper.resolveCollision(entity, aabb, movement, stepped));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
cir.setReturnValue(PortalGunCollisionHelper.resolveCollision(entity, aabb, movement, collided));
|
||||
@Inject(method = "collide", at = @At("HEAD"))
|
||||
private void antarchy$captureCollideWorldMovement(Vec3 movement, CallbackInfoReturnable<Vec3> cir) {
|
||||
this.antarchy$collideWorldMovement = movement;
|
||||
}
|
||||
|
||||
@Unique
|
||||
private static float[] antarchy$collectCandidateStepDownHeights(AABB box, List<VoxelShape> shapes, float maxStep, float currentY) {
|
||||
/*
|
||||
* Keep vanilla's step algorithm in player-local coordinates. Its Y tests,
|
||||
* candidate heights and maxUpStep are all defined in that frame. Only the
|
||||
* physical AABB operations and low-level shape collision belong in world
|
||||
* coordinates.
|
||||
*/
|
||||
@ModifyVariable(
|
||||
method = "collide",
|
||||
at = @At(
|
||||
value = "INVOKE_ASSIGN",
|
||||
target = "Lnet/minecraft/world/level/Level;getEntityCollisions(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/phys/AABB;)Ljava/util/List;",
|
||||
ordinal = 0
|
||||
),
|
||||
ordinal = 0
|
||||
)
|
||||
private Vec3 antarchy$collideWorldToPlayer(Vec3 movement) {
|
||||
Entity entity = (Entity) (Object) this;
|
||||
AntarchyGravityDirection direction = AntarchyGravityApi.getGravityDirection(entity);
|
||||
if (!direction.isInverted()) {
|
||||
return movement;
|
||||
}
|
||||
return AntarchyGravityRotationUtil.vecWorldToPlayer(movement, direction);
|
||||
}
|
||||
|
||||
@ModifyArgs(
|
||||
method = "collide",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/phys/AABB;expandTowards(DDD)Lnet/minecraft/world/phys/AABB;"
|
||||
)
|
||||
)
|
||||
private void antarchy$expandStepSearchInWorldFrame(Args args) {
|
||||
Entity entity = (Entity) (Object) this;
|
||||
AntarchyGravityDirection direction = AntarchyGravityApi.getGravityDirection(entity);
|
||||
if (!direction.isInverted()) {
|
||||
return;
|
||||
}
|
||||
Vec3 world = AntarchyGravityRotationUtil.vecPlayerToWorld(
|
||||
new Vec3(args.get(0), args.get(1), args.get(2)), direction);
|
||||
args.set(0, world.x);
|
||||
args.set(1, world.y);
|
||||
args.set(2, world.z);
|
||||
}
|
||||
|
||||
@ModifyArgs(
|
||||
method = "collide",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/phys/AABB;move(DDD)Lnet/minecraft/world/phys/AABB;"
|
||||
)
|
||||
)
|
||||
private void antarchy$moveStepBoxInWorldFrame(Args args) {
|
||||
Entity entity = (Entity) (Object) this;
|
||||
AntarchyGravityDirection direction = AntarchyGravityApi.getGravityDirection(entity);
|
||||
if (!direction.isInverted()) {
|
||||
return;
|
||||
}
|
||||
Vec3 world = AntarchyGravityRotationUtil.vecPlayerToWorld(
|
||||
new Vec3(args.get(0), args.get(1), args.get(2)), direction);
|
||||
args.set(0, world.x);
|
||||
args.set(1, world.y);
|
||||
args.set(2, world.z);
|
||||
}
|
||||
|
||||
@WrapOperation(
|
||||
method = "collide",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/entity/Entity;collideBoundingBox(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/phys/AABB;Lnet/minecraft/world/level/Level;Ljava/util/List;)Lnet/minecraft/world/phys/Vec3;"
|
||||
)
|
||||
)
|
||||
private Vec3 antarchy$collideBoundingBoxInLocalFrame(
|
||||
Entity collisionEntity,
|
||||
Vec3 localMovement,
|
||||
AABB box,
|
||||
Level level,
|
||||
List<VoxelShape> collisions,
|
||||
Operation<Vec3> original
|
||||
) {
|
||||
AntarchyGravityDirection direction = AntarchyGravityApi.getGravityDirection(collisionEntity);
|
||||
if (!direction.isInverted()) {
|
||||
return original.call(collisionEntity, localMovement, box, level, collisions);
|
||||
}
|
||||
Vec3 worldMovement = AntarchyGravityRotationUtil.vecPlayerToWorld(localMovement, direction);
|
||||
Vec3 worldResult = original.call(collisionEntity, worldMovement, box, level, collisions);
|
||||
return AntarchyGravityRotationUtil.vecWorldToPlayer(worldResult, direction);
|
||||
}
|
||||
|
||||
@Redirect(
|
||||
method = "collide",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/entity/Entity;collectCandidateStepUpHeights(Lnet/minecraft/world/phys/AABB;Ljava/util/List;FF)[F"
|
||||
)
|
||||
)
|
||||
private float[] antarchy$collectGravityAwareStepHeights(
|
||||
AABB box, List<VoxelShape> shapes, float maxStep, float currentY) {
|
||||
Entity entity = (Entity) (Object) this;
|
||||
boolean inverted = AntarchyGravityApi.isGravityInverted(entity);
|
||||
TreeSet<Float> heights = new TreeSet<>();
|
||||
for (VoxelShape shape : shapes) {
|
||||
for (double coord : shape.getCoords(Direction.Axis.Y)) {
|
||||
float height = (float) (box.maxY - coord);
|
||||
float height = (float) (inverted ? box.maxY - coord : coord - box.minY);
|
||||
if (height >= 0.0F && height != currentY && height <= maxStep) {
|
||||
heights.add(height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float[] result = new float[heights.size()];
|
||||
int i = 0;
|
||||
for (float height : heights) {
|
||||
@@ -246,6 +267,34 @@ public abstract class EntityMoveMixin {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Redirect(
|
||||
method = "collide",
|
||||
at = @At(value = "FIELD", target = "Lnet/minecraft/world/phys/AABB;minY:D")
|
||||
)
|
||||
private double antarchy$readLocalStepBase(AABB box) {
|
||||
Entity entity = (Entity) (Object) this;
|
||||
if (!AntarchyGravityApi.isGravityInverted(entity)) {
|
||||
return box.minY;
|
||||
}
|
||||
return -box.maxY;
|
||||
}
|
||||
|
||||
@Inject(method = "collide", at = @At("RETURN"), cancellable = true)
|
||||
private void antarchy$collidePlayerToWorld(Vec3 movement, CallbackInfoReturnable<Vec3> cir) {
|
||||
Entity entity = (Entity) (Object) this;
|
||||
AntarchyGravityDirection direction = AntarchyGravityApi.getGravityDirection(entity);
|
||||
if (!direction.isInverted()) {
|
||||
return;
|
||||
}
|
||||
Vec3 worldResult = AntarchyGravityRotationUtil.vecPlayerToWorld(cir.getReturnValue(), direction);
|
||||
cir.setReturnValue(PortalGunCollisionHelper.resolveCollision(
|
||||
entity,
|
||||
entity.getBoundingBox(),
|
||||
this.antarchy$collideWorldMovement,
|
||||
worldResult
|
||||
));
|
||||
}
|
||||
|
||||
@Unique
|
||||
private boolean antarchy$intersectsAntiwater(Entity entity, AABB box) {
|
||||
BlockPos.MutableBlockPos cursor = new BlockPos.MutableBlockPos();
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package com.craisinlord.antarchy.mixins.gravity;
|
||||
|
||||
import com.craisinlord.antarchy.content.worldgen.thoraxis.ThoraxisUndersideManager;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.projectile.Projectile;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(Entity.class)
|
||||
/*
|
||||
* Entity declares applyGravity in 1.21.1. Restrict the reversed acceleration to
|
||||
* projectiles that are physically inside the Thoraxis Underside.
|
||||
*/
|
||||
public abstract class EntityProjectileGravityMixin {
|
||||
|
||||
@Inject(method = "applyGravity", at = @At("HEAD"), cancellable = true)
|
||||
private void antarchy$applyProjectileGravityUpward(CallbackInfo ci) {
|
||||
Entity self = (Entity) (Object) this;
|
||||
if (!(self instanceof Projectile projectile)
|
||||
|| !ThoraxisUndersideManager.isInUnderside(projectile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
projectile.setDeltaMovement(
|
||||
projectile.getDeltaMovement().add(0.0D, projectile.getGravity(), 0.0D)
|
||||
);
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
+39
-6
@@ -1,8 +1,14 @@
|
||||
package com.craisinlord.antarchy.mixins.gravity;
|
||||
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil;
|
||||
import com.craisinlord.antarchy.content.worldgen.thoraxis.ThoraxisUndersideManager;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.projectile.Projectile;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
@@ -10,9 +16,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(Projectile.class)
|
||||
/*
|
||||
* Gives every projectile a gravity frame based on its own position in Thoraxis.
|
||||
* A shooter can influence the initial aim, but cannot leave a projectile inverted
|
||||
* after it exits the Underside.
|
||||
* Keeps projectile movement in world space while reversing gravity and launch
|
||||
* direction only inside the Thoraxis Underside.
|
||||
*/
|
||||
public abstract class ProjectileGravityMixin {
|
||||
|
||||
@@ -26,11 +31,39 @@ public abstract class ProjectileGravityMixin {
|
||||
float inaccuracy,
|
||||
CallbackInfo ci
|
||||
) {
|
||||
ThoraxisUndersideManager.updateProjectileGravity((Projectile) (Object) this);
|
||||
ThoraxisUndersideManager.normalizeProjectileGravityFrame((Projectile) (Object) this);
|
||||
}
|
||||
|
||||
@Inject(method = "tick", at = @At("HEAD"))
|
||||
private void antarchy$updateUndersideGravity(CallbackInfo ci) {
|
||||
ThoraxisUndersideManager.updateProjectileGravity((Projectile) (Object) this);
|
||||
private void antarchy$keepWorldMovementFrame(CallbackInfo ci) {
|
||||
ThoraxisUndersideManager.normalizeProjectileGravityFrame((Projectile) (Object) this);
|
||||
}
|
||||
|
||||
@WrapOperation(
|
||||
method = "shootFromRotation",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/entity/projectile/Projectile;shoot(DDDFF)V"
|
||||
)
|
||||
)
|
||||
private void antarchy$rotateUndersideLaunchDirection(
|
||||
Projectile projectile,
|
||||
double x,
|
||||
double y,
|
||||
double z,
|
||||
float velocity,
|
||||
float inaccuracy,
|
||||
Operation<Void> original,
|
||||
@Local(argsOnly = true) Entity shooter
|
||||
) {
|
||||
Vec3 direction = new Vec3(x, y, z);
|
||||
if (ThoraxisUndersideManager.shouldInvertInUnderside(shooter)) {
|
||||
direction = AntarchyGravityRotationUtil.vecPlayerToWorld(
|
||||
direction,
|
||||
AntarchyGravityApi.getGravityDirection(shooter)
|
||||
);
|
||||
}
|
||||
original.call(projectile, direction.x, direction.y, direction.z, velocity, inaccuracy);
|
||||
}
|
||||
|
||||
}
|
||||
+4
-19
@@ -1,20 +1,15 @@
|
||||
package com.craisinlord.antarchy.mixins.gravity;
|
||||
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||
import com.craisinlord.antarchy.content.worldgen.thoraxis.ThoraxisUndersideManager;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.entity.projectile.ThrowableProjectile;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
||||
@Mixin(ThrowableProjectile.class)
|
||||
/*
|
||||
* Flips thrown projectile gravity for inverted shooters.
|
||||
* Flips thrown projectile gravity from the projectile's current position.
|
||||
*/
|
||||
public abstract class ThrowableProjectileGravityMixin {
|
||||
|
||||
@@ -22,22 +17,12 @@ public abstract class ThrowableProjectileGravityMixin {
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/entity/projectile/ThrowableProjectile;applyGravity()V"))
|
||||
private void antarchy$applyThrownProjectileGravityUpward(ThrowableProjectile self, Operation<Void> original) {
|
||||
Entity owner = self.getOwner();
|
||||
if (!(owner instanceof LivingEntity living)) {
|
||||
if (!ThoraxisUndersideManager.isInUnderside(self)) {
|
||||
original.call(self);
|
||||
return;
|
||||
}
|
||||
if (owner instanceof Player && !AntarchySettings.invertProjectilesFromInvertedPlayers()) {
|
||||
original.call(self);
|
||||
return;
|
||||
}
|
||||
if (!ThoraxisUndersideManager.shouldInvertInUnderside(living)) {
|
||||
original.call(self);
|
||||
return;
|
||||
}
|
||||
// Vanilla applies gravity as -getGravity(). Negate that acceleration to
|
||||
// mirror the projectile's arc for the inverted Underside gravity.
|
||||
// Vanilla subtracts gravity from world Y; the Underside adds it instead.
|
||||
double gravity = self.getGravity();
|
||||
self.setDeltaMovement(self.getDeltaMovement().add(0.0D, -gravity, 0.0D));
|
||||
self.setDeltaMovement(self.getDeltaMovement().add(0.0D, gravity, 0.0D));
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@
|
||||
"MinecartItemMixin",
|
||||
"GoopedStepSoundMixin",
|
||||
"ExperimentalSettingsLevelSummaryMixin",
|
||||
"CreativeModeTabsEnchantmentOrderMixin",
|
||||
"NightmareSwordDamageMixin",
|
||||
"NightmareArmorEffectImmunityMixin",
|
||||
"PotionBrewingMixin",
|
||||
@@ -63,6 +64,7 @@
|
||||
"gravity.EntityGravityFrameMixin",
|
||||
"gravity.EntityGravityMixin",
|
||||
"gravity.EntityMoveMixin",
|
||||
"gravity.EntityProjectileGravityMixin",
|
||||
"gravity.ExplosionGravityMixin",
|
||||
"gravity.FallingBlockEntityBlockDataMixin",
|
||||
"gravity.FireworkRocketGravityMixin",
|
||||
@@ -128,7 +130,6 @@
|
||||
"client.InventoryScreenRotationBypassMixin",
|
||||
"client.ExperimentalSettingsPopupMixin",
|
||||
"client.KrakensGraspChargePoseMixin",
|
||||
"client.LightningBoltRendererMixin",
|
||||
"client.MountedVehicleCameraMixin",
|
||||
"client.ParalyzedMouseTurnMixin",
|
||||
"client.LocalPlayerPortalMixin",
|
||||
@@ -140,6 +141,7 @@
|
||||
"client.ThoraxisFogMixin",
|
||||
"client.TigerEyeArmorHideMixin",
|
||||
"client.TigerEyeNameTagHideMixin",
|
||||
"client.TemporalContractionLivingRendererMixin",
|
||||
"client.WolfRendererGrimMixin",
|
||||
"gravity.client.CameraGravityMixin",
|
||||
"gravity.client.ClientPacketListenerGravityMixin",
|
||||
|
||||
+6
-6
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"variants": {
|
||||
"trial_spawner_state=inactive": {"model": "antarchy:block/undertrial_spawner_inactive", "x": 90},
|
||||
"trial_spawner_state=waiting_for_players": {"model": "antarchy:block/undertrial_spawner_inactive", "x": 90},
|
||||
"trial_spawner_state=active": {"model": "antarchy:block/undertrial_spawner_active", "x": 90},
|
||||
"trial_spawner_state=waiting_for_reward_ejection": {"model": "antarchy:block/undertrial_spawner_active", "x": 90},
|
||||
"trial_spawner_state=ejecting_reward": {"model": "antarchy:block/undertrial_spawner_ejecting_reward", "x": 90},
|
||||
"trial_spawner_state=cooldown": {"model": "antarchy:block/undertrial_spawner_inactive", "x": 90}
|
||||
"trial_spawner_state=inactive": {"model": "antarchy:block/undertrial_spawner_inactive", "x": 180},
|
||||
"trial_spawner_state=waiting_for_players": {"model": "antarchy:block/undertrial_spawner_inactive", "x": 180},
|
||||
"trial_spawner_state=active": {"model": "antarchy:block/undertrial_spawner_active", "x": 180},
|
||||
"trial_spawner_state=waiting_for_reward_ejection": {"model": "antarchy:block/undertrial_spawner_active", "x": 180},
|
||||
"trial_spawner_state=ejecting_reward": {"model": "antarchy:block/undertrial_spawner_ejecting_reward", "x": 180},
|
||||
"trial_spawner_state=cooldown": {"model": "antarchy:block/undertrial_spawner_inactive", "x": 180}
|
||||
}
|
||||
}
|
||||
@@ -5,24 +5,24 @@
|
||||
"vault_state=inactive,under_facing=east": {"model": "antarchy:block/undervault_off", "y": 90},
|
||||
"vault_state=inactive,under_facing=west": {"model": "antarchy:block/undervault_off", "y": 270},
|
||||
"vault_state=inactive,under_facing=up": {"model": "antarchy:block/undervault_off", "x": 270},
|
||||
"vault_state=inactive,under_facing=down": {"model": "antarchy:block/undervault_off", "x": 90},
|
||||
"vault_state=inactive,under_facing=down": {"model": "antarchy:block/undervault_off", "x": 180},
|
||||
"vault_state=active,under_facing=north": {"model": "antarchy:block/undervault_on"},
|
||||
"vault_state=active,under_facing=south": {"model": "antarchy:block/undervault_on", "y": 180},
|
||||
"vault_state=active,under_facing=east": {"model": "antarchy:block/undervault_on", "y": 90},
|
||||
"vault_state=active,under_facing=west": {"model": "antarchy:block/undervault_on", "y": 270},
|
||||
"vault_state=active,under_facing=up": {"model": "antarchy:block/undervault_on", "x": 270},
|
||||
"vault_state=active,under_facing=down": {"model": "antarchy:block/undervault_on", "x": 90},
|
||||
"vault_state=active,under_facing=down": {"model": "antarchy:block/undervault_on", "x": 180},
|
||||
"vault_state=unlocking,under_facing=north": {"model": "antarchy:block/undervault_on"},
|
||||
"vault_state=unlocking,under_facing=south": {"model": "antarchy:block/undervault_on", "y": 180},
|
||||
"vault_state=unlocking,under_facing=east": {"model": "antarchy:block/undervault_on", "y": 90},
|
||||
"vault_state=unlocking,under_facing=west": {"model": "antarchy:block/undervault_on", "y": 270},
|
||||
"vault_state=unlocking,under_facing=up": {"model": "antarchy:block/undervault_on", "x": 270},
|
||||
"vault_state=unlocking,under_facing=down": {"model": "antarchy:block/undervault_on", "x": 90},
|
||||
"vault_state=unlocking,under_facing=down": {"model": "antarchy:block/undervault_on", "x": 180},
|
||||
"vault_state=ejecting,under_facing=north": {"model": "antarchy:block/undervault_ejecting"},
|
||||
"vault_state=ejecting,under_facing=south": {"model": "antarchy:block/undervault_ejecting", "y": 180},
|
||||
"vault_state=ejecting,under_facing=east": {"model": "antarchy:block/undervault_ejecting", "y": 90},
|
||||
"vault_state=ejecting,under_facing=west": {"model": "antarchy:block/undervault_ejecting", "y": 270},
|
||||
"vault_state=ejecting,under_facing=up": {"model": "antarchy:block/undervault_ejecting", "x": 270},
|
||||
"vault_state=ejecting,under_facing=down": {"model": "antarchy:block/undervault_ejecting", "x": 90}
|
||||
"vault_state=ejecting,under_facing=down": {"model": "antarchy:block/undervault_ejecting", "x": 180}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
+2
@@ -8,5 +8,7 @@
|
||||
{"type":"minecraft:item","name":"antarchy:blood_crystal_shard","weight":9,"functions":[{"function":"minecraft:set_count","count":{"type":"minecraft:uniform","min":1,"max":3}}]},
|
||||
{"type":"minecraft:item","name":"antarchy:blood_crystal_apple","weight":15,"functions":[{"function":"minecraft:set_count","count":{"type":"minecraft:uniform","min":1,"max":2}}]},
|
||||
{"type":"minecraft:item","name":"minecraft:potion","weight":8,"functions":[{"function":"minecraft:set_potion","id":"antarchy:inversion"}]},
|
||||
{"type":"minecraft:item","name":"minecraft:potion","weight":6,"functions":[{"function":"minecraft:set_potion","id":"antarchy:time_contraction"}]},
|
||||
{"type":"minecraft:item","name":"minecraft:potion","weight":6,"functions":[{"function":"minecraft:set_potion","id":"antarchy:time_dilation"}]},
|
||||
{"type":"minecraft:item","name":"minecraft:book","weight":6,"functions":[{"function":"minecraft:enchant_randomly","options":["minecraft:mending","minecraft:unbreaking","minecraft:efficiency"]}]}
|
||||
]}],"random_sequence":"antarchy:chests/underside_ruins/generic"}
|
||||
+2
-1
@@ -8,6 +8,7 @@
|
||||
{"type":"minecraft:item","name":"minecraft:diamond_pickaxe","weight":8,"functions":[{"function":"minecraft:enchant_with_levels","levels":{"type":"minecraft:uniform","min":18,"max":30},"options":"#minecraft:on_random_loot"}]},
|
||||
{"type":"minecraft:item","name":"minecraft:book","weight":10,"functions":[{"function":"minecraft:enchant_randomly","options":["minecraft:mending","minecraft:unbreaking","minecraft:efficiency","minecraft:protection","antarchy:feather_rising","antarchy:chronosphere"]}]},
|
||||
{"type":"minecraft:item","name":"minecraft:tipped_arrow","weight":7,"functions":[{"function":"minecraft:set_count","count":{"type":"minecraft:uniform","min":4,"max":10}},{"function":"minecraft:set_potion","id":"antarchy:inversion"}]},
|
||||
{"type":"minecraft:item","name":"minecraft:potion","weight":7,"functions":[{"function":"minecraft:set_potion","id":"antarchy:inversion"}]},
|
||||
{"type":"minecraft:item","name":"minecraft:potion","weight":6,"functions":[{"function":"minecraft:set_potion","id":"antarchy:time_contraction"}]},
|
||||
{"type":"minecraft:item","name":"minecraft:potion","weight":6,"functions":[{"function":"minecraft:set_potion","id":"antarchy:time_dilation"}]},
|
||||
{"type":"minecraft:item","name":"antarchy:titanium_ingot","weight":1},{"type":"minecraft:item","name":"antarchy:uranium_ingot","weight":1}
|
||||
]}],"random_sequence":"antarchy:chests/underside_ruins/treasure"}
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
{
|
||||
"type": "minecraft:chest",
|
||||
"pools": [
|
||||
{
|
||||
"rolls": {
|
||||
"type": "minecraft:uniform",
|
||||
"min": 4,
|
||||
"max": 6
|
||||
},
|
||||
"entries": [
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "antarchy:ultimate_helmet",
|
||||
"weight": 2
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "antarchy:ultimate_chestplate",
|
||||
"weight": 2
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "antarchy:ultimate_leggings",
|
||||
"weight": 2
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "antarchy:ultimate_boots",
|
||||
"weight": 2
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "antarchy:ultimate_sword",
|
||||
"weight": 2
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "antarchy:ultimate_pickaxe",
|
||||
"weight": 2
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "antarchy:ultimate_axe",
|
||||
"weight": 2
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "antarchy:ultimate_shovel",
|
||||
"weight": 2
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "antarchy:ultimate_hoe",
|
||||
"weight": 2
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "antarchy:ultimate_bow",
|
||||
"weight": 2
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "antarchy:ultimate_crossbow",
|
||||
"weight": 2
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "minecraft:potion",
|
||||
"weight": 8,
|
||||
"functions": [
|
||||
{
|
||||
"function": "minecraft:set_potion",
|
||||
"id": "antarchy:time_contraction"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "minecraft:potion",
|
||||
"weight": 8,
|
||||
"functions": [
|
||||
{
|
||||
"function": "minecraft:set_potion",
|
||||
"id": "antarchy:time_dilation"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "minecraft:book",
|
||||
"weight": 4,
|
||||
"functions": [
|
||||
{
|
||||
"function": "minecraft:enchant_randomly",
|
||||
"options": [
|
||||
"antarchy:chronosphere"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "antarchy:queen_scale",
|
||||
"weight": 1
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "minecraft:netherite_scrap",
|
||||
"weight": 4,
|
||||
"functions": [
|
||||
{
|
||||
"function": "minecraft:set_count",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"min": 1,
|
||||
"max": 3
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "antarchy:titanium_block",
|
||||
"weight": 3
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "antarchy:uranium_block",
|
||||
"weight": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"random_sequence": "antarchy:chests/undertrial_vault"
|
||||
}
|
||||
+1
-1
@@ -3,5 +3,5 @@
|
||||
{"type":"minecraft:item","name":"antarchy:blood_crystal_katana","weight":4},{"type":"minecraft:item","name":"antarchy:blood_crystal_chestplate","weight":2},{"type":"minecraft:item","name":"antarchy:blood_crystal_leggings","weight":2},{"type":"minecraft:item","name":"antarchy:lucid_pearl","weight":4},
|
||||
{"type":"minecraft:item","name":"antarchy:bluestone","weight":14,"functions":[{"function":"minecraft:set_count","count":{"type":"minecraft:uniform","min":8,"max":20}}]},{"type":"minecraft:item","name":"antarchy:nyxite","weight":10,"functions":[{"function":"minecraft:set_count","count":{"type":"minecraft:uniform","min":3,"max":8}}]},
|
||||
{"type":"minecraft:item","name":"antarchy:blood_crystal_apple","weight":20,"functions":[{"function":"minecraft:set_count","count":{"type":"minecraft:uniform","min":1,"max":3}}]},
|
||||
{"type":"minecraft:item","name":"minecraft:tipped_arrow","weight":8,"functions":[{"function":"minecraft:set_count","count":{"type":"minecraft:uniform","min":4,"max":10}},{"function":"minecraft:set_potion","id":"antarchy:inversion"}]},{"type":"minecraft:item","name":"minecraft:potion","weight":8,"functions":[{"function":"minecraft:set_potion","id":"antarchy:inversion"}]},{"type":"minecraft:item","name":"minecraft:book","weight":10,"functions":[{"function":"minecraft:enchant_randomly","options":["minecraft:mending","minecraft:unbreaking","minecraft:efficiency","minecraft:fortune","antarchy:feather_rising","antarchy:chronosphere"]}]},{"type":"minecraft:item","name":"antarchy:titanium_ingot","weight":1},{"type":"minecraft:item","name":"antarchy:uranium_ingot","weight":1}
|
||||
{"type":"minecraft:item","name":"minecraft:tipped_arrow","weight":8,"functions":[{"function":"minecraft:set_count","count":{"type":"minecraft:uniform","min":4,"max":10}},{"function":"minecraft:set_potion","id":"antarchy:inversion"}]},{"type":"minecraft:item","name":"minecraft:potion","weight":8,"functions":[{"function":"minecraft:set_potion","id":"antarchy:inversion"}]},{"type":"minecraft:item","name":"minecraft:potion","weight":6,"functions":[{"function":"minecraft:set_potion","id":"antarchy:time_contraction"}]},{"type":"minecraft:item","name":"minecraft:potion","weight":6,"functions":[{"function":"minecraft:set_potion","id":"antarchy:time_dilation"}]},{"type":"minecraft:item","name":"minecraft:book","weight":10,"functions":[{"function":"minecraft:enchant_randomly","options":["minecraft:mending","minecraft:unbreaking","minecraft:efficiency","minecraft:fortune","antarchy:feather_rising","antarchy:chronosphere"]}]},{"type":"minecraft:item","name":"antarchy:titanium_ingot","weight":1},{"type":"minecraft:item","name":"antarchy:uranium_ingot","weight":1}
|
||||
]}],"random_sequence":"antarchy:spawners/underside_ruins/hard"}
|
||||
+1
-1
@@ -5,5 +5,5 @@
|
||||
{"type":"minecraft:item","name":"antarchy:bluestone","weight":15,"functions":[{"function":"minecraft:set_count","count":{"type":"minecraft:uniform","min":5,"max":14}}]},
|
||||
{"type":"minecraft:item","name":"antarchy:nyxite","weight":10,"functions":[{"function":"minecraft:set_count","count":{"type":"minecraft:uniform","min":1,"max":4}}]},
|
||||
{"type":"minecraft:item","name":"antarchy:blood_crystal_apple","weight":18,"functions":[{"function":"minecraft:set_count","count":{"type":"minecraft:uniform","min":1,"max":2}}]},
|
||||
{"type":"minecraft:item","name":"minecraft:potion","weight":9,"functions":[{"function":"minecraft:set_potion","id":"antarchy:inversion"}]},{"type":"minecraft:item","name":"minecraft:book","weight":7,"functions":[{"function":"minecraft:enchant_randomly","options":["minecraft:mending","minecraft:unbreaking","minecraft:efficiency"]}]}
|
||||
{"type":"minecraft:item","name":"minecraft:potion","weight":9,"functions":[{"function":"minecraft:set_potion","id":"antarchy:inversion"}]},{"type":"minecraft:item","name":"minecraft:potion","weight":6,"functions":[{"function":"minecraft:set_potion","id":"antarchy:time_contraction"}]},{"type":"minecraft:item","name":"minecraft:potion","weight":6,"functions":[{"function":"minecraft:set_potion","id":"antarchy:time_dilation"}]},{"type":"minecraft:item","name":"minecraft:book","weight":7,"functions":[{"function":"minecraft:enchant_randomly","options":["minecraft:mending","minecraft:unbreaking","minecraft:efficiency"]}]}
|
||||
]}],"random_sequence":"antarchy:spawners/underside_ruins/medium"}
|
||||
@@ -0,0 +1,76 @@
|
||||
{
|
||||
"type": "minecraft:chest",
|
||||
"pools": [
|
||||
{
|
||||
"rolls": {
|
||||
"type": "minecraft:uniform",
|
||||
"min": 2,
|
||||
"max": 4
|
||||
},
|
||||
"entries": [
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "antarchy:undertrial_key",
|
||||
"weight": 2
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "minecraft:potion",
|
||||
"weight": 8,
|
||||
"functions": [
|
||||
{
|
||||
"function": "minecraft:set_potion",
|
||||
"id": "antarchy:time_dilation"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "antarchy:cornea_stalk",
|
||||
"weight": 8,
|
||||
"functions": [
|
||||
{
|
||||
"function": "minecraft:set_count",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"min": 1,
|
||||
"max": 3
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "antarchy:bluestone",
|
||||
"weight": 10,
|
||||
"functions": [
|
||||
{
|
||||
"function": "minecraft:set_count",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"min": 2,
|
||||
"max": 8
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "minecraft:diamond",
|
||||
"weight": 4,
|
||||
"functions": [
|
||||
{
|
||||
"function": "minecraft:set_count",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"min": 1,
|
||||
"max": 2
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"random_sequence": "antarchy:spawners/undertrial"
|
||||
}
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+6
-1
@@ -2,6 +2,11 @@
|
||||
"replace": false,
|
||||
"values": [
|
||||
"antarchy:lucid",
|
||||
"antarchy:reverie"
|
||||
"antarchy:reverie",
|
||||
"antarchy:scorpion",
|
||||
"antarchy:bed_bug",
|
||||
"antarchy:queen",
|
||||
"antarchy:princess",
|
||||
"antarchy:manticore"
|
||||
]
|
||||
}
|
||||
+2
-3
@@ -6,8 +6,7 @@
|
||||
"antarchy:lucid",
|
||||
"antarchy:reverie",
|
||||
"antarchy:bed_bug",
|
||||
"antarchy:crawling_blight",
|
||||
"antarchy:skulking_fright",
|
||||
"antarchy:springbug"
|
||||
"antarchy:scorpion",
|
||||
"antarchy:emperor_scorpion"
|
||||
]
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"antarchy:dream_dunes"
|
||||
]
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"type": "integrated_api:ceiling_structure",
|
||||
"start_pool": "antarchy:underside_castle/underside_castle",
|
||||
"size": 1,
|
||||
"y_allowance": {
|
||||
"min_y_allowed": -256,
|
||||
"max_y_allowed": 24
|
||||
},
|
||||
"valid_biome_radius_check": 1,
|
||||
"biomes": "#antarchy:has_structure/underside_castle_biomes",
|
||||
"step": "underground_structures",
|
||||
"enhanced_terrain_adaptation": {
|
||||
"type": "integrated_api:none"
|
||||
},
|
||||
"start_height": {
|
||||
"type": "minecraft:constant",
|
||||
"value": {
|
||||
"absolute": -128
|
||||
}
|
||||
},
|
||||
"max_roof_search_distance": 256,
|
||||
"min_roof_thickness": 3,
|
||||
"min_open_space_below": 16,
|
||||
"ceiling_offset": 0,
|
||||
"spawn_overrides": {},
|
||||
"liquid_settings": "ignore_waterlogging"
|
||||
}
|
||||
@@ -2,6 +2,10 @@
|
||||
"structures": [
|
||||
{
|
||||
"structure": "antarchy:underside_ruins",
|
||||
"weight": 2
|
||||
},
|
||||
{
|
||||
"structure": "antarchy:underside_castle",
|
||||
"weight": 1
|
||||
}
|
||||
],
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "antarchy:underside_castle/underside_castle",
|
||||
"fallback": "minecraft:empty",
|
||||
"elements": [
|
||||
{
|
||||
"weight": 1,
|
||||
"element": {
|
||||
"location": "antarchy:underside_castle/underside_castle1",
|
||||
"processors": "antarchy:generic_processor",
|
||||
"projection": "rigid",
|
||||
"element_type": "integrated_api:integrated_api_single_pool_element"
|
||||
}
|
||||
},
|
||||
{
|
||||
"weight": 1,
|
||||
"element": {
|
||||
"location": "antarchy:underside_castle/underside_castle2",
|
||||
"processors": "antarchy:generic_processor",
|
||||
"projection": "rigid",
|
||||
"element_type": "integrated_api:integrated_api_single_pool_element"
|
||||
}
|
||||
},
|
||||
{
|
||||
"weight": 1,
|
||||
"element": {
|
||||
"location": "antarchy:underside_castle/underside_castle3",
|
||||
"processors": "antarchy:generic_processor",
|
||||
"projection": "rigid",
|
||||
"element_type": "integrated_api:integrated_api_single_pool_element"
|
||||
}
|
||||
},
|
||||
{
|
||||
"weight": 1,
|
||||
"element": {
|
||||
"location": "antarchy:underside_castle/underside_castle4",
|
||||
"processors": "antarchy:generic_processor",
|
||||
"projection": "rigid",
|
||||
"element_type": "integrated_api:integrated_api_single_pool_element"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+9
@@ -73,6 +73,15 @@
|
||||
"projection": "rigid",
|
||||
"element_type": "integrated_api:integrated_api_single_pool_element"
|
||||
}
|
||||
},
|
||||
{
|
||||
"weight": 1,
|
||||
"element": {
|
||||
"location": "antarchy:underside_ruins/underside_ruins9",
|
||||
"processors": "antarchy:generic_processor",
|
||||
"projection": "rigid",
|
||||
"element_type": "integrated_api:integrated_api_single_pool_element"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
"antarchy:blood_crystal_chestplate",
|
||||
"antarchy:primordial_chestplate",
|
||||
"antarchy:royal_guardian_chestplate",
|
||||
"antarchy:royal_assailant_chestplate"
|
||||
"antarchy:royal_assailant_chestplate",
|
||||
"antarchy:tigers_eye_chestplate"
|
||||
]
|
||||
}
|
||||
@@ -41,6 +41,10 @@
|
||||
"antarchy:royal_assailant_chestplate",
|
||||
"antarchy:royal_assailant_leggings",
|
||||
"antarchy:royal_assailant_boots",
|
||||
"antarchy:tigers_eye_helmet",
|
||||
"antarchy:tigers_eye_chestplate",
|
||||
"antarchy:tigers_eye_leggings",
|
||||
"antarchy:tigers_eye_boots",
|
||||
"antarchy:royal_guardian_sword",
|
||||
"antarchy:royal_assailant_battleaxe",
|
||||
"antarchy:royal_guardian_shield",
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
"antarchy:brutalfly_elytra",
|
||||
"antarchy:springy_boots",
|
||||
"antarchy:manticore_wings",
|
||||
"antarchy:tigers_eye_helmet",
|
||||
"antarchy:tigers_eye_chestplate",
|
||||
"antarchy:tigers_eye_leggings",
|
||||
"antarchy:tigers_eye_boots",
|
||||
"antarchy:royal_assailant_battleaxe"
|
||||
]
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
"antarchy:primordial_boots",
|
||||
"antarchy:springy_boots",
|
||||
"antarchy:royal_guardian_boots",
|
||||
"antarchy:royal_assailant_boots"
|
||||
"antarchy:royal_assailant_boots",
|
||||
"antarchy:tigers_eye_boots"
|
||||
]
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
"antarchy:fallen_king_crown",
|
||||
"antarchy:primordial_helmet",
|
||||
"antarchy:royal_guardian_helmet",
|
||||
"antarchy:royal_assailant_helmet"
|
||||
"antarchy:royal_assailant_helmet",
|
||||
"antarchy:tigers_eye_helmet"
|
||||
]
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
"antarchy:blood_crystal_leggings",
|
||||
"antarchy:primordial_leggings",
|
||||
"antarchy:royal_guardian_leggings",
|
||||
"antarchy:royal_assailant_leggings"
|
||||
"antarchy:royal_assailant_leggings",
|
||||
"antarchy:tigers_eye_leggings"
|
||||
]
|
||||
}
|
||||
Reference in new issue
Block a user