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

155 lines
6.4 KiB
Java

/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* org.jspecify.annotations.Nullable
*/
package net.minecraft.world.entity.npc;
import java.util.Optional;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.tags.BiomeTags;
import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.EntitySpawnReason;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.SpawnPlacementType;
import net.minecraft.world.entity.SpawnPlacements;
import net.minecraft.world.entity.ai.village.poi.PoiManager;
import net.minecraft.world.entity.ai.village.poi.PoiTypes;
import net.minecraft.world.entity.animal.horse.TraderLlama;
import net.minecraft.world.entity.npc.WanderingTrader;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.CustomSpawner;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.gamerules.GameRules;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.storage.ServerLevelData;
import org.jspecify.annotations.Nullable;
public class WanderingTraderSpawner
implements CustomSpawner {
private static final int DEFAULT_TICK_DELAY = 1200;
public static final int DEFAULT_SPAWN_DELAY = 24000;
private static final int MIN_SPAWN_CHANCE = 25;
private static final int MAX_SPAWN_CHANCE = 75;
private static final int SPAWN_CHANCE_INCREASE = 25;
private static final int SPAWN_ONE_IN_X_CHANCE = 10;
private static final int NUMBER_OF_SPAWN_ATTEMPTS = 10;
private final RandomSource random = RandomSource.create();
private final ServerLevelData serverLevelData;
private int tickDelay;
private int spawnDelay;
private int spawnChance;
public WanderingTraderSpawner(ServerLevelData serverLevelData) {
this.serverLevelData = serverLevelData;
this.tickDelay = 1200;
this.spawnDelay = serverLevelData.getWanderingTraderSpawnDelay();
this.spawnChance = serverLevelData.getWanderingTraderSpawnChance();
if (this.spawnDelay == 0 && this.spawnChance == 0) {
this.spawnDelay = 24000;
serverLevelData.setWanderingTraderSpawnDelay(this.spawnDelay);
this.spawnChance = 25;
serverLevelData.setWanderingTraderSpawnChance(this.spawnChance);
}
}
@Override
public void tick(ServerLevel level, boolean spawnEnemies) {
if (!level.getGameRules().get(GameRules.SPAWN_WANDERING_TRADERS).booleanValue()) {
return;
}
if (--this.tickDelay > 0) {
return;
}
this.tickDelay = 1200;
this.spawnDelay -= 1200;
this.serverLevelData.setWanderingTraderSpawnDelay(this.spawnDelay);
if (this.spawnDelay > 0) {
return;
}
this.spawnDelay = 24000;
int chanceToSpawn = this.spawnChance;
this.spawnChance = Mth.clamp(this.spawnChance + 25, 25, 75);
this.serverLevelData.setWanderingTraderSpawnChance(this.spawnChance);
if (this.random.nextInt(100) > chanceToSpawn) {
return;
}
if (this.spawn(level)) {
this.spawnChance = 25;
}
}
private boolean spawn(ServerLevel level) {
ServerPlayer player = level.getRandomPlayer();
if (player == null) {
return true;
}
if (this.random.nextInt(10) != 0) {
return false;
}
BlockPos playerPos = player.blockPosition();
int radius = 48;
PoiManager poiManager = level.getPoiManager();
Optional<BlockPos> poiPos = poiManager.find(p -> p.is(PoiTypes.MEETING), p -> true, playerPos, 48, PoiManager.Occupancy.ANY);
BlockPos referencePos = poiPos.orElse(playerPos);
BlockPos spawnPosition = this.findSpawnPositionNear(level, referencePos, 48);
if (spawnPosition != null && this.hasEnoughSpace(level, spawnPosition)) {
if (level.getBiome(spawnPosition).is(BiomeTags.WITHOUT_WANDERING_TRADER_SPAWNS)) {
return false;
}
WanderingTrader trader = EntityType.WANDERING_TRADER.spawn(level, spawnPosition, EntitySpawnReason.EVENT);
if (trader != null) {
for (int i = 0; i < 2; ++i) {
this.tryToSpawnLlamaFor(level, trader, 4);
}
this.serverLevelData.setWanderingTraderId(trader.getUUID());
trader.setDespawnDelay(48000);
trader.setWanderTarget(referencePos);
trader.setHomeTo(referencePos, 16);
return true;
}
}
return false;
}
private void tryToSpawnLlamaFor(ServerLevel level, WanderingTrader trader, int radius) {
BlockPos spawnPosition = this.findSpawnPositionNear(level, trader.blockPosition(), radius);
if (spawnPosition == null) {
return;
}
TraderLlama llama = EntityType.TRADER_LLAMA.spawn(level, spawnPosition, EntitySpawnReason.EVENT);
if (llama == null) {
return;
}
llama.setLeashedTo(trader, true);
}
private @Nullable BlockPos findSpawnPositionNear(LevelReader level, BlockPos referencePosition, int radius) {
BlockPos spawnPosition = null;
SpawnPlacementType wanderingTraderSpawnType = SpawnPlacements.getPlacementType(EntityType.WANDERING_TRADER);
for (int i = 0; i < 10; ++i) {
int zPosition;
int yPosition;
int xPosition = referencePosition.getX() + this.random.nextInt(radius * 2) - radius;
BlockPos spawnPos = new BlockPos(xPosition, yPosition = level.getHeight(Heightmap.Types.WORLD_SURFACE, xPosition, zPosition = referencePosition.getZ() + this.random.nextInt(radius * 2) - radius), zPosition);
if (!wanderingTraderSpawnType.isSpawnPositionOk(level, spawnPos, EntityType.WANDERING_TRADER)) continue;
spawnPosition = spawnPos;
break;
}
return spawnPosition;
}
private boolean hasEnoughSpace(BlockGetter level, BlockPos spawnPos) {
for (BlockPos pos : BlockPos.betweenClosed(spawnPos, spawnPos.offset(1, 2, 1))) {
if (level.getBlockState(pos).getCollisionShape(level, pos).isEmpty()) continue;
return false;
}
return true;
}
}