2025-11-24 22:52:51 +03:00

242 lines
12 KiB
Java

/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* com.mojang.logging.LogUtils
* org.jspecify.annotations.Nullable
* org.slf4j.Logger
*/
package net.minecraft.world.level;
import com.mojang.logging.LogUtils;
import java.util.Optional;
import net.minecraft.core.BlockPos;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.ProblemReporter;
import net.minecraft.util.RandomSource;
import net.minecraft.util.random.WeightedList;
import net.minecraft.world.Difficulty;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityProcessor;
import net.minecraft.world.entity.EntitySelector;
import net.minecraft.world.entity.EntitySpawnReason;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.SpawnPlacements;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.SpawnData;
import net.minecraft.world.level.entity.EntityTypeTest;
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.storage.TagValueInput;
import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.level.storage.ValueOutput;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import org.jspecify.annotations.Nullable;
import org.slf4j.Logger;
public abstract class BaseSpawner {
private static final Logger LOGGER = LogUtils.getLogger();
public static final String SPAWN_DATA_TAG = "SpawnData";
private static final int EVENT_SPAWN = 1;
private static final int DEFAULT_SPAWN_DELAY = 20;
private static final int DEFAULT_MIN_SPAWN_DELAY = 200;
private static final int DEFAULT_MAX_SPAWN_DELAY = 800;
private static final int DEFAULT_SPAWN_COUNT = 4;
private static final int DEFAULT_MAX_NEARBY_ENTITIES = 6;
private static final int DEFAULT_REQUIRED_PLAYER_RANGE = 16;
private static final int DEFAULT_SPAWN_RANGE = 4;
private int spawnDelay = 20;
private WeightedList<SpawnData> spawnPotentials = WeightedList.of();
private @Nullable SpawnData nextSpawnData;
private double spin;
private double oSpin;
private int minSpawnDelay = 200;
private int maxSpawnDelay = 800;
private int spawnCount = 4;
private @Nullable Entity displayEntity;
private int maxNearbyEntities = 6;
private int requiredPlayerRange = 16;
private int spawnRange = 4;
public void setEntityId(EntityType<?> type, @Nullable Level level, RandomSource random, BlockPos pos) {
this.getOrCreateNextSpawnData(level, random, pos).getEntityToSpawn().putString("id", BuiltInRegistries.ENTITY_TYPE.getKey(type).toString());
}
private boolean isNearPlayer(Level level, BlockPos pos) {
return level.hasNearbyAlivePlayer((double)pos.getX() + 0.5, (double)pos.getY() + 0.5, (double)pos.getZ() + 0.5, this.requiredPlayerRange);
}
public void clientTick(Level level, BlockPos pos) {
if (!this.isNearPlayer(level, pos)) {
this.oSpin = this.spin;
} else if (this.displayEntity != null) {
RandomSource random = level.getRandom();
double xP = (double)pos.getX() + random.nextDouble();
double yP = (double)pos.getY() + random.nextDouble();
double zP = (double)pos.getZ() + random.nextDouble();
level.addParticle(ParticleTypes.SMOKE, xP, yP, zP, 0.0, 0.0, 0.0);
level.addParticle(ParticleTypes.FLAME, xP, yP, zP, 0.0, 0.0, 0.0);
if (this.spawnDelay > 0) {
--this.spawnDelay;
}
this.oSpin = this.spin;
this.spin = (this.spin + (double)(1000.0f / ((float)this.spawnDelay + 200.0f))) % 360.0;
}
}
public void serverTick(ServerLevel level, BlockPos pos) {
if (!this.isNearPlayer(level, pos) || !level.isSpawnerBlockEnabled()) {
return;
}
if (this.spawnDelay == -1) {
this.delay(level, pos);
}
if (this.spawnDelay > 0) {
--this.spawnDelay;
return;
}
boolean delay = false;
RandomSource random = level.getRandom();
SpawnData nextSpawnData = this.getOrCreateNextSpawnData(level, random, pos);
for (int c = 0; c < this.spawnCount; ++c) {
try (ProblemReporter.ScopedCollector reporter = new ProblemReporter.ScopedCollector(this::toString, LOGGER);){
ValueInput input = TagValueInput.create((ProblemReporter)reporter, (HolderLookup.Provider)level.registryAccess(), nextSpawnData.getEntityToSpawn());
Optional<EntityType<?>> entityType = EntityType.by(input);
if (entityType.isEmpty()) {
this.delay(level, pos);
return;
}
Vec3 spawnPos = input.read("Pos", Vec3.CODEC).orElseGet(() -> new Vec3((double)pos.getX() + (random.nextDouble() - random.nextDouble()) * (double)this.spawnRange + 0.5, pos.getY() + random.nextInt(3) - 1, (double)pos.getZ() + (random.nextDouble() - random.nextDouble()) * (double)this.spawnRange + 0.5));
if (!level.noCollision(entityType.get().getSpawnAABB(spawnPos.x, spawnPos.y, spawnPos.z))) continue;
BlockPos spawnBlockPos = BlockPos.containing(spawnPos);
if (nextSpawnData.getCustomSpawnRules().isPresent()) {
SpawnData.CustomSpawnRules customSpawnRules;
if (!entityType.get().getCategory().isFriendly() && level.getDifficulty() == Difficulty.PEACEFUL || !(customSpawnRules = nextSpawnData.getCustomSpawnRules().get()).isValidPosition(spawnBlockPos, level)) continue;
} else if (!SpawnPlacements.checkSpawnRules(entityType.get(), level, EntitySpawnReason.SPAWNER, spawnBlockPos, level.getRandom())) continue;
Entity entity = EntityType.loadEntityRecursive(input, (Level)level, EntitySpawnReason.SPAWNER, e -> {
e.snapTo(spawnPos.x, spawnPos.y, spawnPos.z, e.getYRot(), e.getXRot());
return e;
});
if (entity == null) {
this.delay(level, pos);
return;
}
int nearBy = level.getEntities(EntityTypeTest.forExactClass(entity.getClass()), new AABB(pos.getX(), pos.getY(), pos.getZ(), pos.getX() + 1, pos.getY() + 1, pos.getZ() + 1).inflate(this.spawnRange), EntitySelector.NO_SPECTATORS).size();
if (nearBy >= this.maxNearbyEntities) {
this.delay(level, pos);
return;
}
entity.snapTo(entity.getX(), entity.getY(), entity.getZ(), random.nextFloat() * 360.0f, 0.0f);
if (entity instanceof Mob) {
boolean hasNoConfiguration;
Mob mob = (Mob)entity;
if (nextSpawnData.getCustomSpawnRules().isEmpty() && !mob.checkSpawnRules(level, EntitySpawnReason.SPAWNER) || !mob.checkSpawnObstruction(level)) continue;
boolean bl = hasNoConfiguration = nextSpawnData.getEntityToSpawn().size() == 1 && nextSpawnData.getEntityToSpawn().getString("id").isPresent();
if (hasNoConfiguration) {
((Mob)entity).finalizeSpawn(level, level.getCurrentDifficultyAt(entity.blockPosition()), EntitySpawnReason.SPAWNER, null);
}
nextSpawnData.getEquipment().ifPresent(mob::equip);
}
if (!level.tryAddFreshEntityWithPassengers(entity)) {
this.delay(level, pos);
return;
}
level.levelEvent(2004, pos, 0);
level.gameEvent(entity, GameEvent.ENTITY_PLACE, spawnBlockPos);
if (entity instanceof Mob) {
((Mob)entity).spawnAnim();
}
delay = true;
continue;
}
}
if (delay) {
this.delay(level, pos);
}
}
private void delay(Level level, BlockPos pos) {
RandomSource random = level.random;
this.spawnDelay = this.maxSpawnDelay <= this.minSpawnDelay ? this.minSpawnDelay : this.minSpawnDelay + random.nextInt(this.maxSpawnDelay - this.minSpawnDelay);
this.spawnPotentials.getRandom(random).ifPresent(entry -> this.setNextSpawnData(level, pos, (SpawnData)entry));
this.broadcastEvent(level, pos, 1);
}
public void load(@Nullable Level level, BlockPos pos, ValueInput input) {
this.spawnDelay = input.getShortOr("Delay", (short)20);
input.read(SPAWN_DATA_TAG, SpawnData.CODEC).ifPresent(nextSpawnData -> this.setNextSpawnData(level, pos, (SpawnData)nextSpawnData));
this.spawnPotentials = input.read("SpawnPotentials", SpawnData.LIST_CODEC).orElseGet(() -> WeightedList.of(this.nextSpawnData != null ? this.nextSpawnData : new SpawnData()));
this.minSpawnDelay = input.getIntOr("MinSpawnDelay", 200);
this.maxSpawnDelay = input.getIntOr("MaxSpawnDelay", 800);
this.spawnCount = input.getIntOr("SpawnCount", 4);
this.maxNearbyEntities = input.getIntOr("MaxNearbyEntities", 6);
this.requiredPlayerRange = input.getIntOr("RequiredPlayerRange", 16);
this.spawnRange = input.getIntOr("SpawnRange", 4);
this.displayEntity = null;
}
public void save(ValueOutput output) {
output.putShort("Delay", (short)this.spawnDelay);
output.putShort("MinSpawnDelay", (short)this.minSpawnDelay);
output.putShort("MaxSpawnDelay", (short)this.maxSpawnDelay);
output.putShort("SpawnCount", (short)this.spawnCount);
output.putShort("MaxNearbyEntities", (short)this.maxNearbyEntities);
output.putShort("RequiredPlayerRange", (short)this.requiredPlayerRange);
output.putShort("SpawnRange", (short)this.spawnRange);
output.storeNullable(SPAWN_DATA_TAG, SpawnData.CODEC, this.nextSpawnData);
output.store("SpawnPotentials", SpawnData.LIST_CODEC, this.spawnPotentials);
}
public @Nullable Entity getOrCreateDisplayEntity(Level level, BlockPos pos) {
if (this.displayEntity == null) {
CompoundTag entityToSpawn = this.getOrCreateNextSpawnData(level, level.getRandom(), pos).getEntityToSpawn();
if (entityToSpawn.getString("id").isEmpty()) {
return null;
}
this.displayEntity = EntityType.loadEntityRecursive(entityToSpawn, level, EntitySpawnReason.SPAWNER, EntityProcessor.NOP);
if (entityToSpawn.size() != 1 || this.displayEntity instanceof Mob) {
// empty if block
}
}
return this.displayEntity;
}
public boolean onEventTriggered(Level level, int id) {
if (id == 1) {
if (level.isClientSide()) {
this.spawnDelay = this.minSpawnDelay;
}
return true;
}
return false;
}
protected void setNextSpawnData(@Nullable Level level, BlockPos pos, SpawnData nextSpawnData) {
this.nextSpawnData = nextSpawnData;
}
private SpawnData getOrCreateNextSpawnData(@Nullable Level level, RandomSource random, BlockPos pos) {
if (this.nextSpawnData != null) {
return this.nextSpawnData;
}
this.setNextSpawnData(level, pos, this.spawnPotentials.getRandom(random).orElseGet(SpawnData::new));
return this.nextSpawnData;
}
public abstract void broadcastEvent(Level var1, BlockPos var2, int var3);
public double getSpin() {
return this.spin;
}
public double getOSpin() {
return this.oSpin;
}
}