2018-09-13 12:03:28 -04:00
|
|
|
package noppes.npcs;
|
|
|
|
|
|
|
|
|
|
import com.google.common.collect.Sets;
|
|
|
|
|
import cpw.mods.fml.common.eventhandler.Event.Result;
|
|
|
|
|
import net.minecraft.block.Block;
|
2023-01-12 21:33:06 -05:00
|
|
|
import net.minecraft.entity.Entity;
|
|
|
|
|
import net.minecraft.entity.EntityList;
|
|
|
|
|
import net.minecraft.entity.EntityLiving;
|
|
|
|
|
import net.minecraft.entity.EnumCreatureType;
|
2018-09-13 12:03:28 -04:00
|
|
|
import net.minecraft.entity.player.EntityPlayer;
|
2022-06-29 03:36:52 -05:00
|
|
|
import net.minecraft.init.Blocks;
|
2022-06-29 14:22:27 -05:00
|
|
|
import net.minecraft.nbt.NBTTagCompound;
|
2018-09-13 12:03:28 -04:00
|
|
|
import net.minecraft.util.MathHelper;
|
2022-06-29 03:36:52 -05:00
|
|
|
import net.minecraft.util.math.BlockPos;
|
2023-01-12 21:33:06 -05:00
|
|
|
import net.minecraft.world.ChunkCoordIntPair;
|
|
|
|
|
import net.minecraft.world.ChunkPosition;
|
|
|
|
|
import net.minecraft.world.World;
|
|
|
|
|
import net.minecraft.world.WorldServer;
|
2018-09-13 12:03:28 -04:00
|
|
|
import net.minecraft.world.biome.BiomeGenBase;
|
|
|
|
|
import net.minecraft.world.chunk.Chunk;
|
|
|
|
|
import net.minecraftforge.event.ForgeEventFactory;
|
|
|
|
|
import noppes.npcs.controllers.SpawnController;
|
2022-05-24 01:07:50 -05:00
|
|
|
import noppes.npcs.controllers.data.SpawnData;
|
2018-09-13 12:03:28 -04:00
|
|
|
import noppes.npcs.entity.EntityCustomNpc;
|
|
|
|
|
import noppes.npcs.entity.EntityNPCInterface;
|
2022-11-24 14:36:09 -06:00
|
|
|
import noppes.npcs.scripted.NpcAPI;
|
|
|
|
|
import noppes.npcs.scripted.event.CustomNPCsEvent;
|
2018-09-13 12:03:28 -04:00
|
|
|
|
2023-01-12 21:33:06 -05:00
|
|
|
import java.util.*;
|
|
|
|
|
|
2018-09-13 12:03:28 -04:00
|
|
|
public class NPCSpawning {
|
|
|
|
|
private static Set<ChunkCoordIntPair> eligibleChunksForSpawning = Sets.newHashSet();
|
2022-06-29 03:36:52 -05:00
|
|
|
|
|
|
|
|
private static boolean animalSpawn;
|
|
|
|
|
private static boolean monsterSpawn;
|
|
|
|
|
private static boolean airSpawn;
|
|
|
|
|
private static boolean liquidSpawn;
|
|
|
|
|
|
2018-09-13 12:03:28 -04:00
|
|
|
public static void findChunksForSpawning(WorldServer world){
|
2023-06-05 22:12:48 -04:00
|
|
|
if(SpawnController.Instance.data.isEmpty() || world.getWorldInfo().getWorldTotalTime() % 400L != 0L)
|
2018-09-13 12:03:28 -04:00
|
|
|
return;
|
|
|
|
|
eligibleChunksForSpawning.clear();
|
|
|
|
|
for (int i = 0; i < world.playerEntities.size(); ++i){
|
|
|
|
|
EntityPlayer entityplayer = (EntityPlayer)world.playerEntities.get(i);
|
|
|
|
|
int j = MathHelper.floor_double(entityplayer.posX / 16.0D);
|
|
|
|
|
int k = MathHelper.floor_double(entityplayer.posZ / 16.0D);
|
|
|
|
|
byte size = 7;
|
|
|
|
|
|
|
|
|
|
for (int x = -size; x <= size; ++x){
|
|
|
|
|
for (int z = -size; z <= size; ++z){
|
|
|
|
|
ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(x + j, z + k);
|
|
|
|
|
if (!eligibleChunksForSpawning.contains(chunkcoordintpair)){
|
|
|
|
|
eligibleChunksForSpawning.add(chunkcoordintpair);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (countNPCs(world) > eligibleChunksForSpawning.size()){
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
ArrayList<ChunkCoordIntPair> tmp = new ArrayList(eligibleChunksForSpawning);
|
|
|
|
|
Collections.shuffle(tmp);
|
|
|
|
|
Iterator<ChunkCoordIntPair> iterator = tmp.iterator();
|
|
|
|
|
|
|
|
|
|
while (iterator.hasNext()){
|
|
|
|
|
ChunkCoordIntPair chunkcoordintpair1 = iterator.next();
|
|
|
|
|
|
|
|
|
|
ChunkPosition chunkposition = getChunk(world, chunkcoordintpair1.chunkXPos, chunkcoordintpair1.chunkZPos);
|
|
|
|
|
int j1 = chunkposition.chunkPosX;
|
2022-06-29 12:21:30 -05:00
|
|
|
int y = chunkposition.chunkPosY;
|
2018-09-13 12:03:28 -04:00
|
|
|
int l1 = chunkposition.chunkPosZ;
|
|
|
|
|
|
|
|
|
|
for(int i = 0; i < 3; i++){
|
|
|
|
|
int x = j1;
|
|
|
|
|
int z = l1;
|
|
|
|
|
byte b1 = 6;
|
|
|
|
|
|
|
|
|
|
x += world.rand.nextInt(b1) - world.rand.nextInt(b1);
|
|
|
|
|
z += world.rand.nextInt(b1) - world.rand.nextInt(b1);
|
|
|
|
|
|
|
|
|
|
String name = world.getBiomeGenForCoords(x, z).biomeName;
|
2023-06-05 22:12:48 -04:00
|
|
|
SpawnData data = SpawnController.Instance.getRandomSpawnData(name, world.provider.dimensionId);
|
2018-09-13 12:03:28 -04:00
|
|
|
if (data == null || !canCreatureTypeSpawnAtLocation(data, world, x, y, z) || world.getClosestPlayer(x, y, z, 24.0D) != null)
|
|
|
|
|
continue;
|
2024-08-05 19:35:59 -05:00
|
|
|
|
2018-09-13 12:03:28 -04:00
|
|
|
spawnData(data, world, x, y, z);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-08-05 19:35:59 -05:00
|
|
|
|
2018-09-13 12:03:28 -04:00
|
|
|
public static int countNPCs(World world){
|
|
|
|
|
int count = 0;
|
|
|
|
|
List<Entity> list = world.loadedEntityList;
|
|
|
|
|
for (Entity entity : list){
|
|
|
|
|
if (entity instanceof EntityNPCInterface){
|
|
|
|
|
count++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected static ChunkPosition getChunk(World world, int x, int z){
|
|
|
|
|
Chunk chunk = world.getChunkFromChunkCoords(x, z);
|
|
|
|
|
int k = x * 16 + world.rand.nextInt(16);
|
|
|
|
|
int l = z * 16 + world.rand.nextInt(16);
|
|
|
|
|
int i1 = world.rand.nextInt(chunk == null ? world.getActualHeight() : chunk.getTopFilledSegment() + 16 - 1);
|
|
|
|
|
return new ChunkPosition(k, i1, l);
|
|
|
|
|
}
|
2024-08-05 19:35:59 -05:00
|
|
|
|
2018-09-13 12:03:28 -04:00
|
|
|
public static void performWorldGenSpawning(World world, int x, int z, Random rand){
|
|
|
|
|
BiomeGenBase biome = world.getBiomeGenForCoords(x + 8, z + 8);
|
|
|
|
|
while (rand.nextFloat() < biome.getSpawningChance()){
|
2023-06-05 22:12:48 -04:00
|
|
|
SpawnData data = SpawnController.Instance.getRandomSpawnData(biome.biomeName, world.provider.dimensionId);
|
2018-09-13 12:03:28 -04:00
|
|
|
if(data == null)
|
|
|
|
|
continue;
|
2024-08-05 19:35:59 -05:00
|
|
|
|
2018-09-13 12:03:28 -04:00
|
|
|
int size = 16;
|
2024-08-05 19:35:59 -05:00
|
|
|
|
2018-09-13 12:03:28 -04:00
|
|
|
int j1 = x + rand.nextInt(size);
|
|
|
|
|
int k1 = z + rand.nextInt(size);
|
|
|
|
|
int l1 = j1;
|
|
|
|
|
int i2 = k1;
|
|
|
|
|
|
|
|
|
|
for (int k2 = 0; k2 < 4; ++k2){
|
|
|
|
|
int l2 = world.getTopSolidOrLiquidBlock(j1, k1);
|
2022-06-29 03:36:52 -05:00
|
|
|
if (l2 > data.spawnHeightMax || l2 < data.spawnHeightMin) {
|
|
|
|
|
continue;
|
|
|
|
|
} else if (data.airSpawning && l2 < data.spawnHeightMax) {
|
|
|
|
|
l2 = l2 + (int) ((data.spawnHeightMax - l2) * Math.random());
|
|
|
|
|
}
|
2018-09-13 12:03:28 -04:00
|
|
|
|
|
|
|
|
if (!canCreatureTypeSpawnAtLocation(data, world, j1, l2, k1)){
|
|
|
|
|
j1 += rand.nextInt(5) - rand.nextInt(5);
|
|
|
|
|
|
|
|
|
|
for (k1 += rand.nextInt(5) - rand.nextInt(5); j1 < x || j1 >= x + size || k1 < z || k1 >= z + size; k1 = i2 + rand.nextInt(5) - rand.nextInt(5))
|
|
|
|
|
{
|
|
|
|
|
j1 = l1 + rand.nextInt(5) - rand.nextInt(5);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(spawnData(data, world, j1, l2, k1))
|
|
|
|
|
break;
|
2024-08-05 19:35:59 -05:00
|
|
|
|
2018-09-13 12:03:28 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-08-05 19:35:59 -05:00
|
|
|
|
2018-09-13 12:03:28 -04:00
|
|
|
private static boolean spawnData(SpawnData data, World world, int x, int y, int z){
|
|
|
|
|
EntityLiving entityliving;
|
|
|
|
|
|
|
|
|
|
try{
|
2023-03-20 02:00:58 -05:00
|
|
|
NBTTagCompound[] allCompoundList = data.spawnCompounds.values().toArray(new NBTTagCompound[0]);
|
2022-06-29 14:22:27 -05:00
|
|
|
ArrayList<Entity> entities = new ArrayList<>();
|
|
|
|
|
for (NBTTagCompound compound : allCompoundList) {
|
|
|
|
|
Entity entity;
|
|
|
|
|
try {
|
2022-10-31 17:48:53 -05:00
|
|
|
Class<?> oclass = (Class<?>)EntityList.stringToClassMapping.get(compound.getString("id"));
|
|
|
|
|
if (oclass == null) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2022-06-29 14:22:27 -05:00
|
|
|
entity = EntityList.createEntityFromNBT(compound, world);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2022-10-29 18:30:21 -05:00
|
|
|
if (entity != null) {
|
|
|
|
|
entities.add(entity);
|
|
|
|
|
}
|
2022-06-29 14:22:27 -05:00
|
|
|
}
|
|
|
|
|
|
2022-10-31 17:48:53 -05:00
|
|
|
if (entities.size() == 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-29 14:22:27 -05:00
|
|
|
Entity spawnEntity = entities.get((int)Math.floor(Math.random()*entities.size()));
|
|
|
|
|
|
2022-10-31 17:48:53 -05:00
|
|
|
if (!(spawnEntity instanceof EntityLiving)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2022-06-29 14:22:27 -05:00
|
|
|
|
|
|
|
|
entityliving = (EntityLiving) spawnEntity;
|
2024-08-05 19:35:59 -05:00
|
|
|
|
2022-06-29 14:22:27 -05:00
|
|
|
if(spawnEntity instanceof EntityCustomNpc){
|
|
|
|
|
EntityCustomNpc npc = (EntityCustomNpc) spawnEntity;
|
2018-09-13 12:03:28 -04:00
|
|
|
npc.stats.spawnCycle = 3;
|
2025-02-10 21:32:55 -05:00
|
|
|
npc.ais.returnToStart = false;
|
|
|
|
|
npc.ais.startPos = new int[]{x,y, z};
|
2022-06-29 03:36:52 -05:00
|
|
|
npc.updateAI = true;
|
|
|
|
|
npc.updateClient = true;
|
|
|
|
|
npc.getNavigator().clearPathEntity();
|
2018-09-13 12:03:28 -04:00
|
|
|
}
|
2022-06-29 14:22:27 -05:00
|
|
|
spawnEntity.setLocationAndAngles(x + 0.5, y, z + 0.5, world.rand.nextFloat() * 360.0F, 0.0F);
|
2018-09-13 12:03:28 -04:00
|
|
|
}
|
|
|
|
|
catch (Exception exception){
|
|
|
|
|
exception.printStackTrace();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Result canSpawn = ForgeEventFactory.canEntitySpawn(entityliving, world, x + 0.5f, y, z + 0.5f);
|
2022-06-29 12:21:30 -05:00
|
|
|
if (canSpawn == Result.DENY || (canSpawn == Result.DEFAULT && !canEntitySpawn(data,entityliving)))
|
2018-09-13 12:03:28 -04:00
|
|
|
return false;
|
2022-06-29 03:36:52 -05:00
|
|
|
|
2024-08-05 19:35:59 -05:00
|
|
|
CustomNPCsEvent.CNPCNaturalSpawnEvent event = new CustomNPCsEvent.CNPCNaturalSpawnEvent(entityliving, data, NpcAPI.Instance().getIPos(new BlockPos(x,y,z)), NPCSpawning.animalSpawn, NPCSpawning.monsterSpawn, NPCSpawning.liquidSpawn, NPCSpawning.airSpawn);
|
2022-11-24 14:36:09 -06:00
|
|
|
if (EventHooks.onCNPCNaturalSpawn(event)) {
|
2022-06-29 03:36:52 -05:00
|
|
|
return false;
|
|
|
|
|
}
|
2022-11-24 14:36:09 -06:00
|
|
|
|
|
|
|
|
entityliving.setPosition(event.attemptPosition.getX(),event.attemptPosition.getY(),event.attemptPosition.getZ());
|
2018-09-13 12:03:28 -04:00
|
|
|
world.spawnEntityInWorld(entityliving);
|
2024-08-05 19:35:59 -05:00
|
|
|
|
2018-09-13 12:03:28 -04:00
|
|
|
return true;
|
|
|
|
|
}
|
2022-06-29 12:21:30 -05:00
|
|
|
|
|
|
|
|
public static boolean canEntitySpawn(SpawnData data, EntityLiving entityLiving) {
|
|
|
|
|
if (!data.liquidSpawning) {
|
|
|
|
|
return entityLiving.getCanSpawnHere();
|
|
|
|
|
} else {
|
|
|
|
|
return entityLiving.worldObj.checkNoEntityCollision(entityLiving.boundingBox) && entityLiving.worldObj.getCollidingBoundingBoxes(entityLiving, entityLiving.boundingBox).isEmpty();
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-08-05 19:35:59 -05:00
|
|
|
|
2018-09-13 12:03:28 -04:00
|
|
|
public static boolean canCreatureTypeSpawnAtLocation(SpawnData data, World world, int x, int y, int z){
|
2022-06-29 03:36:52 -05:00
|
|
|
Block block = world.getBlock(x, y - 1, z);
|
2022-06-29 14:22:27 -05:00
|
|
|
boolean hasSolidSurface = World.doesBlockHaveSolidTopSurface(world, x, y - 1, z);
|
2022-06-29 03:36:52 -05:00
|
|
|
|
|
|
|
|
boolean spawnBlockCreature = block.canCreatureSpawn(EnumCreatureType.creature, world, x, y - 1, z);
|
|
|
|
|
boolean spawnBlockMonster = block.canCreatureSpawn(EnumCreatureType.monster, world, x, y - 1, z);
|
|
|
|
|
|
|
|
|
|
boolean animalSpawn = data.animalSpawning && hasSolidSurface && spawnBlockCreature && !world.getBlock(x, y, z).isNormalCube() && !world.getBlock(x, y, z).getMaterial().isLiquid() && !world.getBlock(x, y + 1, z).isNormalCube();
|
|
|
|
|
boolean monsterSpawn = data.monsterSpawning && hasSolidSurface && spawnBlockMonster && !world.getBlock(x, y, z).isNormalCube() && !world.getBlock(x, y, z).getMaterial().isLiquid() && !world.getBlock(x, y + 1, z).isNormalCube();
|
2022-06-29 12:21:30 -05:00
|
|
|
boolean liquidSpawn = data.liquidSpawning && world.getBlock(x, y - 1, z).getMaterial().isLiquid() && world.getBlock(x, y, z).getMaterial().isLiquid();
|
2022-06-29 03:36:52 -05:00
|
|
|
boolean caveSpawn = data.airSpawning && world.getBlock(x, y - 1, z) == Blocks.air && world.getBlock(x, y, z) == Blocks.air && world.getBlock(x, y + 1, z) == Blocks.air;
|
|
|
|
|
|
|
|
|
|
NPCSpawning.animalSpawn = animalSpawn;
|
|
|
|
|
NPCSpawning.monsterSpawn = monsterSpawn;
|
|
|
|
|
NPCSpawning.liquidSpawn = liquidSpawn;
|
|
|
|
|
NPCSpawning.airSpawn = caveSpawn;
|
|
|
|
|
|
|
|
|
|
return animalSpawn || monsterSpawn || caveSpawn || liquidSpawn;
|
2018-09-13 12:03:28 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|