Skip to content

Commit

Permalink
Provide more-sane eldritch altar mob-spawning behaviors (#101)
Browse files Browse the repository at this point in the history
* Pick coordinates for knights and guardians in an even distribution

* Unrelated fix: set remap = false for levitator

* Create an enum setting type

* Provide an origin-centered eldritch altar spawning behavior

* Add documentation for eldritchAltarSpawningMethod

* Inline local variable updates, suppress local param warnings

* Condense two mixins into one
  • Loading branch information
rndmorris authored Jan 20, 2025
1 parent d0c0584 commit 3834bd3
Show file tree
Hide file tree
Showing 7 changed files with 194 additions and 3 deletions.
9 changes: 9 additions & 0 deletions docs/enhancements.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,15 @@ Has the side effect of making non-shifting entities, like passive mobs, unable t

By default, pure nodes only change the biome around them if they are either in tainted lands or inside of a silverwood tree. This setting allows pure nodes to change the biome around them regardless of their location.

## Alternate Eldritch Altar Mob Spawning

**Config Option:** `eldritchAltarSpawningMethod`

Override how eldritch altars pick where to try spawning crimson knights and eldritch guardians. [The default approach is... unusual](https://github.com/rndmorris/Salis-Arcana/issues/99).

* `EVEN_SPREAD`: each valid coordinate in range has an equal chance of being selected. Will not try to spawn in spaces occupied by the altar itself.
* `CENTER_WEIGHTED`: weighted towards coordinates near the altar. Will not try to spawn in spaces occupied by the altar itself.

# Enhancements - Infusion

## Config option: `useStabilizerRewrite`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import dev.rndmorris.salisarcana.config.ConfigPhase;
import dev.rndmorris.salisarcana.config.settings.BlockItemListSetting;
import dev.rndmorris.salisarcana.config.settings.CustomResearchSetting;
import dev.rndmorris.salisarcana.config.settings.EldritchAltarMobSpawnSetting;
import dev.rndmorris.salisarcana.config.settings.IntArraySetting;
import dev.rndmorris.salisarcana.config.settings.IntSetting;
import dev.rndmorris.salisarcana.config.settings.ReplaceWandComponentSettings;
Expand Down Expand Up @@ -48,6 +49,8 @@ public class EnhancementsModule extends BaseConfigModule {

public final IntSetting itemEldritchObjectStackSize;

public final EldritchAltarMobSpawnSetting eldritchAltarSpawningMethod;

public final ToggleSetting wandPedestalUseCV;
public final ToggleSetting thaumometerScanContainers;
public final CustomResearchSetting thaumometerScanContainersResearch;
Expand Down Expand Up @@ -218,8 +221,12 @@ public EnhancementsModule() {
this,
ConfigPhase.EARLY,
"pureNodeAlwaysMagicalForest",
"By default, pure nodes only change the biome around them if they are either in tainted lands or inside of a silverwood tree. This setting allows pure nodes to change the biome around them regardless of their location.")

"By default, pure nodes only change the biome around them if they are either in tainted lands or inside of a silverwood tree. This setting allows pure nodes to change the biome around them regardless of their location."),
eldritchAltarSpawningMethod = new EldritchAltarMobSpawnSetting(
this,
ConfigPhase.EARLY,
"eldritchAltarSpawningMethod",
"Override how eldritch altars pick where to try spawning crimson knights and eldritch guardians.")
);

// spotless:on
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package dev.rndmorris.salisarcana.config.settings;

import java.util.Random;

import net.minecraft.util.MathHelper;

import dev.rndmorris.salisarcana.config.ConfigPhase;
import dev.rndmorris.salisarcana.config.IEnabler;

public class EldritchAltarMobSpawnSetting extends EnumSetting<EldritchAltarMobSpawnSetting.Options> {

public EldritchAltarMobSpawnSetting(IEnabler dependency, ConfigPhase phase, String name, String comment) {
super(dependency, phase, name, comment, Options.DEFAULT);
}

public int randomHorizontal(Random random) {
return switch (value) {
case EVEN_SPREAD -> horizontalEven(random);
case CENTER_WEIGHTED -> horizontalWeighted(random);
default -> throw new RuntimeException(
String.format(
"%s called while its mixin should be disabled.",
EldritchAltarMobSpawnSetting.class.getName()));
};
}

public int randomVertical(Random random) {
return switch (value) {
case EVEN_SPREAD -> verticalEven(random);
case CENTER_WEIGHTED -> verticalWeighted(random);
default -> throw new RuntimeException(
String.format(
"%s called while its mixin should be disabled.",
EldritchAltarMobSpawnSetting.class.getName()));
};
}

private int horizontalEven(Random random) {
return (MathHelper.getRandomIntegerInRange(random, 0, 6) + 4) * (random.nextBoolean() ? 1 : -1);
}

private int verticalEven(Random random) {
return MathHelper.getRandomIntegerInRange(random, -3, 3);
}

private int horizontalWeighted(Random random) {
final var val = MathHelper.getRandomIntegerInRange(random, 0, 6)
- MathHelper.getRandomIntegerInRange(random, 0, 6);
if (val == 0) {
return val + (4 * (random.nextBoolean() ? 1 : -1));
}
if (val < 0) {
return val - 4;
}
return val + 4;
}

private int verticalWeighted(Random random) {
return MathHelper.getRandomIntegerInRange(random, 0, 3) - MathHelper.getRandomIntegerInRange(random, 0, 3);
}

@Override
public boolean isEnabled() {
return super.isEnabled() && value != Options.DEFAULT;
}

public enum Options {
DEFAULT,
EVEN_SPREAD,
CENTER_WEIGHTED
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package dev.rndmorris.salisarcana.config.settings;

import java.util.Arrays;

import javax.annotation.Nonnull;

import net.minecraftforge.common.config.Configuration;

import dev.rndmorris.salisarcana.config.ConfigPhase;
import dev.rndmorris.salisarcana.config.IEnabler;

public class EnumSetting<E extends Enum<E>> extends Setting {

protected final Class<E> enumClass;
protected final String name;
protected final String comment;
protected E value;

public EnumSetting(IEnabler dependency, ConfigPhase phase, String name, String comment, @Nonnull E defaultValue) {
super(dependency, phase);
this.name = name;
enumClass = defaultValue.getDeclaringClass();
value = defaultValue;

final var sb = new StringBuilder();
final var $vals = Arrays.stream(enumClass.getEnumConstants())
.iterator();
while ($vals.hasNext()) {
sb.append(
$vals.next()
.toString());
if ($vals.hasNext()) {
sb.append(", ");
}
}

this.comment = comment + " Valid values: [" + sb + "]";
}

@Override
public void loadFromConfiguration(Configuration configuration) {
final var validValues = Arrays.stream(enumClass.getEnumConstants())
.map(Enum::toString)
.toArray(String[]::new);
final var valueString = configuration.getString(name, getCategory(), value.toString(), comment, validValues);
value = Enum.valueOf(enumClass, valueString);
}
}
6 changes: 6 additions & 0 deletions src/main/java/dev/rndmorris/salisarcana/mixins/Mixins.java
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,12 @@ public enum Mixins {
.addMixinClasses("tiles.MixinTileNode")
.addTargetedMod(TargetedMod.THAUMCRAFT)),

ELDRITCH_ALTAR_EVEN_SPREAD_MOBS(new Builder().setPhase(Phase.LATE)
.setSide(Side.BOTH)
.setApplyIf(ConfigModuleRoot.enhancements.eldritchAltarSpawningMethod::isEnabled)
.addMixinClasses("tiles.MixinTileEldritchAltar_SpawnMobs")
.addTargetedMod(TargetedMod.THAUMCRAFT)),

;

private final List<String> mixinClasses;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package dev.rndmorris.salisarcana.mixins.late.tiles;

import java.util.Random;

import net.minecraft.world.IBlockAccess;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;

import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import com.llamalad7.mixinextras.sugar.ref.LocalIntRef;

import dev.rndmorris.salisarcana.config.ConfigModuleRoot;
import thaumcraft.api.TileThaumcraft;
import thaumcraft.common.tiles.TileEldritchAltar;

@Mixin(value = TileEldritchAltar.class, remap = false)
public abstract class MixinTileEldritchAltar_SpawnMobs extends TileThaumcraft {

@WrapOperation(
method = { "spawnGuards", "spawnGuardian" },
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/util/MathHelper;getRandomIntegerInRange(Ljava/util/Random;II)I"))
private int preventRandCalls(Random random, int min, int max, Operation<Integer> original) {
return 0;
}

@WrapOperation(
method = { "spawnGuards", "spawnGuardian" },
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/World;doesBlockHaveSolidTopSurface(Lnet/minecraft/world/IBlockAccess;III)Z"))
@SuppressWarnings("ParameterCanBeLocal")
private boolean pickAndCheckCoords(IBlockAccess worldIn, int x, int y, int z, Operation<Boolean> original,
@Local(name = "i1") LocalIntRef xRef, @Local(name = "j1") LocalIntRef yRef,
@Local(name = "k1") LocalIntRef zRef) {

final var spawnSettings = ConfigModuleRoot.enhancements.eldritchAltarSpawningMethod;

xRef.set(x = xCoord + spawnSettings.randomHorizontal(worldObj.rand));
yRef.set(y = yCoord + spawnSettings.randomVertical(worldObj.rand));
zRef.set(z = zCoord + spawnSettings.randomHorizontal(worldObj.rand));

return original.call(worldIn, x, y - 1, z);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import thaumcraft.common.tiles.TileLifter;

@Mixin(TileLifter.class)
@Mixin(value = TileLifter.class, remap = false)
public abstract class MixinTileLifter extends TileEntity {

@Shadow
Expand Down

0 comments on commit 3834bd3

Please sign in to comment.