use of org.spongepowered.common.interfaces.IMixinChunk in project SpongeCommon by SpongePowered.
the class MixinWorldEntitySpawner method findChunksForSpawning.
/**
* @author blood - February 18th, 2017
* @reason Refactor entire method for optimizations and spawn limits.
*
* @param worldServerIn The world
* @param spawnHostileMobs If hostile entities can spawn
* @param spawnPeacefulMobs If passive entities can spawn
* @param spawnOnSetTickRate If tickrate has been reached for spawning passives
* @return The amount of entities spawned
*/
@Overwrite
public int findChunksForSpawning(WorldServer worldServerIn, boolean spawnHostileMobs, boolean spawnPeacefulMobs, boolean spawnOnSetTickRate) {
if (!spawnHostileMobs && !spawnPeacefulMobs) {
return 0;
}
try (PhaseContext<?> context = GenerationPhase.State.WORLD_SPAWNER_SPAWNING.createPhaseContext().world(worldServerIn).buildAndSwitch()) {
Iterator<Chunk> chunkIterator = this.eligibleSpawnChunks.iterator();
while (chunkIterator.hasNext()) {
Chunk chunk = chunkIterator.next();
((IMixinChunk) chunk).setIsSpawning(false);
chunkIterator.remove();
}
IMixinWorldServer spongeWorld = ((IMixinWorldServer) worldServerIn);
spongeWorld.getTimingsHandler().mobSpawn.startTiming();
int chunkSpawnCandidates = 0;
final int mobSpawnRange = Math.min(((IMixinWorldServer) worldServerIn).getActiveConfig().getConfig().getWorld().getMobSpawnRange(), ((org.spongepowered.api.world.World) worldServerIn).getViewDistance());
// Vanilla uses a div count of 289 (17x17) which assumes the view distance is 8.
// Since we allow for custom ranges, we need to adjust the div count based on the
// mob spawn range set by server.
final int MOB_SPAWN_COUNT_DIV = (2 * mobSpawnRange + 1) * (2 * mobSpawnRange + 1);
for (EntityPlayer entityplayer : worldServerIn.playerEntities) {
// We treat players who do not affect spawning as "spectators"
if (!((IMixinEntityPlayer) entityplayer).affectsSpawning() || entityplayer.isSpectator()) {
continue;
}
int playerPosX = MathHelper.floor(entityplayer.posX / 16.0D);
int playerPosZ = MathHelper.floor(entityplayer.posZ / 16.0D);
for (int i = -mobSpawnRange; i <= mobSpawnRange; ++i) {
for (int j = -mobSpawnRange; j <= mobSpawnRange; ++j) {
boolean flag = i == -mobSpawnRange || i == mobSpawnRange || j == -mobSpawnRange || j == mobSpawnRange;
final Chunk chunk = ((IMixinChunkProviderServer) worldServerIn.getChunkProvider()).getLoadedChunkWithoutMarkingActive(i + playerPosX, j + playerPosZ);
if (chunk == null || (chunk.unloadQueued && !((IMixinChunk) chunk).isPersistedChunk())) {
// Don't attempt to spawn in an unloaded chunk
continue;
}
final IMixinChunk spongeChunk = (IMixinChunk) chunk;
++chunkSpawnCandidates;
final ChunkPos chunkPos = chunk.getPos();
if (!flag && worldServerIn.getWorldBorder().contains(chunkPos)) {
PlayerChunkMapEntry playerchunkmapentry = worldServerIn.getPlayerChunkMap().getEntry(chunkPos.x, chunkPos.z);
if (playerchunkmapentry != null && playerchunkmapentry.isSentToPlayers() && !spongeChunk.isSpawning()) {
this.eligibleSpawnChunks.add(chunk);
spongeChunk.setIsSpawning(true);
}
}
}
}
}
// If there are no eligible chunks, return early
if (this.eligibleSpawnChunks.size() == 0) {
spongeWorld.getTimingsHandler().mobSpawn.stopTiming();
return 0;
}
int totalSpawned = 0;
final long worldTotalTime = worldServerIn.getTotalWorldTime();
final SpongeConfig<? extends GeneralConfigBase> activeConfig = ((IMixinWorldServer) worldServerIn).getActiveConfig();
labelOuterLoop: for (EnumCreatureType enumCreatureType : EnumCreatureType.values()) {
int limit = 0;
int tickRate = 0;
if (enumCreatureType == EnumCreatureType.MONSTER) {
limit = activeConfig.getConfig().getSpawner().getMonsterSpawnLimit();
tickRate = activeConfig.getConfig().getSpawner().getMonsterTickRate();
} else if (enumCreatureType == EnumCreatureType.CREATURE) {
limit = activeConfig.getConfig().getSpawner().getAnimalSpawnLimit();
tickRate = activeConfig.getConfig().getSpawner().getAnimalTickRate();
} else if (enumCreatureType == EnumCreatureType.WATER_CREATURE) {
limit = activeConfig.getConfig().getSpawner().getAquaticSpawnLimit();
tickRate = activeConfig.getConfig().getSpawner().getAquaticTickRate();
} else if (enumCreatureType == EnumCreatureType.AMBIENT) {
limit = activeConfig.getConfig().getSpawner().getAmbientSpawnLimit();
tickRate = activeConfig.getConfig().getSpawner().getAmbientTickRate();
}
if (limit == 0 || tickRate == 0 || (worldTotalTime % tickRate) != 0L) {
continue;
}
if ((!enumCreatureType.getPeacefulCreature() || spawnPeacefulMobs) && (enumCreatureType.getPeacefulCreature() || spawnHostileMobs)) {
int entityCount = SpongeImplHooks.countEntities(worldServerIn, enumCreatureType, true);
int maxCount = limit * chunkSpawnCandidates / MOB_SPAWN_COUNT_DIV;
if (entityCount > maxCount) {
continue labelOuterLoop;
}
chunkIterator = this.eligibleSpawnChunks.iterator();
int mobLimit = maxCount - entityCount + 1;
labelChunkStart: while (chunkIterator.hasNext() && mobLimit > 0) {
final Chunk chunk = chunkIterator.next();
final BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
final BlockPos blockpos = getRandomChunkPosition(worldServerIn, chunk);
int k1 = blockpos.getX();
int l1 = blockpos.getY();
int i2 = blockpos.getZ();
IBlockState iblockstate = worldServerIn.getBlockState(blockpos);
if (!iblockstate.isNormalCube()) {
int spawnCount = 0;
for (int spawnLimit = 0; spawnLimit < 3; ++spawnLimit) {
int l2 = k1;
int i3 = l1;
int j3 = i2;
Biome.SpawnListEntry spawnListEntry = null;
IEntityLivingData ientitylivingdata = null;
int l3 = MathHelper.ceil(Math.random() * 4.0D);
for (int i4 = 0; i4 < l3; ++i4) {
l2 += worldServerIn.rand.nextInt(6) - worldServerIn.rand.nextInt(6);
i3 += worldServerIn.rand.nextInt(1) - worldServerIn.rand.nextInt(1);
j3 += worldServerIn.rand.nextInt(6) - worldServerIn.rand.nextInt(6);
mutableBlockPos.setPos(l2, i3, j3);
final double spawnX = l2 + 0.5F;
final double spawnY = i3;
final double spawnZ = j3 + 0.5F;
if (!worldServerIn.isAnyPlayerWithinRangeAt(spawnX, spawnY, spawnZ, 24.0D) && worldServerIn.getSpawnPoint().distanceSq(spawnX, spawnY, spawnZ) >= 576.0D) {
if (spawnListEntry == null) {
spawnListEntry = worldServerIn.getSpawnListEntryForTypeAt(enumCreatureType, mutableBlockPos);
if (spawnListEntry == null) {
break;
}
}
final EntityType entityType = EntityTypeRegistryModule.getInstance().getForClass(spawnListEntry.entityClass);
if (entityType != null) {
Vector3d vector3d = new Vector3d(spawnX, spawnY, spawnZ);
Transform<org.spongepowered.api.world.World> transform = new Transform<>((org.spongepowered.api.world.World) worldServerIn, vector3d);
ConstructEntityEvent.Pre event = SpongeEventFactory.createConstructEntityEventPre(Sponge.getCauseStackManager().getCurrentCause(), entityType, transform);
if (SpongeImpl.postEvent(event)) {
continue;
}
}
if (worldServerIn.canCreatureTypeSpawnHere(enumCreatureType, spawnListEntry, mutableBlockPos) && WorldEntitySpawner.canCreatureTypeSpawnAtLocation(EntitySpawnPlacementRegistry.getPlacementForEntity(spawnListEntry.entityClass), worldServerIn, mutableBlockPos)) {
EntityLiving entityliving;
try {
entityliving = spawnListEntry.entityClass.getConstructor(new Class<?>[] { World.class }).newInstance(worldServerIn);
} catch (Exception exception) {
exception.printStackTrace();
continue labelOuterLoop;
}
entityliving.setLocationAndAngles(spawnX, spawnY, spawnZ, worldServerIn.rand.nextFloat() * 360.0F, 0.0F);
final boolean entityNotColliding = entityliving.isNotColliding();
final SpawnerSpawnType type = SpongeImplHooks.canEntitySpawnHere(entityliving, entityNotColliding);
if (type != SpawnerSpawnType.NONE) {
if (type == SpawnerSpawnType.NORMAL) {
ientitylivingdata = entityliving.onInitialSpawn(worldServerIn.getDifficultyForLocation(new BlockPos(entityliving)), ientitylivingdata);
}
if (entityNotColliding) {
++spawnCount;
worldServerIn.spawnEntity(entityliving);
} else {
entityliving.setDead();
}
mobLimit--;
if (mobLimit <= 0 || spawnCount >= SpongeImplHooks.getMaxSpawnPackSize(entityliving)) {
continue labelChunkStart;
}
}
totalSpawned += spawnCount;
}
}
}
}
}
}
}
}
spongeWorld.getTimingsHandler().mobSpawn.stopTiming();
return totalSpawned;
}
}
use of org.spongepowered.common.interfaces.IMixinChunk in project SpongeCommon by SpongePowered.
the class MixinWorldServer method isAreaLoaded.
/**
* @author amaranth - April 25th, 2016
* @reason Avoid 25 chunk map lookups per entity per tick by using neighbor pointers
*
* @param xStart X block start coordinate
* @param yStart Y block start coordinate
* @param zStart Z block start coordinate
* @param xEnd X block end coordinate
* @param yEnd Y block end coordinate
* @param zEnd Z block end coordinate
* @param allowEmpty Whether empty chunks should be accepted
* @return If the chunks for the area are loaded
*/
@Override
public boolean isAreaLoaded(int xStart, int yStart, int zStart, int xEnd, int yEnd, int zEnd, boolean allowEmpty) {
if (yEnd < 0 || yStart > 255) {
return false;
}
xStart = xStart >> 4;
zStart = zStart >> 4;
xEnd = xEnd >> 4;
zEnd = zEnd >> 4;
net.minecraft.world.chunk.Chunk base = this.mixinChunkProviderServer.getLoadedChunkWithoutMarkingActive(xStart, zStart);
if (base == null) {
return false;
}
IMixinChunk currentColumn = (IMixinChunk) base;
for (int i = xStart; i <= xEnd; i++) {
if (currentColumn == null) {
return false;
}
IMixinChunk currentRow = (IMixinChunk) currentColumn.getNeighborChunk(1);
for (int j = zStart; j <= zEnd; j++) {
if (currentRow == null) {
return false;
}
if (!allowEmpty && ((net.minecraft.world.chunk.Chunk) currentRow).isEmpty()) {
return false;
}
currentRow = (IMixinChunk) currentRow.getNeighborChunk(1);
}
currentColumn = (IMixinChunk) currentColumn.getNeighborChunk(2);
}
return true;
}
use of org.spongepowered.common.interfaces.IMixinChunk in project SpongeForge by SpongePowered.
the class MixinChunk method onSetChunkLoaded.
@SideOnly(Side.CLIENT)
@Inject(method = "markLoaded", at = @At("RETURN"))
public void onSetChunkLoaded(boolean loaded, CallbackInfo ci) {
Direction[] directions = { Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST };
for (Direction direction : directions) {
Vector3i neighborPosition = this.getPosition().add(direction.asBlockOffset());
net.minecraft.world.chunk.Chunk neighbor = this.world.getChunkProvider().getLoadedChunk(neighborPosition.getX(), neighborPosition.getZ());
if (neighbor != null) {
this.setNeighbor(direction, (Chunk) neighbor);
((IMixinChunk) neighbor).setNeighbor(direction.getOpposite(), this);
}
}
}
use of org.spongepowered.common.interfaces.IMixinChunk in project SpongeForge by SpongePowered.
the class MixinWorld_Activation method updateEntityWithOptionalForce.
@Overwrite
public void updateEntityWithOptionalForce(Entity entityIn, boolean forceUpdate) {
// Sponge start - area is handled in ActivationRange
// int i = MathHelper.floor_double(entityIn.posX);
// int j = MathHelper.floor_double(entityIn.posZ);
// boolean isForced = getPersistentChunks().containsKey(new net.minecraft.util.math.ChunkPos(i >> 4, j >> 4));
// int k = isForced ? 0 : 32;
// boolean canUpdate = !forceUpdate || this.isAreaLoaded(i - k, 0, j - k, i + k, 0, j + k, true);
boolean canUpdate = EntityActivationRange.checkIfActive(entityIn);
// Allow forge mods to force an update
if (!canUpdate)
canUpdate = net.minecraftforge.event.ForgeEventFactory.canEntityUpdate(entityIn);
if (!canUpdate) {
entityIn.ticksExisted++;
((IModData_Activation) entityIn).inactiveTick();
return;
}
// Sponge end
entityIn.lastTickPosX = entityIn.posX;
entityIn.lastTickPosY = entityIn.posY;
entityIn.lastTickPosZ = entityIn.posZ;
entityIn.prevRotationYaw = entityIn.rotationYaw;
entityIn.prevRotationPitch = entityIn.rotationPitch;
if (forceUpdate && entityIn.addedToChunk) {
++entityIn.ticksExisted;
// Sponge
++co.aikar.timings.TimingHistory.activatedEntityTicks;
if (entityIn.isRiding()) {
entityIn.updateRidden();
} else {
entityIn.onUpdate();
}
}
if (Double.isNaN(entityIn.posX) || Double.isInfinite(entityIn.posX)) {
entityIn.posX = entityIn.lastTickPosX;
}
if (Double.isNaN(entityIn.posY) || Double.isInfinite(entityIn.posY)) {
entityIn.posY = entityIn.lastTickPosY;
}
if (Double.isNaN(entityIn.posZ) || Double.isInfinite(entityIn.posZ)) {
entityIn.posZ = entityIn.lastTickPosZ;
}
if (Double.isNaN(entityIn.rotationPitch) || Double.isInfinite(entityIn.rotationPitch)) {
entityIn.rotationPitch = entityIn.prevRotationPitch;
}
if (Double.isNaN(entityIn.rotationYaw) || Double.isInfinite(entityIn.rotationYaw)) {
entityIn.rotationYaw = entityIn.prevRotationYaw;
}
int l = MathHelper.floor(entityIn.posX / 16.0D);
int i1 = MathHelper.floor(entityIn.posY / 16.0D);
int j1 = MathHelper.floor(entityIn.posZ / 16.0D);
if (!entityIn.addedToChunk || entityIn.chunkCoordX != l || entityIn.chunkCoordY != i1 || entityIn.chunkCoordZ != j1) {
// Sponge start - use cached chunk
final Chunk activeChunk = (Chunk) ((IMixinEntity) entityIn).getActiveChunk();
if (activeChunk != null) {
activeChunk.removeEntityAtIndex(entityIn, entityIn.chunkCoordY);
}
// Sponge end
final IMixinChunk newChunk = (IMixinChunk) ((IMixinChunkProviderServer) entityIn.world.getChunkProvider()).getLoadedChunkWithoutMarkingActive(l, j1);
final boolean isPositionDirty = entityIn.setPositionNonDirty();
if (newChunk == null || (!isPositionDirty && newChunk.isQueuedForUnload() && !newChunk.isPersistedChunk())) {
entityIn.addedToChunk = false;
} else {
((net.minecraft.world.chunk.Chunk) newChunk).addEntity(entityIn);
}
}
if (forceUpdate && entityIn.addedToChunk) {
for (Entity entity : entityIn.getPassengers()) {
if (!entity.isDead && entity.getRidingEntity() == entityIn) {
this.updateEntity(entity);
} else {
entity.dismountRidingEntity();
}
}
}
}
Aggregations