150 lines
		
	
	
	
		
			5.6 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			150 lines
		
	
	
	
		
			5.6 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package net.minecraft.world.entity.npc;
 | |
| 
 | |
| import java.util.Optional;
 | |
| import net.minecraft.core.BlockPos;
 | |
| import net.minecraft.server.level.ServerLevel;
 | |
| 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.player.Player;
 | |
| import net.minecraft.world.level.BlockGetter;
 | |
| import net.minecraft.world.level.CustomSpawner;
 | |
| import net.minecraft.world.level.GameRules;
 | |
| import net.minecraft.world.level.LevelReader;
 | |
| import net.minecraft.world.level.levelgen.Heightmap;
 | |
| import net.minecraft.world.level.storage.ServerLevelData;
 | |
| import org.jetbrains.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, boolean spawnFriendlies) {
 | |
| 		if (level.getGameRules().getBoolean(GameRules.RULE_DO_TRADER_SPAWNING)) {
 | |
| 			if (--this.tickDelay <= 0) {
 | |
| 				this.tickDelay = 1200;
 | |
| 				this.spawnDelay -= 1200;
 | |
| 				this.serverLevelData.setWanderingTraderSpawnDelay(this.spawnDelay);
 | |
| 				if (this.spawnDelay <= 0) {
 | |
| 					this.spawnDelay = 24000;
 | |
| 					if (level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING)) {
 | |
| 						int i = this.spawnChance;
 | |
| 						this.spawnChance = Mth.clamp(this.spawnChance + 25, 25, 75);
 | |
| 						this.serverLevelData.setWanderingTraderSpawnChance(this.spawnChance);
 | |
| 						if (this.random.nextInt(100) <= i) {
 | |
| 							if (this.spawn(level)) {
 | |
| 								this.spawnChance = 25;
 | |
| 							}
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private boolean spawn(ServerLevel serverLevel) {
 | |
| 		Player player = serverLevel.getRandomPlayer();
 | |
| 		if (player == null) {
 | |
| 			return true;
 | |
| 		} else if (this.random.nextInt(10) != 0) {
 | |
| 			return false;
 | |
| 		} else {
 | |
| 			BlockPos blockPos = player.blockPosition();
 | |
| 			int i = 48;
 | |
| 			PoiManager poiManager = serverLevel.getPoiManager();
 | |
| 			Optional<BlockPos> optional = poiManager.find(holder -> holder.is(PoiTypes.MEETING), blockPosx -> true, blockPos, 48, PoiManager.Occupancy.ANY);
 | |
| 			BlockPos blockPos2 = (BlockPos)optional.orElse(blockPos);
 | |
| 			BlockPos blockPos3 = this.findSpawnPositionNear(serverLevel, blockPos2, 48);
 | |
| 			if (blockPos3 != null && this.hasEnoughSpace(serverLevel, blockPos3)) {
 | |
| 				if (serverLevel.getBiome(blockPos3).is(BiomeTags.WITHOUT_WANDERING_TRADER_SPAWNS)) {
 | |
| 					return false;
 | |
| 				}
 | |
| 
 | |
| 				WanderingTrader wanderingTrader = EntityType.WANDERING_TRADER.spawn(serverLevel, blockPos3, EntitySpawnReason.EVENT);
 | |
| 				if (wanderingTrader != null) {
 | |
| 					for (int j = 0; j < 2; j++) {
 | |
| 						this.tryToSpawnLlamaFor(serverLevel, wanderingTrader, 4);
 | |
| 					}
 | |
| 
 | |
| 					this.serverLevelData.setWanderingTraderId(wanderingTrader.getUUID());
 | |
| 					wanderingTrader.setDespawnDelay(48000);
 | |
| 					wanderingTrader.setWanderTarget(blockPos2);
 | |
| 					wanderingTrader.setHomeTo(blockPos2, 16);
 | |
| 					return true;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			return false;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private void tryToSpawnLlamaFor(ServerLevel serverLevel, WanderingTrader trader, int maxDistance) {
 | |
| 		BlockPos blockPos = this.findSpawnPositionNear(serverLevel, trader.blockPosition(), maxDistance);
 | |
| 		if (blockPos != null) {
 | |
| 			TraderLlama traderLlama = EntityType.TRADER_LLAMA.spawn(serverLevel, blockPos, EntitySpawnReason.EVENT);
 | |
| 			if (traderLlama != null) {
 | |
| 				traderLlama.setLeashedTo(trader, true);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	@Nullable
 | |
| 	private BlockPos findSpawnPositionNear(LevelReader level, BlockPos pos, int maxDistance) {
 | |
| 		BlockPos blockPos = null;
 | |
| 		SpawnPlacementType spawnPlacementType = SpawnPlacements.getPlacementType(EntityType.WANDERING_TRADER);
 | |
| 
 | |
| 		for (int i = 0; i < 10; i++) {
 | |
| 			int j = pos.getX() + this.random.nextInt(maxDistance * 2) - maxDistance;
 | |
| 			int k = pos.getZ() + this.random.nextInt(maxDistance * 2) - maxDistance;
 | |
| 			int l = level.getHeight(Heightmap.Types.WORLD_SURFACE, j, k);
 | |
| 			BlockPos blockPos2 = new BlockPos(j, l, k);
 | |
| 			if (spawnPlacementType.isSpawnPositionOk(level, blockPos2, EntityType.WANDERING_TRADER)) {
 | |
| 				blockPos = blockPos2;
 | |
| 				break;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return blockPos;
 | |
| 	}
 | |
| 
 | |
| 	private boolean hasEnoughSpace(BlockGetter level, BlockPos pos) {
 | |
| 		for (BlockPos blockPos : BlockPos.betweenClosed(pos, pos.offset(1, 2, 1))) {
 | |
| 			if (!level.getBlockState(blockPos).getCollisionShape(level, blockPos).isEmpty()) {
 | |
| 				return false;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return true;
 | |
| 	}
 | |
| }
 |