#1354: Improve spawner API and add API for Trial Spawners

By: coll1234567 <joshl5324@gmail.com>
This commit is contained in:
CraftBukkit/Spigot 2024-06-28 07:06:20 +10:00
parent c59410cfbc
commit 820bc6423d
5 changed files with 677 additions and 12 deletions

View file

@ -1,5 +1,27 @@
--- a/net/minecraft/world/level/block/entity/trialspawner/TrialSpawner.java
+++ b/net/minecraft/world/level/block/entity/trialspawner/TrialSpawner.java
@@ -57,16 +57,16 @@
private static final int MAX_MOB_TRACKING_DISTANCE = 47;
private static final int MAX_MOB_TRACKING_DISTANCE_SQR = MathHelper.square(47);
private static final float SPAWNING_AMBIENT_SOUND_CHANCE = 0.02F;
- private final TrialSpawnerConfig normalConfig;
- private final TrialSpawnerConfig ominousConfig;
+ public TrialSpawnerConfig normalConfig; // PAIL - private->public, -final
+ public TrialSpawnerConfig ominousConfig; // PAIL - private->public, -final
private final TrialSpawnerData data;
- private final int requiredPlayerRange;
- private final int targetCooldownLength;
+ public int requiredPlayerRange; // PAIL - private->public, -final
+ public int targetCooldownLength; // PAIL - private->public, -final
public final TrialSpawner.b stateAccessor;
private PlayerDetector playerDetector;
private final PlayerDetector.a entitySelector;
private boolean overridePeacefulAndMobSpawnRule;
- private boolean isOminous;
+ public boolean isOminous; // PAIL - private->public
public Codec<TrialSpawner> codec() {
return RecordCodecBuilder.create((instance) -> {
@@ -219,13 +219,13 @@
}

View file

@ -15,6 +15,7 @@ import net.minecraft.util.random.SimpleWeightedRandomList;
import net.minecraft.util.random.WeightedEntry.b;
import net.minecraft.world.entity.EntityTypes;
import net.minecraft.world.entity.EquipmentTable;
import net.minecraft.world.level.MobSpawnerAbstract;
import net.minecraft.world.level.MobSpawnerData;
import net.minecraft.world.level.block.entity.TileEntityMobSpawner;
import org.bukkit.Location;
@ -75,60 +76,94 @@ public class CraftCreatureSpawner extends CraftBlockEntityState<TileEntityMobSpa
@Override
public void setSpawnedEntity(EntitySnapshot snapshot) {
setSpawnedEntity(this.getSnapshot().getSpawner(), snapshot, null, null);
}
@Override
public void setSpawnedEntity(SpawnerEntry spawnerEntry) {
Preconditions.checkArgument(spawnerEntry != null, "Entry cannot be null");
setSpawnedEntity(this.getSnapshot().getSpawner(), spawnerEntry.getSnapshot(), spawnerEntry.getSpawnRule(), spawnerEntry.getEquipment());
}
public static void setSpawnedEntity(MobSpawnerAbstract spawner, EntitySnapshot snapshot, SpawnRule spawnRule, SpawnerEntry.Equipment equipment) {
spawner.spawnPotentials = SimpleWeightedRandomList.empty(); // need clear the spawnPotentials to avoid nextSpawnData being replaced later
if (snapshot == null) {
spawner.nextSpawnData = new MobSpawnerData();
return;
}
NBTTagCompound compoundTag = ((CraftEntitySnapshot) snapshot).getData();
this.getSnapshot().getSpawner().spawnPotentials = SimpleWeightedRandomList.empty();
this.getSnapshot().getSpawner().nextSpawnData = new MobSpawnerData(compoundTag, Optional.empty(), Optional.empty());
spawner.nextSpawnData = new MobSpawnerData(compoundTag, Optional.ofNullable(toMinecraftRule(spawnRule)), getEquipment(equipment));
}
@Override
public void addPotentialSpawn(EntitySnapshot snapshot, int weight, SpawnRule spawnRule) {
addPotentialSpawn(this.getSnapshot().getSpawner(), snapshot, weight, spawnRule, null);
}
public static void addPotentialSpawn(MobSpawnerAbstract spawner, EntitySnapshot snapshot, int weight, SpawnRule spawnRule, SpawnerEntry.Equipment equipment) {
Preconditions.checkArgument(snapshot != null, "Snapshot cannot be null");
NBTTagCompound compoundTag = ((CraftEntitySnapshot) snapshot).getData();
SimpleWeightedRandomList.a<MobSpawnerData> builder = SimpleWeightedRandomList.builder(); // PAIL rename Builder
this.getSnapshot().getSpawner().spawnPotentials.unwrap().forEach(entry -> builder.add(entry.data(), entry.getWeight().asInt()));
builder.add(new MobSpawnerData(compoundTag, Optional.ofNullable(toMinecraftRule(spawnRule)), Optional.empty()), weight);
this.getSnapshot().getSpawner().spawnPotentials = builder.build();
spawner.spawnPotentials.unwrap().forEach(entry -> builder.add(entry.data(), entry.getWeight().asInt()));
builder.add(new MobSpawnerData(compoundTag, Optional.ofNullable(toMinecraftRule(spawnRule)), getEquipment(equipment)), weight);
spawner.spawnPotentials = builder.build();
}
@Override
public void addPotentialSpawn(SpawnerEntry spawnerEntry) {
Preconditions.checkArgument(spawnerEntry != null, "Entry cannot be null");
addPotentialSpawn(spawnerEntry.getSnapshot(), spawnerEntry.getSpawnWeight(), spawnerEntry.getSpawnRule());
}
@Override
public void setPotentialSpawns(Collection<SpawnerEntry> entries) {
setPotentialSpawns(this.getSnapshot().getSpawner(), entries);
}
public static void setPotentialSpawns(MobSpawnerAbstract spawner, Collection<SpawnerEntry> entries) {
Preconditions.checkArgument(entries != null, "Entries cannot be null");
SimpleWeightedRandomList.a<MobSpawnerData> builder = SimpleWeightedRandomList.builder();
for (SpawnerEntry spawnerEntry : entries) {
NBTTagCompound compoundTag = ((CraftEntitySnapshot) spawnerEntry.getSnapshot()).getData();
builder.add(new MobSpawnerData(compoundTag, Optional.ofNullable(toMinecraftRule(spawnerEntry.getSpawnRule())), getEquipment(spawnerEntry.getEquipment())), spawnerEntry.getSpawnWeight());
}
this.getSnapshot().getSpawner().spawnPotentials = builder.build();
spawner.spawnPotentials = builder.build();
}
@Override
public List<SpawnerEntry> getPotentialSpawns() {
return getPotentialSpawns(this.getSnapshot().getSpawner());
}
public static List<SpawnerEntry> getPotentialSpawns(MobSpawnerAbstract spawner) {
List<SpawnerEntry> entries = new ArrayList<>();
for (b<MobSpawnerData> entry : this.getSnapshot().getSpawner().spawnPotentials.unwrap()) { // PAIL rename Wrapper
for (b<MobSpawnerData> entry : spawner.spawnPotentials.unwrap()) { // PAIL rename Wrapper
CraftEntitySnapshot snapshot = CraftEntitySnapshot.create(entry.data().getEntityToSpawn());
if (snapshot != null) {
SpawnRule rule = entry.data().customSpawnRules().map(this::fromMinecraftRule).orElse(null);
SpawnRule rule = entry.data().customSpawnRules().map(CraftCreatureSpawner::fromMinecraftRule).orElse(null);
entries.add(new SpawnerEntry(snapshot, entry.getWeight().asInt(), rule, getEquipment(entry.data().equipment())));
}
}
return entries;
}
private MobSpawnerData.a toMinecraftRule(SpawnRule rule) { // PAIL rename CustomSpawnRules
public static MobSpawnerData.a toMinecraftRule(SpawnRule rule) { // PAIL rename CustomSpawnRules
if (rule == null) {
return null;
}
return new MobSpawnerData.a(new InclusiveRange<>(rule.getMinBlockLight(), rule.getMaxBlockLight()), new InclusiveRange<>(rule.getMinSkyLight(), rule.getMaxSkyLight()));
}
private SpawnRule fromMinecraftRule(MobSpawnerData.a rule) {
public static SpawnRule fromMinecraftRule(MobSpawnerData.a rule) {
InclusiveRange<Integer> blockLight = rule.blockLightLimit();
InclusiveRange<Integer> skyLight = rule.skyLightLimit();
@ -240,7 +275,7 @@ public class CraftCreatureSpawner extends CraftBlockEntityState<TileEntityMobSpa
return new CraftCreatureSpawner(this, location);
}
private static Optional<EquipmentTable> getEquipment(SpawnerEntry.Equipment bukkit) {
public static Optional<EquipmentTable> getEquipment(SpawnerEntry.Equipment bukkit) {
if (bukkit == null) {
return Optional.empty();
}
@ -251,7 +286,7 @@ public class CraftCreatureSpawner extends CraftBlockEntityState<TileEntityMobSpa
);
}
private static SpawnerEntry.Equipment getEquipment(Optional<EquipmentTable> optional) {
public static SpawnerEntry.Equipment getEquipment(Optional<EquipmentTable> optional) {
return optional.map((nms) -> new SpawnerEntry.Equipment(
CraftLootTable.minecraftToBukkit(nms.lootTable()),
new HashMap<>(nms.slotDropChances().entrySet().stream().collect(Collectors.toMap((entry) -> CraftEquipmentSlot.getSlot(entry.getKey()), Map.Entry::getValue)))

View file

@ -1,18 +1,162 @@
package org.bukkit.craftbukkit.block;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import java.util.Collection;
import java.util.UUID;
import net.minecraft.world.level.block.TrialSpawnerBlock;
import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity;
import net.minecraft.world.level.block.entity.trialspawner.TrialSpawnerData;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.TrialSpawner;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.spawner.TrialSpawnerConfiguration;
public class CraftTrialSpawner extends CraftBlockEntityState<TrialSpawnerBlockEntity> implements TrialSpawner {
private final CraftTrialSpawnerConfiguration normalConfig;
private final CraftTrialSpawnerConfiguration ominousConfig;
public CraftTrialSpawner(World world, TrialSpawnerBlockEntity tileEntity) {
super(world, tileEntity);
this.normalConfig = new CraftTrialSpawnerConfiguration(tileEntity.getTrialSpawner().getNormalConfig(), getSnapshot());
this.ominousConfig = new CraftTrialSpawnerConfiguration(tileEntity.getTrialSpawner().getOminousConfig(), getSnapshot());
}
protected CraftTrialSpawner(CraftTrialSpawner state, Location location) {
super(state, location);
this.normalConfig = state.normalConfig;
this.ominousConfig = state.ominousConfig;
}
@Override
public int getCooldownLength() {
return getSnapshot().trialSpawner.getTargetCooldownLength();
}
@Override
public void setCooldownLength(int ticks) {
getSnapshot().trialSpawner.targetCooldownLength = ticks;
}
@Override
public int getRequiredPlayerRange() {
return getSnapshot().trialSpawner.getRequiredPlayerRange();
}
@Override
public void setRequiredPlayerRange(int requiredPlayerRange) {
getSnapshot().trialSpawner.requiredPlayerRange = requiredPlayerRange;
}
@Override
public Collection<Player> getTrackedPlayers() {
ImmutableSet.Builder<Player> players = ImmutableSet.builder();
for (UUID uuid : getTrialData().detectedPlayers) {
Player player = Bukkit.getPlayer(uuid);
if (player != null) {
players.add(player);
}
}
return players.build();
}
@Override
public boolean isTrackingPlayer(Player player) {
Preconditions.checkArgument(player != null, "Player cannot be null");
return getTrialData().detectedPlayers.contains(player.getUniqueId());
}
@Override
public void startTrackingPlayer(Player player) {
Preconditions.checkArgument(player != null, "Player cannot be null");
getTrialData().detectedPlayers.add(player.getUniqueId());
}
@Override
public void stopTrackingPlayer(Player player) {
Preconditions.checkArgument(player != null, "Player cannot be null");
getTrialData().detectedPlayers.remove(player.getUniqueId());
}
@Override
public Collection<Entity> getTrackedEntities() {
ImmutableSet.Builder<Entity> entities = ImmutableSet.builder();
for (UUID uuid : getTrialData().currentMobs) {
Entity entity = Bukkit.getEntity(uuid);
if (entity != null) {
entities.add(entity);
}
}
return entities.build();
}
@Override
public boolean isTrackingEntity(Entity entity) {
Preconditions.checkArgument(entity != null, "Entity cannot be null");
return getTrialData().currentMobs.contains(entity.getUniqueId());
}
@Override
public void startTrackingEntity(Entity entity) {
Preconditions.checkArgument(entity != null, "Entity cannot be null");
getTrialData().currentMobs.add(entity.getUniqueId());
}
@Override
public void stopTrackingEntity(Entity entity) {
Preconditions.checkArgument(entity != null, "Entity cannot be null");
getTrialData().currentMobs.remove(entity.getUniqueId());
}
@Override
public boolean isOminous() {
return getHandle().getValue(TrialSpawnerBlock.OMINOUS);
}
@Override
public void setOminous(boolean ominous) {
getSnapshot().trialSpawner.isOminous = ominous;
if (ominous) {
setData(getHandle().setValue(TrialSpawnerBlock.OMINOUS, true));
// TODO: Consider calling TrialSpawnerData#resetAfterBecomingOminous in update(...), but note that method also removes entities
return;
}
setData(getHandle().setValue(TrialSpawnerBlock.OMINOUS, false));
}
@Override
public TrialSpawnerConfiguration getNormalConfiguration() {
return normalConfig;
}
@Override
public TrialSpawnerConfiguration getOminousConfiguration() {
return ominousConfig;
}
@Override
protected void applyTo(TrialSpawnerBlockEntity tileEntity) {
super.applyTo(tileEntity);
tileEntity.trialSpawner.normalConfig = normalConfig.toMinecraft();
tileEntity.trialSpawner.ominousConfig = ominousConfig.toMinecraft();
}
private TrialSpawnerData getTrialData() {
return getSnapshot().getTrialSpawner().getData();
}
@Override

View file

@ -0,0 +1,305 @@
package org.bukkit.craftbukkit.block;
import com.google.common.base.Preconditions;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.resources.ResourceKey;
import net.minecraft.util.random.SimpleWeightedRandomList;
import net.minecraft.util.random.WeightedEntry.b;
import net.minecraft.world.entity.EntityTypes;
import net.minecraft.world.level.MobSpawnerData;
import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity;
import net.minecraft.world.level.block.entity.trialspawner.TrialSpawnerConfig;
import net.minecraft.world.level.block.entity.trialspawner.TrialSpawnerData;
import org.bukkit.block.spawner.SpawnRule;
import org.bukkit.block.spawner.SpawnerEntry;
import org.bukkit.craftbukkit.CraftLootTable;
import org.bukkit.craftbukkit.entity.CraftEntitySnapshot;
import org.bukkit.craftbukkit.entity.CraftEntityType;
import org.bukkit.entity.EntitySnapshot;
import org.bukkit.entity.EntityType;
import org.bukkit.loot.LootTable;
import org.bukkit.spawner.TrialSpawnerConfiguration;
public class CraftTrialSpawnerConfiguration implements TrialSpawnerConfiguration {
private final TrialSpawnerBlockEntity snapshot;
private int spawnRange;
private float totalMobs;
private float simultaneousMobs;
private float totalMobsAddedPerPlayer;
private float simultaneousMobsAddedPerPlayer;
private int ticksBetweenSpawn;
private SimpleWeightedRandomList<MobSpawnerData> spawnPotentialsDefinition;
private SimpleWeightedRandomList<ResourceKey<net.minecraft.world.level.storage.loot.LootTable>> lootTablesToEject;
private ResourceKey<net.minecraft.world.level.storage.loot.LootTable> itemsToDropWhenOminous;
public CraftTrialSpawnerConfiguration(TrialSpawnerConfig minecraft, TrialSpawnerBlockEntity snapshot) {
this.snapshot = snapshot;
this.spawnRange = minecraft.spawnRange();
this.totalMobs = minecraft.totalMobs();
this.simultaneousMobs = minecraft.simultaneousMobs();
this.totalMobsAddedPerPlayer = minecraft.totalMobsAddedPerPlayer();
this.simultaneousMobsAddedPerPlayer = minecraft.simultaneousMobsAddedPerPlayer();
this.ticksBetweenSpawn = minecraft.ticksBetweenSpawn();
this.spawnPotentialsDefinition = minecraft.spawnPotentialsDefinition();
this.lootTablesToEject = minecraft.lootTablesToEject();
this.itemsToDropWhenOminous = minecraft.itemsToDropWhenOminous();
}
@Override
public EntityType getSpawnedType() {
if (spawnPotentialsDefinition.isEmpty()) {
return null;
}
Optional<EntityTypes<?>> type = EntityTypes.by(spawnPotentialsDefinition.unwrap().get(0).data().getEntityToSpawn());
return type.map(CraftEntityType::minecraftToBukkit).orElse(null);
}
@Override
public void setSpawnedType(EntityType entityType) {
if (entityType == null) {
getTrialData().nextSpawnData = Optional.empty();
spawnPotentialsDefinition = SimpleWeightedRandomList.empty(); // need clear the spawnPotentials to avoid nextSpawnData being replaced later
return;
}
Preconditions.checkArgument(entityType != EntityType.UNKNOWN, "Can't spawn EntityType %s from mob spawners!", entityType);
MobSpawnerData data = new MobSpawnerData();
data.getEntityToSpawn().putString("id", BuiltInRegistries.ENTITY_TYPE.getKey(CraftEntityType.bukkitToMinecraft(entityType)).toString());
getTrialData().nextSpawnData = Optional.of(data);
spawnPotentialsDefinition = SimpleWeightedRandomList.single(data);
}
@Override
public float getBaseSpawnsBeforeCooldown() {
return totalMobs;
}
@Override
public void setBaseSpawnsBeforeCooldown(float amount) {
totalMobs = amount;
}
@Override
public float getBaseSimultaneousEntities() {
return simultaneousMobs;
}
@Override
public void setBaseSimultaneousEntities(float amount) {
simultaneousMobs = amount;
}
@Override
public float getAdditionalSpawnsBeforeCooldown() {
return totalMobsAddedPerPlayer;
}
@Override
public void setAdditionalSpawnsBeforeCooldown(float amount) {
totalMobsAddedPerPlayer = amount;
}
@Override
public float getAdditionalSimultaneousEntities() {
return simultaneousMobsAddedPerPlayer;
}
@Override
public void setAdditionalSimultaneousEntities(float amount) {
simultaneousMobsAddedPerPlayer = amount;
}
@Override
public int getDelay() {
return ticksBetweenSpawn;
}
@Override
public void setDelay(int delay) {
Preconditions.checkArgument(delay >= 0, "Delay cannot be less than 0");
ticksBetweenSpawn = delay;
}
@Override
public int getSpawnRange() {
return spawnRange;
}
@Override
public void setSpawnRange(int spawnRange) {
this.spawnRange = spawnRange;
}
@Override
public EntitySnapshot getSpawnedEntity() {
SimpleWeightedRandomList<MobSpawnerData> potentials = spawnPotentialsDefinition;
if (potentials.isEmpty()) {
return null;
}
return CraftEntitySnapshot.create(potentials.unwrap().get(0).data().getEntityToSpawn());
}
@Override
public void setSpawnedEntity(EntitySnapshot snapshot) {
setSpawnedEntity(snapshot, null, null);
}
@Override
public void setSpawnedEntity(SpawnerEntry spawnerEntry) {
Preconditions.checkArgument(spawnerEntry != null, "Entry cannot be null");
setSpawnedEntity(spawnerEntry.getSnapshot(), spawnerEntry.getSpawnRule(), spawnerEntry.getEquipment());
}
private void setSpawnedEntity(EntitySnapshot snapshot, SpawnRule spawnRule, SpawnerEntry.Equipment equipment) {
if (snapshot == null) {
getTrialData().nextSpawnData = Optional.empty();
spawnPotentialsDefinition = SimpleWeightedRandomList.empty(); // need clear the spawnPotentials to avoid nextSpawnData being replaced later
return;
}
NBTTagCompound compoundTag = ((CraftEntitySnapshot) snapshot).getData();
MobSpawnerData data = new MobSpawnerData(compoundTag, Optional.ofNullable(CraftCreatureSpawner.toMinecraftRule(spawnRule)), CraftCreatureSpawner.getEquipment(equipment));
getTrialData().nextSpawnData = Optional.of(data);
spawnPotentialsDefinition = SimpleWeightedRandomList.single(data);
}
@Override
public void addPotentialSpawn(EntitySnapshot snapshot, int weight, SpawnRule spawnRule) {
addPotentialSpawn(snapshot, weight, spawnRule, null);
}
private void addPotentialSpawn(EntitySnapshot snapshot, int weight, SpawnRule spawnRule, SpawnerEntry.Equipment equipment) {
Preconditions.checkArgument(snapshot != null, "Snapshot cannot be null");
NBTTagCompound compoundTag = ((CraftEntitySnapshot) snapshot).getData();
SimpleWeightedRandomList.a<MobSpawnerData> builder = SimpleWeightedRandomList.builder(); // PAIL rename Builder
spawnPotentialsDefinition.unwrap().forEach(entry -> builder.add(entry.data(), entry.getWeight().asInt()));
builder.add(new MobSpawnerData(compoundTag, Optional.ofNullable(CraftCreatureSpawner.toMinecraftRule(spawnRule)), CraftCreatureSpawner.getEquipment(equipment)), weight);
spawnPotentialsDefinition = builder.build();
}
@Override
public void addPotentialSpawn(SpawnerEntry spawnerEntry) {
Preconditions.checkArgument(spawnerEntry != null, "Entry cannot be null");
addPotentialSpawn(spawnerEntry.getSnapshot(), spawnerEntry.getSpawnWeight(), spawnerEntry.getSpawnRule(), spawnerEntry.getEquipment());
}
@Override
public void setPotentialSpawns(Collection<SpawnerEntry> entries) {
Preconditions.checkArgument(entries != null, "Entries cannot be null");
SimpleWeightedRandomList.a<MobSpawnerData> builder = SimpleWeightedRandomList.builder();
for (SpawnerEntry spawnerEntry : entries) {
NBTTagCompound compoundTag = ((CraftEntitySnapshot) spawnerEntry.getSnapshot()).getData();
builder.add(new MobSpawnerData(compoundTag, Optional.ofNullable(CraftCreatureSpawner.toMinecraftRule(spawnerEntry.getSpawnRule())), CraftCreatureSpawner.getEquipment(spawnerEntry.getEquipment())), spawnerEntry.getSpawnWeight());
}
spawnPotentialsDefinition = builder.build();
}
@Override
public List<SpawnerEntry> getPotentialSpawns() {
List<SpawnerEntry> entries = new ArrayList<>();
for (b<MobSpawnerData> entry : spawnPotentialsDefinition.unwrap()) { // PAIL rename Wrapper
CraftEntitySnapshot snapshot = CraftEntitySnapshot.create(entry.data().getEntityToSpawn());
if (snapshot != null) {
SpawnRule rule = entry.data().customSpawnRules().map(CraftCreatureSpawner::fromMinecraftRule).orElse(null);
entries.add(new SpawnerEntry(snapshot, entry.getWeight().asInt(), rule));
}
}
return entries;
}
@Override
public Map<LootTable, Integer> getPossibleRewards() {
Map<LootTable, Integer> tables = new HashMap<>();
for (b<ResourceKey<net.minecraft.world.level.storage.loot.LootTable>> entry : lootTablesToEject.unwrap()) {
LootTable table = CraftLootTable.minecraftToBukkit(entry.data());
if (table != null) {
tables.put(table, entry.getWeight().asInt());
}
}
return tables;
}
@Override
public void addPossibleReward(LootTable table, int weight) {
Preconditions.checkArgument(table != null, "Table cannot be null");
Preconditions.checkArgument(weight >= 1, "Weight must be at least 1");
SimpleWeightedRandomList.a<ResourceKey<net.minecraft.world.level.storage.loot.LootTable>> builder = SimpleWeightedRandomList.builder();
lootTablesToEject.unwrap().forEach(entry -> builder.add(entry.data(), entry.getWeight().asInt()));
builder.add(CraftLootTable.bukkitToMinecraft(table), weight);
lootTablesToEject = builder.build();
}
@Override
public void removePossibleReward(LootTable table) {
Preconditions.checkArgument(table != null, "Key cannot be null");
ResourceKey<net.minecraft.world.level.storage.loot.LootTable> minecraftKey = CraftLootTable.bukkitToMinecraft(table);
SimpleWeightedRandomList.a<ResourceKey<net.minecraft.world.level.storage.loot.LootTable>> builder = SimpleWeightedRandomList.builder();
for (b<ResourceKey<net.minecraft.world.level.storage.loot.LootTable>> entry : lootTablesToEject.unwrap()) {
if (!entry.data().equals(minecraftKey)) {
builder.add(entry.data(), entry.getWeight().asInt());
}
}
lootTablesToEject = builder.build();
}
@Override
public void setPossibleRewards(Map<LootTable, Integer> rewards) {
if (rewards == null || rewards.isEmpty()) {
lootTablesToEject = SimpleWeightedRandomList.empty();
return;
}
SimpleWeightedRandomList.a<ResourceKey<net.minecraft.world.level.storage.loot.LootTable>> builder = SimpleWeightedRandomList.builder();
rewards.forEach((table, weight) -> {
Preconditions.checkArgument(table != null, "Table cannot be null");
Preconditions.checkArgument(weight >= 1, "Weight must be at least 1");
builder.add(CraftLootTable.bukkitToMinecraft(table), weight);
});
lootTablesToEject = builder.build();
}
@Override
public int getRequiredPlayerRange() {
return snapshot.trialSpawner.getRequiredPlayerRange();
}
@Override
public void setRequiredPlayerRange(int requiredPlayerRange) {
snapshot.trialSpawner.requiredPlayerRange = requiredPlayerRange;
}
private TrialSpawnerData getTrialData() {
return snapshot.getTrialSpawner().getData();
}
protected TrialSpawnerConfig toMinecraft() {
return new TrialSpawnerConfig(spawnRange, totalMobs, simultaneousMobs, totalMobsAddedPerPlayer, simultaneousMobsAddedPerPlayer, ticksBetweenSpawn, spawnPotentialsDefinition, lootTablesToEject, itemsToDropWhenOminous);
}
}

View file

@ -1,7 +1,20 @@
package org.bukkit.craftbukkit.entity;
import com.google.common.base.Preconditions;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import net.minecraft.util.RandomSource;
import net.minecraft.util.random.SimpleWeightedRandomList;
import net.minecraft.world.entity.EntityTypes;
import net.minecraft.world.entity.vehicle.EntityMinecartMobSpawner;
import net.minecraft.world.level.MobSpawnerData;
import org.bukkit.block.spawner.SpawnRule;
import org.bukkit.block.spawner.SpawnerEntry;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.block.CraftCreatureSpawner;
import org.bukkit.entity.EntitySnapshot;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.minecart.SpawnerMinecart;
final class CraftMinecartMobSpawner extends CraftMinecart implements SpawnerMinecart {
@ -9,6 +22,152 @@ final class CraftMinecartMobSpawner extends CraftMinecart implements SpawnerMine
super(server, entity);
}
@Override
public EntityType getSpawnedType() {
MobSpawnerData spawnData = getHandle().getSpawner().nextSpawnData;
if (spawnData == null) {
return null;
}
Optional<EntityTypes<?>> type = EntityTypes.by(spawnData.getEntityToSpawn());
return type.map(CraftEntityType::minecraftToBukkit).orElse(null);
}
@Override
public void setSpawnedType(EntityType entityType) {
if (entityType == null) {
getHandle().getSpawner().spawnPotentials = SimpleWeightedRandomList.empty(); // need clear the spawnPotentials to avoid nextSpawnData being replaced later
getHandle().getSpawner().nextSpawnData = new MobSpawnerData();
return;
}
Preconditions.checkArgument(entityType != EntityType.UNKNOWN, "Can't spawn EntityType %s from mob spawners!", entityType);
RandomSource rand = getHandle().level().getRandom();
getHandle().getSpawner().setEntityId(CraftEntityType.bukkitToMinecraft(entityType), getHandle().level(), rand, getHandle().blockPosition());
}
@Override
public EntitySnapshot getSpawnedEntity() {
MobSpawnerData spawnData = getHandle().getSpawner().nextSpawnData;
if (spawnData == null) {
return null;
}
return CraftEntitySnapshot.create(spawnData.getEntityToSpawn());
}
@Override
public void setSpawnedEntity(EntitySnapshot snapshot) {
CraftCreatureSpawner.setSpawnedEntity(getHandle().getSpawner(), snapshot, null, null);
}
@Override
public void setSpawnedEntity(SpawnerEntry spawnerEntry) {
Preconditions.checkArgument(spawnerEntry != null, "Entry cannot be null");
CraftCreatureSpawner.setSpawnedEntity(getHandle().getSpawner(), spawnerEntry.getSnapshot(), spawnerEntry.getSpawnRule(), spawnerEntry.getEquipment());
}
@Override
public void addPotentialSpawn(EntitySnapshot snapshot, int weight, SpawnRule spawnRule) {
CraftCreatureSpawner.addPotentialSpawn(getHandle().getSpawner(), snapshot, weight, spawnRule, null);
}
@Override
public void addPotentialSpawn(SpawnerEntry spawnerEntry) {
Preconditions.checkArgument(spawnerEntry != null, "Entry cannot be null");
CraftCreatureSpawner.addPotentialSpawn(getHandle().getSpawner(), spawnerEntry.getSnapshot(), spawnerEntry.getSpawnWeight(), spawnerEntry.getSpawnRule(), spawnerEntry.getEquipment());
}
@Override
public void setPotentialSpawns(Collection<SpawnerEntry> entries) {
CraftCreatureSpawner.setPotentialSpawns(getHandle().getSpawner(), entries);
}
@Override
public List<SpawnerEntry> getPotentialSpawns() {
return CraftCreatureSpawner.getPotentialSpawns(getHandle().getSpawner());
}
@Override
public int getDelay() {
return getHandle().getSpawner().spawnDelay;
}
@Override
public void setDelay(int delay) {
getHandle().getSpawner().spawnDelay = delay;
}
@Override
public int getMinSpawnDelay() {
return getHandle().getSpawner().minSpawnDelay;
}
@Override
public void setMinSpawnDelay(int spawnDelay) {
Preconditions.checkArgument(spawnDelay <= getMaxSpawnDelay(), "Minimum Spawn Delay must be less than or equal to Maximum Spawn Delay");
getHandle().getSpawner().minSpawnDelay = spawnDelay;
}
@Override
public int getMaxSpawnDelay() {
return getHandle().getSpawner().maxSpawnDelay;
}
@Override
public void setMaxSpawnDelay(int spawnDelay) {
Preconditions.checkArgument(spawnDelay > 0, "Maximum Spawn Delay must be greater than 0.");
Preconditions.checkArgument(spawnDelay >= getMinSpawnDelay(), "Maximum Spawn Delay must be greater than or equal to Minimum Spawn Delay");
getHandle().getSpawner().maxSpawnDelay = spawnDelay;
}
@Override
public int getMaxNearbyEntities() {
return getHandle().getSpawner().maxNearbyEntities;
}
@Override
public void setMaxNearbyEntities(int maxNearbyEntities) {
getHandle().getSpawner().maxNearbyEntities = maxNearbyEntities;
}
@Override
public int getSpawnCount() {
return getHandle().getSpawner().spawnCount;
}
@Override
public void setSpawnCount(int count) {
getHandle().getSpawner().spawnCount = count;
}
@Override
public int getRequiredPlayerRange() {
return getHandle().getSpawner().requiredPlayerRange;
}
@Override
public void setRequiredPlayerRange(int requiredPlayerRange) {
getHandle().getSpawner().requiredPlayerRange = requiredPlayerRange;
}
@Override
public int getSpawnRange() {
return getHandle().getSpawner().spawnRange;
}
@Override
public void setSpawnRange(int spawnRange) {
getHandle().getSpawner().spawnRange = spawnRange;
}
@Override
public EntityMinecartMobSpawner getHandle() {
return (EntityMinecartMobSpawner) entity;
}
@Override
public String toString() {
return "CraftMinecartMobSpawner";