Spawn API enhancements
This commit is contained in:
parent
5d5c215f48
commit
7def63ee01
12 changed files with 308 additions and 37 deletions
|
@ -3,7 +3,7 @@ package ru.bclib;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import ru.bclib.api.datafixer.DataFixerAPI;
|
import ru.bclib.api.datafixer.DataFixerAPI;
|
||||||
import ru.bclib.api.datafixer.Patch;
|
import ru.bclib.api.datafixer.Patch;
|
||||||
import ru.bclib.api.datafixer.PatchFunction;
|
import ru.bclib.interfaces.PatchFunction;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
|
@Deprecated(forRemoval = true)
|
||||||
public class SpawnAPI<T extends Entity> {
|
public class SpawnAPI<T extends Entity> {
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface SpawnRule<E extends Entity> {
|
public interface SpawnRule<E extends Entity> {
|
||||||
|
|
|
@ -3,6 +3,8 @@ package ru.bclib.api.datafixer;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.nbt.ListTag;
|
import net.minecraft.nbt.ListTag;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import ru.bclib.interfaces.PatchBiFunction;
|
||||||
|
import ru.bclib.interfaces.PatchFunction;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
|
@ -7,6 +7,8 @@ import net.minecraft.nbt.Tag;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import ru.bclib.BCLib;
|
import ru.bclib.BCLib;
|
||||||
import ru.bclib.api.WorldDataAPI;
|
import ru.bclib.api.WorldDataAPI;
|
||||||
|
import ru.bclib.interfaces.PatchBiFunction;
|
||||||
|
import ru.bclib.interfaces.PatchFunction;
|
||||||
import ru.bclib.util.ModUtil;
|
import ru.bclib.util.ModUtil;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
|
@ -3,6 +3,8 @@ package ru.bclib.api.datafixer;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.nbt.ListTag;
|
import net.minecraft.nbt.ListTag;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import ru.bclib.interfaces.PatchBiFunction;
|
||||||
|
import ru.bclib.interfaces.PatchFunction;
|
||||||
import ru.bclib.util.ModUtil;
|
import ru.bclib.util.ModUtil;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
215
src/main/java/ru/bclib/api/spawning/SpawnRuleBulder.java
Normal file
215
src/main/java/ru/bclib/api/spawning/SpawnRuleBulder.java
Normal file
|
@ -0,0 +1,215 @@
|
||||||
|
package ru.bclib.api.spawning;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
import net.fabricmc.fabric.mixin.object.builder.SpawnRestrictionAccessor;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.world.Difficulty;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.entity.Mob;
|
||||||
|
import net.minecraft.world.entity.MobSpawnType;
|
||||||
|
import net.minecraft.world.entity.SpawnPlacements.SpawnPredicate;
|
||||||
|
import net.minecraft.world.entity.SpawnPlacements.Type;
|
||||||
|
import net.minecraft.world.level.ServerLevelAccessor;
|
||||||
|
import net.minecraft.world.level.levelgen.Heightmap.Types;
|
||||||
|
import net.minecraft.world.phys.AABB;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class SpawnRuleBulder<M extends Mob> {
|
||||||
|
private static final Map<String, SpawnRuleEntry> RULES_CACHE = Maps.newHashMap();
|
||||||
|
private static final SpawnRuleBulder INSTANCE = new SpawnRuleBulder();
|
||||||
|
private List<SpawnRuleEntry> rules = Lists.newArrayList();
|
||||||
|
private SpawnRuleEntry entryInstance;
|
||||||
|
private EntityType<M> entityType;
|
||||||
|
|
||||||
|
private SpawnRuleBulder() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts new rule building process.
|
||||||
|
* @return prepared {@link SpawnRuleBulder} instance
|
||||||
|
*/
|
||||||
|
public static SpawnRuleBulder start(EntityType<? extends Mob> entityType) {
|
||||||
|
INSTANCE.entityType = entityType;
|
||||||
|
INSTANCE.rules.clear();
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop entity spawn on peaceful {@link Difficulty}
|
||||||
|
* @return same {@link SpawnRuleBulder} instance
|
||||||
|
*/
|
||||||
|
public SpawnRuleBulder notPeaceful() {
|
||||||
|
entryInstance = getFromCache("not_peaceful", () -> {
|
||||||
|
return new SpawnRuleEntry(0, (type, world, spawnReason, pos, random) -> world.getDifficulty() != Difficulty.PEACEFUL);
|
||||||
|
});
|
||||||
|
rules.add(entryInstance);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restricts entity spawn below world logical height (useful for Nether mobs).
|
||||||
|
* @return same {@link SpawnRuleBulder} instance
|
||||||
|
*/
|
||||||
|
public SpawnRuleBulder belowMaxHeight() {
|
||||||
|
entryInstance = getFromCache("not_peaceful", () -> {
|
||||||
|
return new SpawnRuleEntry(0, (type, world, spawnReason, pos, random) -> pos.getY() < world.dimensionType().logicalHeight());
|
||||||
|
});
|
||||||
|
rules.add(entryInstance);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will spawn entity only below specified brightness value.
|
||||||
|
* @param lightLevel light level upper limit.
|
||||||
|
* @return same {@link SpawnRuleBulder} instance
|
||||||
|
*/
|
||||||
|
public SpawnRuleBulder belowBrightness(int lightLevel) {
|
||||||
|
entryInstance = getFromCache("below_brightness_" + lightLevel, () -> {
|
||||||
|
return new SpawnRuleEntry(1, (type, world, spawnReason, pos, random) -> world.getMaxLocalRawBrightness(pos) <= lightLevel);
|
||||||
|
});
|
||||||
|
rules.add(entryInstance);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will spawn entity only above specified brightness value.
|
||||||
|
* @param lightLevel light level lower limit.
|
||||||
|
* @return same {@link SpawnRuleBulder} instance
|
||||||
|
*/
|
||||||
|
public SpawnRuleBulder aboveBrightness(int lightLevel) {
|
||||||
|
entryInstance = getFromCache("above_brightness_" + lightLevel, () -> {
|
||||||
|
return new SpawnRuleEntry(1, (type, world, spawnReason, pos, random) -> world.getMaxLocalRawBrightness(pos) >= lightLevel);
|
||||||
|
});
|
||||||
|
rules.add(entryInstance);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entity spawn will follow common vanilla spawn rules - spawn in darkness and not on peaceful level.
|
||||||
|
* @return same {@link SpawnRuleBulder} instance
|
||||||
|
*/
|
||||||
|
public SpawnRuleBulder vanillaHostile() {
|
||||||
|
return notPeaceful().belowBrightness(7);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will spawn entity only if count of nearby entities will be lower than specified.
|
||||||
|
* @param selectorType selector {@link EntityType} to search.
|
||||||
|
* @param count max entity count.
|
||||||
|
* @param side side of box to search in.
|
||||||
|
* @return same {@link SpawnRuleBulder} instance
|
||||||
|
*/
|
||||||
|
public SpawnRuleBulder maxNerby(EntityType<?> selectorType, int count, int side) {
|
||||||
|
final Class<? extends Entity> baseClass = selectorType.getBaseClass();
|
||||||
|
entryInstance = getFromCache("below_brightness_" + selectorType.getDescriptionId(), () -> {
|
||||||
|
return new SpawnRuleEntry(2, (type, world, spawnReason, pos, random) -> {
|
||||||
|
try {
|
||||||
|
final AABB box = new AABB(pos).inflate(side, world.getHeight(), side);
|
||||||
|
final List<?> list = world.getEntitiesOfClass(baseClass, box, (entity) -> true);
|
||||||
|
return list.size() < count;
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
rules.add(entryInstance);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will spawn entity only if count of nearby entities with same type will be lower than specified.
|
||||||
|
* @param count max entity count.
|
||||||
|
* @param side side of box to search in.
|
||||||
|
* @return same {@link SpawnRuleBulder} instance
|
||||||
|
*/
|
||||||
|
public SpawnRuleBulder maxNerby(int count, int side) {
|
||||||
|
return maxNerby(entityType, count, side);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will spawn entity only if count of nearby entities with same type will be lower than specified.
|
||||||
|
* @param count max entity count.
|
||||||
|
* @return same {@link SpawnRuleBulder} instance
|
||||||
|
*/
|
||||||
|
public SpawnRuleBulder maxNerby(int count) {
|
||||||
|
return maxNerby(entityType, count, 256);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finalize spawning rule creation.
|
||||||
|
* @param spawnType {@link Type} of spawn.
|
||||||
|
* @param heightmapType {@link Types} heightmap type.
|
||||||
|
*/
|
||||||
|
public void build(Type spawnType, Types heightmapType) {
|
||||||
|
final List<SpawnRuleEntry> rulesCopy = Lists.newArrayList(this.rules);
|
||||||
|
Collections.sort(rulesCopy);
|
||||||
|
|
||||||
|
SpawnPredicate<M> predicate = new SpawnPredicate<M>() {
|
||||||
|
@Override
|
||||||
|
public boolean test(EntityType<M> entityType, ServerLevelAccessor serverLevelAccessor, MobSpawnType mobSpawnType, BlockPos blockPos, Random random) {
|
||||||
|
for (SpawnRuleEntry rule: rulesCopy) {
|
||||||
|
if (!rule.canSpawn(entityType, serverLevelAccessor, mobSpawnType, blockPos, random)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SpawnRestrictionAccessor.callRegister(entityType, spawnType, heightmapType, predicate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finalize spawning rule creation with No Restrictions spawn type, useful for flying entities.
|
||||||
|
* @param heightmapType {@link Types} heightmap type.
|
||||||
|
*/
|
||||||
|
public void buildNoRestrictions(Types heightmapType) {
|
||||||
|
build(Type.NO_RESTRICTIONS, heightmapType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finalize spawning rule creation with On Ground spawn type, useful for common entities.
|
||||||
|
* @param heightmapType {@link Types} heightmap type.
|
||||||
|
*/
|
||||||
|
public void buildOnGround(Types heightmapType) {
|
||||||
|
build(Type.ON_GROUND, heightmapType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finalize spawning rule creation with In Water spawn type, useful for water entities.
|
||||||
|
* @param heightmapType {@link Types} heightmap type.
|
||||||
|
*/
|
||||||
|
public void buildInWater(Types heightmapType) {
|
||||||
|
build(Type.IN_WATER, heightmapType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finalize spawning rule creation with In Lava spawn type, useful for lava entities.
|
||||||
|
* @param heightmapType {@link Types} heightmap type.
|
||||||
|
*/
|
||||||
|
public void buildInLava(Types heightmapType) {
|
||||||
|
build(Type.IN_LAVA, heightmapType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal function, will take entry from cache or create it if necessary.
|
||||||
|
* @param name {@link String} entry internal name.
|
||||||
|
* @param supplier {@link Supplier} for {@link SpawnRuleEntry}.
|
||||||
|
* @return new or existing {@link SpawnRuleEntry}.
|
||||||
|
*/
|
||||||
|
private static SpawnRuleEntry getFromCache(String name, Supplier<SpawnRuleEntry> supplier) {
|
||||||
|
SpawnRuleEntry entry = RULES_CACHE.get(name);
|
||||||
|
if (entry == null) {
|
||||||
|
entry = supplier.get();
|
||||||
|
RULES_CACHE.put(name, entry);
|
||||||
|
}
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
30
src/main/java/ru/bclib/api/spawning/SpawnRuleEntry.java
Normal file
30
src/main/java/ru/bclib/api/spawning/SpawnRuleEntry.java
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
package ru.bclib.api.spawning;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.entity.Mob;
|
||||||
|
import net.minecraft.world.entity.MobSpawnType;
|
||||||
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import ru.bclib.interfaces.SpawnRule;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
public class SpawnRuleEntry<M extends Mob> implements Comparable<SpawnRuleEntry> {
|
||||||
|
private final SpawnRule rule;
|
||||||
|
private final byte priority;
|
||||||
|
|
||||||
|
public SpawnRuleEntry(int priority, SpawnRule rule) {
|
||||||
|
this.priority = (byte) priority;
|
||||||
|
this.rule = rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean canSpawn(EntityType<M> type, LevelAccessor world, MobSpawnType spawnReason, BlockPos pos, Random random) {
|
||||||
|
return rule.canSpawn(type, world, spawnReason, pos, random);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(@NotNull SpawnRuleEntry entry) {
|
||||||
|
return Integer.compare(priority, entry.priority);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,7 @@
|
||||||
package ru.bclib.api.datafixer;
|
package ru.bclib.interfaces;
|
||||||
|
|
||||||
|
import ru.bclib.api.datafixer.MigrationProfile;
|
||||||
|
import ru.bclib.api.datafixer.PatchDidiFailException;
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface PatchBiFunction<U, V, R> {
|
public interface PatchBiFunction<U, V, R> {
|
|
@ -1,4 +1,7 @@
|
||||||
package ru.bclib.api.datafixer;
|
package ru.bclib.interfaces;
|
||||||
|
|
||||||
|
import ru.bclib.api.datafixer.MigrationProfile;
|
||||||
|
import ru.bclib.api.datafixer.PatchDidiFailException;
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface PatchFunction<T, R> {
|
public interface PatchFunction<T, R> {
|
14
src/main/java/ru/bclib/interfaces/SpawnRule.java
Normal file
14
src/main/java/ru/bclib/interfaces/SpawnRule.java
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
package ru.bclib.interfaces;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.entity.Mob;
|
||||||
|
import net.minecraft.world.entity.MobSpawnType;
|
||||||
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface SpawnRule<M extends Mob> {
|
||||||
|
boolean canSpawn(EntityType<M> type, LevelAccessor world, MobSpawnType spawnReason, BlockPos pos, Random random);
|
||||||
|
}
|
|
@ -4,16 +4,16 @@
|
||||||
"package": "ru.bclib.mixin.client",
|
"package": "ru.bclib.mixin.client",
|
||||||
"compatibilityLevel": "JAVA_16",
|
"compatibilityLevel": "JAVA_16",
|
||||||
"client": [
|
"client": [
|
||||||
"SimpleReloadableResourceManagerMixin",
|
"AnvilScreenMixin",
|
||||||
"EnchantingTableBlockMixin",
|
|
||||||
"BackgroundRendererMixin",
|
"BackgroundRendererMixin",
|
||||||
"ClientRecipeBookMixin",
|
"ClientRecipeBookMixin",
|
||||||
"ModelManagerMixin",
|
"EnchantingTableBlockMixin",
|
||||||
"TextureAtlasMixin",
|
"GameMixin",
|
||||||
"AnvilScreenMixin",
|
|
||||||
"ModelBakeryMixin",
|
|
||||||
"MinecraftMixin",
|
"MinecraftMixin",
|
||||||
"GameMixin"
|
"ModelBakeryMixin",
|
||||||
|
"ModelManagerMixin",
|
||||||
|
"SimpleReloadableResourceManagerMixin",
|
||||||
|
"TextureAtlasMixin"
|
||||||
],
|
],
|
||||||
"injectors": {
|
"injectors": {
|
||||||
"defaultRequire": 1
|
"defaultRequire": 1
|
||||||
|
|
|
@ -4,35 +4,35 @@
|
||||||
"package": "ru.bclib.mixin.common",
|
"package": "ru.bclib.mixin.common",
|
||||||
"compatibilityLevel": "JAVA_16",
|
"compatibilityLevel": "JAVA_16",
|
||||||
"mixins": [
|
"mixins": [
|
||||||
"SimpleReloadableResourceManagerMixin",
|
|
||||||
"shears.DiggingEnchantmentMixin",
|
|
||||||
"LayerLightSectionStorageMixin",
|
|
||||||
"shears.TripWireBlockMixin",
|
|
||||||
"ChunkBiomeContainerMixin",
|
|
||||||
"shears.BeehiveBlockMixin",
|
|
||||||
"shears.PumpkinBlockMixin",
|
|
||||||
"shears.MushroomCowMixin",
|
|
||||||
"shears.SnowGolemMixin",
|
|
||||||
"ComposterBlockAccessor",
|
|
||||||
"InternalBiomeDataMixin",
|
|
||||||
"PotionBrewingAccessor",
|
|
||||||
"RecipeManagerAccessor",
|
|
||||||
"EnchantmentMenuMixin",
|
|
||||||
"MinecraftServerMixin",
|
|
||||||
"PistonBaseBlockMixin",
|
|
||||||
"WorldGenRegionMixin",
|
|
||||||
"DimensionTypeMixin",
|
|
||||||
"RecipeManagerMixin",
|
|
||||||
"CraftingMenuMixin",
|
|
||||||
"BoneMealItemMixin",
|
|
||||||
"shears.SheepMixin",
|
|
||||||
"PortalShapeMixin",
|
|
||||||
"ServerLevelMixin",
|
|
||||||
"AnvilBlockMixin",
|
"AnvilBlockMixin",
|
||||||
"AnvilMenuMixin",
|
"AnvilMenuMixin",
|
||||||
"TagLoaderMixin",
|
|
||||||
"BiomeMixin",
|
"BiomeMixin",
|
||||||
"MainMixin"
|
"BoneMealItemMixin",
|
||||||
|
"ChunkBiomeContainerMixin",
|
||||||
|
"ComposterBlockAccessor",
|
||||||
|
"CraftingMenuMixin",
|
||||||
|
"DimensionTypeMixin",
|
||||||
|
"EnchantmentMenuMixin",
|
||||||
|
"InternalBiomeDataMixin",
|
||||||
|
"LayerLightSectionStorageMixin",
|
||||||
|
"MainMixin",
|
||||||
|
"MinecraftServerMixin",
|
||||||
|
"PistonBaseBlockMixin",
|
||||||
|
"PortalShapeMixin",
|
||||||
|
"PotionBrewingAccessor",
|
||||||
|
"RecipeManagerAccessor",
|
||||||
|
"RecipeManagerMixin",
|
||||||
|
"ServerLevelMixin",
|
||||||
|
"SimpleReloadableResourceManagerMixin",
|
||||||
|
"TagLoaderMixin",
|
||||||
|
"WorldGenRegionMixin",
|
||||||
|
"shears.BeehiveBlockMixin",
|
||||||
|
"shears.DiggingEnchantmentMixin",
|
||||||
|
"shears.MushroomCowMixin",
|
||||||
|
"shears.PumpkinBlockMixin",
|
||||||
|
"shears.SheepMixin",
|
||||||
|
"shears.SnowGolemMixin",
|
||||||
|
"shears.TripWireBlockMixin"
|
||||||
],
|
],
|
||||||
"injectors": {
|
"injectors": {
|
||||||
"defaultRequire": 1
|
"defaultRequire": 1
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue