Skip to content

Commit

Permalink
Replace NaturalSpawner overwrite with a better injection
Browse files Browse the repository at this point in the history
  • Loading branch information
Yeregorix committed Mar 6, 2025
1 parent 1ae5420 commit 677dada
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 130 deletions.

This file was deleted.

1 change: 0 additions & 1 deletion src/accessors/resources/mixins.sponge.accessors.json
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,6 @@
"world.level.GameRulesAccessor",
"world.level.LevelAccessor",
"world.level.LevelSettingsAccessor",
"world.level.NaturalSpawner_SpawnStateAccessor",
"world.level.NaturalSpawnerAccessor",
"world.level.biome.Biome_ClimateSettingsAccessor",
"world.level.biome.BiomeAccessor",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@

public interface NaturalSpawner_SpawnStateBridge {

boolean bridge$canSpawnForCategoryInWorld(MobCategory p_234991_1_, ServerLevel world);
boolean bridge$canSpawnForCategoryInWorld(MobCategory category, ServerLevel level);

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,81 +24,47 @@
*/
package org.spongepowered.common.mixin.core.world.level;

import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.MobCategory;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.NaturalSpawner;
import net.minecraft.world.level.chunk.LevelChunk;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.common.accessor.world.level.NaturalSpawner_SpawnStateAccessor;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.common.bridge.world.level.NaturalSpawner_SpawnStateBridge;
import org.spongepowered.common.config.SpongeGameConfigs;
import org.spongepowered.common.config.inheritable.SpawnerCategory;

@Mixin(NaturalSpawner.class)
public abstract class NaturalSpawnerMixin {

// @formatter:off
@Shadow @Final private static MobCategory[] SPAWNING_CATEGORIES;
@Shadow static public void spawnCategoryForChunk(final MobCategory p_234967_0_, final ServerLevel p_234967_1_, final LevelChunk p_234967_2_,
final NaturalSpawner.SpawnPredicate p_234967_3_, final NaturalSpawner.AfterSpawnCallback p_234967_4_) {
}
// @formatter:on

/**
* @author morph - January 3rd, 2021 - Minecraft 1.16.4
* @reason Use world configured spawn limits
*/
@Overwrite
public static void spawnForChunk(final ServerLevel world, final LevelChunk chunk, final NaturalSpawner.SpawnState manager, final boolean spawnFriendlies, final boolean spawnEnemies, final boolean doMobSpawning) {
world.getProfiler().push("spawner");

for (final MobCategory entityclassification : SPAWNING_CATEGORIES) {
if ((spawnFriendlies || !entityclassification.isFriendly()) && (spawnEnemies || entityclassification.isFriendly()) && (doMobSpawning || !entityclassification.isPersistent()) && NaturalSpawnerMixin.impl$canSpawnInLevel(manager, entityclassification, world, chunk)) {
// spawnCategoryForChunk(var0, param0, param1, (param1x, param2x, param3x) -> param2.canSpawn(param1x, param2x,
// param3x), (param1x, param2x) -> param2.afterSpawn(param1x, param2x));
NaturalSpawnerMixin.spawnCategoryForChunk(entityclassification, world, chunk,
(p_234969_1_, p_234969_2_, p_234969_3_) -> ((NaturalSpawner_SpawnStateAccessor) manager).invoker$canSpawn(p_234969_1_, p_234969_2_, p_234969_3_),
(p_234970_1_, p_234970_2_) -> ((NaturalSpawner_SpawnStateAccessor) manager).invoker$afterSpawn(p_234970_1_, p_234970_2_)
);
}
}

world.getProfiler().pop();
}

private static boolean impl$canSpawnInLevel(final NaturalSpawner.SpawnState manager, final MobCategory classification, final ServerLevel level, final LevelChunk chunk) {
final int tick = NaturalSpawnerMixin.impl$getSpawningTickRate(classification, level);
@WrapOperation(method = "spawnForChunk", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/NaturalSpawner$SpawnState;canSpawnForCategory(Lnet/minecraft/world/entity/MobCategory;Lnet/minecraft/world/level/ChunkPos;)Z"))
private static boolean impl$spawnTickRate(final NaturalSpawner.SpawnState state, final MobCategory category, final ChunkPos pos,
final Operation<Boolean> original, @Local(argsOnly = true) final ServerLevel level) {
final int tickRate = NaturalSpawnerMixin.impl$getSpawningTickRate(category, level);
// Unknown category/use default
if (tick == -1) {
return ((NaturalSpawner_SpawnStateAccessor) manager).invoker$canSpawnForCategory(classification, chunk.getPos());
if (tickRate == -1) {
return original.call(state, category, pos);
}
// Turn off spawns
if (tick == 0) {
if (tickRate == 0) {
return false;
}
return level.getGameTime() % tick == 0L && ((NaturalSpawner_SpawnStateBridge) manager).bridge$canSpawnForCategoryInWorld(classification, level);
return level.getGameTime() % tickRate == 0L && ((NaturalSpawner_SpawnStateBridge) state).bridge$canSpawnForCategoryInWorld(category, level);
}

private static int impl$getSpawningTickRate(final MobCategory classification, final ServerLevel level) {
private static int impl$getSpawningTickRate(final MobCategory category, final ServerLevel level) {
final SpawnerCategory.TickRatesSubCategory tickRates = SpongeGameConfigs.getForWorld(level).get().spawner.tickRates;
switch (classification) {
case MONSTER:
return tickRates.monster;
case CREATURE:
return tickRates.creature;
case AMBIENT:
return tickRates.ambient;
case UNDERGROUND_WATER_CREATURE:
return tickRates.undergroundAquaticCreature;
case WATER_CREATURE:
return tickRates.aquaticCreature;
case WATER_AMBIENT:
return tickRates.aquaticAmbient;
default:
return -1;
}
return switch (category) {
case MONSTER -> tickRates.monster;
case CREATURE -> tickRates.creature;
case AMBIENT -> tickRates.ambient;
case UNDERGROUND_WATER_CREATURE -> tickRates.undergroundAquaticCreature;
case WATER_CREATURE -> tickRates.aquaticCreature;
case WATER_AMBIENT -> tickRates.aquaticAmbient;
default -> -1;
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,32 +45,18 @@ public abstract class NaturalSpawner_SpawnStateMixin implements NaturalSpawner_S
// @formatter:on

@Override
public boolean bridge$canSpawnForCategoryInWorld(final MobCategory classification, final ServerLevel world) {
final SpawnerCategory.SpawnLimitsSubCategory spawnLimits = SpongeGameConfigs.getForWorld(world).get().spawner.spawnLimits;
final int maxInstancesPerChunk;
switch (classification) {
case MONSTER:
maxInstancesPerChunk = spawnLimits.monster;
break;
case CREATURE:
maxInstancesPerChunk = spawnLimits.creature;
break;
case AMBIENT:
maxInstancesPerChunk = spawnLimits.ambient;
break;
case UNDERGROUND_WATER_CREATURE:
maxInstancesPerChunk = spawnLimits.undergroundAquaticCreature;
break;
case WATER_CREATURE:
maxInstancesPerChunk = spawnLimits.aquaticCreature;
break;
case WATER_AMBIENT:
maxInstancesPerChunk = spawnLimits.aquaticAmbient;
break;
default:
throw new IllegalStateException("Unexpected value: " + classification);
}
public boolean bridge$canSpawnForCategoryInWorld(final MobCategory category, final ServerLevel level) {
final SpawnerCategory.SpawnLimitsSubCategory spawnLimits = SpongeGameConfigs.getForWorld(level).get().spawner.spawnLimits;
final int maxInstancesPerChunk = switch (category) {
case MONSTER -> spawnLimits.monster;
case CREATURE -> spawnLimits.creature;
case AMBIENT -> spawnLimits.ambient;
case UNDERGROUND_WATER_CREATURE -> spawnLimits.undergroundAquaticCreature;
case WATER_CREATURE -> spawnLimits.aquaticCreature;
case WATER_AMBIENT -> spawnLimits.aquaticAmbient;
default -> throw new IllegalStateException("Unexpected value: " + category);
};
final int i = maxInstancesPerChunk * this.spawnableChunkCount / NaturalSpawnerAccessor.accessor$MAGIC_NUMBER();
return this.mobCategoryCounts.getInt(classification) < i;
return this.mobCategoryCounts.getInt(category) < i;
}
}

0 comments on commit 677dada

Please sign in to comment.