tcr/server/src/server/world/WorldServer.java
2025-05-14 00:37:46 +02:00

2962 lines
95 KiB
Java
Executable file

package server.world;
import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import common.biome.BaseBiome;
import common.block.Block;
import common.block.BlockDoor;
import common.block.BlockEventData;
import common.block.BlockFalling;
import common.block.BlockLiquid;
import common.block.BlockSnow;
import common.collect.Lists;
import common.collect.Maps;
import common.collect.Sets;
import common.dimension.Dimension;
import common.entity.DamageSource;
import common.entity.Entity;
import common.entity.EntityTrackerEntry;
import common.entity.effect.EntityLightning;
import common.entity.npc.EntityNPC;
import common.entity.types.EntityLiving;
import common.init.Blocks;
import common.init.Config;
import common.init.SoundEvent;
import common.init.UniverseRegistry;
import common.item.ItemDoor;
import common.log.Log;
import common.material.Material;
import common.model.ParticleType;
import common.nbt.NBTLoader;
import common.nbt.NBTTagCompound;
import common.nbt.NBTTagInt;
import common.nbt.NBTTagList;
import common.network.IPlayer;
import common.network.Packet;
import common.packet.S1APacketEntityStatus;
import common.packet.S27PacketExplosion;
import common.packet.S28PacketEffect;
import common.packet.S29PacketSoundEffect;
import common.packet.S2APacketParticles;
import common.packet.S2BPacketChangeGameState;
import common.packet.S2CPacketSpawnGlobalEntity;
import common.packet.SPacketBiomes;
import common.packet.SPacketBlockAction;
import common.packet.SPacketBlockBreakAnim;
import common.packet.SPacketBlockChange;
import common.packet.SPacketChunkData;
import common.packet.SPacketMultiBlockChange;
import common.rng.Random;
import common.rng.WeightedList;
import common.tileentity.TileEntity;
import common.util.BlockPos;
import common.util.BoundingBox;
import common.util.ChunkPos;
import common.util.ExtMath;
import common.util.FileUtils;
import common.util.IntHashMap;
import common.util.LongHashMap;
import common.util.NextTickListEntry;
import common.util.PortalType;
import common.util.Position;
import common.util.Vec3;
import common.village.Village;
import common.world.BlockArray;
import common.world.Chunk;
import common.world.Explosion;
import common.world.AWorldServer;
import common.world.LightType;
import common.world.State;
import common.world.Weather;
import common.world.World;
import common.worldgen.BiomeGenerator;
import common.worldgen.FeatureLake;
import common.worldgen.FeatureLiquid;
import common.worldgen.FeatureOre;
import server.Server;
import server.biome.Biome;
import server.biome.RngSpawn;
import server.clipboard.ClipboardBlock;
import server.network.Player;
import server.village.VillageCollection;
import server.worldgen.BiomeGenLayered;
import server.worldgen.BiomeGenPerlin;
import server.worldgen.BiomeGenSingle;
import server.worldgen.BlockReplacer;
import server.worldgen.ChunkGenerator;
import server.worldgen.ChunkPrimer;
import server.worldgen.FeatureDungeons;
import server.worldgen.FeatureLakes;
import server.worldgen.FeatureLiquids;
import server.worldgen.FeatureOres;
import server.worldgen.GeneratorCavern;
import server.worldgen.GeneratorDebug;
import server.worldgen.GeneratorDestroyed;
import server.worldgen.GeneratorFlat;
import server.worldgen.GeneratorIsland;
import server.worldgen.GeneratorPerlin;
import server.worldgen.GeneratorSimple;
import server.worldgen.MobConstants;
import server.worldgen.ReplacerAltBiome;
import server.worldgen.ReplacerAltSurface;
import server.worldgen.ReplacerBiome;
import server.worldgen.ReplacerTopLayer;
import server.worldgen.caves.MapGenBigCaves;
import server.worldgen.caves.MapGenCaves;
import server.worldgen.caves.MapGenRavine;
import server.worldgen.structure.MapGenBridge;
import server.worldgen.structure.MapGenMineshaft;
import server.worldgen.structure.MapGenScatteredFeature;
import server.worldgen.structure.MapGenStronghold;
import server.worldgen.structure.MapGenVillage;
public final class WorldServer extends AWorldServer {
private static final int[][] XZ_DIRS = new int[][] {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
private final Server server;
private final File chunkDir;
private final Random grng;
private final Set<NextTickListEntry> ticks = Sets.<NextTickListEntry>newHashSet();
private final TreeSet<NextTickListEntry> ticksNext = new TreeSet();
private final EventList[] queue = new EventList[] {new EventList(), new EventList()};
private final List<NextTickListEntry> ticksNow = Lists.<NextTickListEntry>newArrayList();
private final Set<Long> dropped = Collections.<Long>newSetFromMap(new ConcurrentHashMap());
private final LongHashMap<Chunk> chunks = new LongHashMap();
private final List<Chunk> loaded = Lists.<Chunk>newArrayList();
private final Map<ChunkPos, NBTTagCompound> toRemove = new ConcurrentHashMap();
private final Set<ChunkPos> pending = Collections.<ChunkPos>newSetFromMap(new ConcurrentHashMap());
private final LongHashMap<BlockPos> loaders = new LongHashMap();
private final Set<BlockPos> loaderList = Sets.<BlockPos>newHashSet();
private final List<EntityNPC> managed = Lists.<EntityNPC>newArrayList();
private final LongHashMap<PlayerInstance> instances = new LongHashMap();
private final List<PlayerInstance> toUpdate = Lists.<PlayerInstance>newArrayList();
private final List<PlayerInstance> instList = Lists.<PlayerInstance>newArrayList();
private final Set<EntityTrackerEntry> tracked = Sets.<EntityTrackerEntry>newHashSet();
private final IntHashMap<EntityTrackerEntry> trackMap = new IntHashMap();
private final Map<String, WorldSavedData> dataMap = Maps.<String, WorldSavedData>newHashMap();
private final List<WorldSavedData> dataList = Lists.<WorldSavedData>newArrayList();
private final BaseBiome[] biomes = new BaseBiome[256];
private MapGenCaves caveGen;
private MapGenBigCaves bigCaveGen;
private MapGenRavine ravineGen;
private MapGenStronghold strongholdGen;
private MapGenVillage villageGen;
private VillageCollection villageStorage;
private MapGenMineshaft mineshaftGen;
private MapGenScatteredFeature scatteredGen;
private MapGenBridge bridgeGen;
private ChunkGenerator generator;
private BiomeGenerator biomeGen;
private BlockReplacer replacer;
private FeatureDungeons dungeons;
private State liquid;
private State base;
private State ceil;
private FeatureOres[] ores;
private FeatureLakes[] lakes;
private FeatureLiquids[] liquids;
private long seed;
private int height;
private int seaLevel;
private boolean mobs;
private boolean snow;
private boolean populate;
private boolean updateForced;
// private boolean resetWeather;
private boolean loadersModified;
// private boolean warpsModified;
private boolean exterminated;
private int emptyTicks;
private int blockEvtIdx;
private int trackDistance;
private int viewRadius;
private int updateLCG = this.rand.intv();
private long prevUpdate;
private long time;
public static float clampGravity() {
return ExtMath.clampf(Config.gravity, -10.0f, 10.0f);
}
private BiomeGenerator createBiomeGenerator(Random rand) {
return this.dimension.getBiomeSize() > 0 ? new BiomeGenLayered(rand.longv(), this.dimension.getDefaultBiome(), this.dimension.isSemiFixed(), this.dimension.getBiomeSize(), this.dimension.getRiverSize(),
this.dimension.getSnowRarity(), this.dimension.getSeaRarity(), this.dimension.getAddBiomes() == null ? new BaseBiome[0] : this.dimension.getAddBiomes(), this.dimension.getAddRarity(),
this.dimension.getHotBiomes() == null ? new BaseBiome[] {this.dimension.getDefaultBiome()} : this.dimension.getHotBiomes(),
this.dimension.getMediumBiomes() == null ? new BaseBiome[] {this.dimension.getDefaultBiome()} : this.dimension.getMediumBiomes(),
this.dimension.getColdBiomes() == null ? new BaseBiome[] {this.dimension.getDefaultBiome()} : this.dimension.getColdBiomes(),
this.dimension.getFrostBiomes() == null ? new BaseBiome[] {this.dimension.getDefaultBiome()} : this.dimension.getFrostBiomes()) : new BiomeGenSingle(this.dimension.getDefaultBiome());
}
private ChunkGenerator createChunkGenerator(Random rand) {
switch(this.dimension.getGeneratorType()) {
case FLAT:
return this.dimension.getLayers() == null ? new GeneratorFlat(this.dimension.getSeaLevel(), this.dimension.getFiller()) : new GeneratorFlat(this.dimension.getLayers());
case PERLIN:
default:
return new GeneratorPerlin(rand, this.dimension.getFiller(), this.dimension.getLiquid(), this.dimension.getNoiseGen());
case SIMPLE:
return new GeneratorSimple(rand, this.dimension.getFiller(), this.dimension.getLiquid(),
this.dimension.getBiomeSize() > 0 ? null : new BiomeGenPerlin(rand.longv()));
case ISLAND:
return new GeneratorIsland(rand, this.dimension.getFiller());
case CAVERN:
return new GeneratorCavern(rand, this.dimension.getFiller(), this.dimension.getLiquid());
case DESTROYED:
return new GeneratorDestroyed(this.dimension.getSeaLevel());
}
}
private BlockReplacer createBlockReplacer(Random rand) {
switch(this.dimension.getReplacerType()) {
case BIOMES:
default:
return new ReplacerBiome(rand);
case SIMPLE:
return new ReplacerAltBiome(rand, this.dimension.getFiller(), this.dimension.getLiquid(), this.dimension.getAlt2(), this.dimension.getAlt1());
case ALTERNATE:
return new ReplacerAltSurface(rand, this.dimension.getFiller(), this.dimension.getAlt1(), this.dimension.getAlt2(), this.dimension.getLiquid());
case TOPLAYER:
return new ReplacerTopLayer(this.dimension.getSurface(), this.dimension.getFiller().getBlock());
case NONE:
return null;
}
}
private FeatureDungeons createDungeonGenerator() {
return this.dimension.getDungeons() > 0 ? new FeatureDungeons(this.dimension.getDungeons()) : null;
}
private MapGenCaves createCaveGenerator() {
return this.dimension.hasCaves() ?
(new MapGenCaves(this.dimension.getCaveFiller(), this.dimension.getFiller().getBlock(), this.dimension.getTop().getBlock(),
this.dimension.getSurface().getBlock(), this.dimension.getAlt1().getBlock())) : null;
}
private MapGenRavine createRavineGenerator() {
return this.dimension.hasRavines() ?
(new MapGenRavine(this.dimension.getCaveFiller(), this.dimension.getFiller().getBlock(),
this.dimension.getTop().getBlock(), this.dimension.getSurface().getBlock())) : null;
}
private MapGenBigCaves createBigCaveGenerator() {
return this.dimension.hasStrideCaves() ?
(new MapGenBigCaves(this.dimension.getFiller().getBlock(),
this.dimension.getTop().getBlock(), this.dimension.getSurface().getBlock())) : null;
}
private FeatureOres[] createOres() {
if(this.dimension.getOres().isEmpty())
return null;
FeatureOres[] gens = new FeatureOres[this.dimension.getOres().size()];
for(int z = 0; z < gens.length; z++) {
FeatureOre gen = this.dimension.getOres().get(z);
gens[z] = new FeatureOres(gen.state, gen.count, gen.more, gen.size, gen.min, gen.max, gen.dist);
}
return gens;
}
private FeatureLakes[] createLakes() {
if(this.dimension.getLakes().isEmpty())
return null;
FeatureLakes[] gens = new FeatureLakes[this.dimension.getLakes().size()];
for(int z = 0; z < gens.length; z++) {
FeatureLake gen = this.dimension.getLakes().get(z);
gens[z] = new FeatureLakes(gen.state, gen.filler, gen.top, gen.chance, gen.minHeight, gen.maxHeight, gen.ratiod);
}
return gens;
}
private FeatureLiquids[] createLiquids() {
if(this.dimension.getLiquids().isEmpty())
return null;
FeatureLiquids[] gens = new FeatureLiquids[this.dimension.getLiquids().size()];
for(int z = 0; z < gens.length; z++) {
FeatureLiquid gen = this.dimension.getLiquids().get(z);
gens[z] = new FeatureLiquids(gen.state, gen.chance, gen.minHeight, gen.maxHeight, gen.lower);
}
return gens;
}
public WorldServer(Server server, long dtime, Dimension dim, boolean debug) {
super(dim, debug);
this.server = server;
// this.time = time;
this.daytime = dtime;
this.updateViewRadius();
this.chunkDir = new File(new File("chunk"), dim.getDimensionName());
if(!debug) {
this.chunkDir.mkdirs();
this.seed = this.rand.longv();
this.dimension.setSeed(this.seed);
NBTTagCompound tag = null;
try {
File dat = new File(this.chunkDir, "data.nbt");
if(dat.exists() && dat.isFile())
tag = NBTLoader.readGZip(dat);
}
catch(Exception e) {
Log.JNI.error(e, "Konnte Weltdaten nicht laden");
}
if(tag != null) {
this.exterminated = tag.getBoolean("Exterminated");
this.time = tag.getLong("Time");
if(tag.hasKey("Generator", 10)) {
this.dimension.fromNbt(tag.getCompoundTag("Generator"));
if(this.dimension.getType().weather && !this.exterminated)
this.weather = this.dimension.getWeather();
this.seed = this.dimension.getSeed();
}
if(this.dimension.getType().weather && !this.exterminated)
this.weather = Weather.getByName(tag.getString("Weather"));
if(this.weather == null) {
this.weather = this.dimension.getWeather();
// this.dataModified = true;
}
// ...
}
if(this.exterminated)
this.weather = Weather.CLEAR;
}
this.grng = new Random(this.seed);
// GeneratorSettings settings = !debug && !this.exterminated ? dim.getSettings() : null;
if(debug) {
this.liquid = Blocks.air.getState();
this.biomeGen = new BiomeGenSingle(BaseBiome.NONE);
this.generator = new GeneratorDebug();
this.replacer = null;
this.populate = false;
this.caveGen = null;
this.bigCaveGen = null;
this.ravineGen = null;
this.base = null;
this.ceil = null;
this.mobs = false;
this.snow = false;
this.strongholdGen = null;
this.villageGen = null;
this.mineshaftGen = null;
this.scatteredGen = null;
this.bridgeGen = null;
this.seaLevel = 0;
this.ores = null;
this.lakes = null;
this.liquids = null;
this.dungeons = null;
}
else if(this.exterminated) {
this.setExterminatedGen();
}
// else if(settings != null) {
//// settings = settings == null ? new GeneratorSettings() : settings;
// this.liquid = settings.useLavaSeas ? Blocks.lava.getDefaultState() : Blocks.water.getDefaultState();
// this.biomeGen = new BiomeGenNew(this.seed, settings);
// switch(settings.genMode) {
// case 0:
// this.generator = new GeneratorFlat(settings);
// break;
// case 1:
// default:
// this.generator = new GeneratorNew(this.grng, settings);
// break;
// case 2:
// this.generator = new GeneratorSimple(this.seed, this.grng, settings);
// break;
// }
// switch(settings.replMode) {
// case 0:
// this.replacer = null;
// break;
// case 1:
// default:
// this.replacer = new ReplacerBiome(this.grng);
// break;
// case 2:
// this.replacer = new ReplacerAltBiome(this.grng, settings);
// break;
// }
// this.populator = settings.populate == 0 ? null :
// (settings.populate == 2 ? new PopulatorSimple(this.grng, settings) : new PopulatorNew(this.grng, settings));
// this.caveGen = settings.useCaves ?
// (new MapGenCaves(settings.caveFill == 1 ? Blocks.lava.getDefaultState() :
// (settings.caveFill == 2 ? Blocks.water.getDefaultState() : Blocks.air.getDefaultState()), Blocks.stone,
// Blocks.dirt, Blocks.grass, Blocks.gravel)) : null;
// this.bigCaveGen = null;
// this.ravineGen = settings.useRavines ?
// (new MapGenRavine(settings.ravineFill == 1 ? Blocks.flowing_lava.getDefaultState() : (settings.ravineFill == 2
// ? Blocks.flowing_water.getDefaultState() : Blocks.air.getDefaultState()), Blocks.stone, Blocks.dirt, Blocks.grass)) : null;
// this.base = settings.useBedrock ? Blocks.bedrock.getDefaultState() : null;
// this.ceil = null;
// this.mobs = settings.mobs;
// this.snow = settings.snow;
// this.strongholdGen = settings.useStrongholds ? new MapGenStronghold() : null;
// this.villageGen = settings.useVillages ? new MapGenVillage() : null;
// this.mineshaftGen = settings.useMineShafts ? new MapGenMineshaft() : null;
// this.scatteredGen = settings.useScattered ? new MapGenScatteredFeature() : null;
// this.bridgeGen = null;
// this.seaLevel = settings.genMode == 0 ? this.generator.getMaximumHeight() : settings.seaLevel;
// this.ores = new FeatureOres[settings.oreList.size()];
// for(int z = 0; z < settings.oreList.size(); z++) {
// this.ores[z] = settings.oreList.get(z).createGenerator();
// }
//// PlanetTerra.setOres(settings.oreList);
// }
else {
this.liquid = this.dimension.getLiquid();
this.biomeGen = this.createBiomeGenerator(this.grng);
this.generator = this.createChunkGenerator(this.grng);
this.replacer = this.createBlockReplacer(this.grng);
this.populate = this.dimension.hasPopulator();
this.caveGen = this.createCaveGenerator();
this.bigCaveGen = this.createBigCaveGenerator();
this.ravineGen = this.createRavineGenerator();
this.base = this.dimension.getWorldFloor();
this.ceil = this.dimension.getWorldCeiling();
this.mobs = this.dimension.hasMobs();
this.snow = this.dimension.hasSnow();
this.strongholdGen = this.dimension.hasStrongholds() ? new MapGenStronghold() : null;
this.villageGen = this.dimension.hasVillages() ? new MapGenVillage() : null;
this.mineshaftGen = this.dimension.hasMineshafts() ? new MapGenMineshaft() : null;
this.scatteredGen = this.dimension.hasScattered() ? new MapGenScatteredFeature() : null;
this.bridgeGen = this.dimension.hasFortresses() ? new MapGenBridge() : null;
this.seaLevel = this.dimension.getSeaLevel();
this.ores = this.createOres();
this.lakes = this.createLakes();
this.liquids = this.createLiquids();
this.dungeons = this.createDungeonGenerator();
}
this.height = this.generator.getMaximumHeight();
// this.teleporter = new Teleporter(this);
this.calculateInitialSkylight();
this.calculateInitialWeather();
this.updatePhysics();
if(!debug) {
NBTTagCompound tag = null;
try {
File dat = new File(this.chunkDir, "loaders.nbt");
if(dat.exists() && dat.isFile())
tag = NBTLoader.readGZip(dat);
}
catch(Exception e) {
Log.JNI.error(e, "Konnte Ladeliste nicht laden");
}
if(tag != null && tag.hasKey("Loaders", 9)) {
NBTTagList list = tag.getTagList("Loaders", 10);
for(int z = 0; z < list.tagCount(); z++) {
NBTTagCompound pos = list.getCompoundTagAt(z);
this.addLoader(new BlockPos(pos.getInteger("X"), pos.getInteger("Y"), pos.getInteger("Z")));
}
this.loadersModified = false;
}
// tag = null;
// try {
// File dat = new File(this.chunkDir, "warps.nbt");
// if(dat.exists() && dat.isFile())
// tag = NBTLoader.readGZip(dat);
// }
// catch(Exception e) {
// Log.warn("Konnte Warpliste nicht laden", e);
// }
// if(tag != null && tag.hasKey("Warps", 9)) {
// NBTTagList list = tag.getTagList("Warps", 10);
// for(int z = 0; z < list.tagCount(); z++) {
// NBTTagCompound pos = list.getCompoundTagAt(z);
// server.getWarps().put(pos.getString("Name"), new Position(pos.getDouble("X"), pos.getDouble("Y"), pos.getDouble("Z"),
// pos.getFloat("Yaw"), pos.getFloat("Pitch"), this.dimension.getDimensionId()));
// }
// this.warpsModified = false;
// }
if(this.villageGen != null) {
tag = null;
try {
File dat = new File(this.chunkDir, "villages.nbt");
if(dat.exists() && dat.isFile())
tag = NBTLoader.readGZip(dat);
}
catch(Exception e) {
Log.JNI.error(e, "Konnte Dorfliste nicht laden");
}
this.villageStorage = new VillageCollection(tag);
}
}
}
public Server getServer() {
return this.server;
}
public void updatePhysics() {
this.setTimeFactor(Config.timeFlow);
this.setGravity(clampGravity());
}
public void tick() {
this.updateWeather(false);
this.biomeGen.cleanupCache();
// this.profiler.start("mobSpawner");
if(this.mobs && Config.mobs && Config.tickSpawn && !this.debug) {
Spawner.spawn(this);
}
// this.profiler.next("chunkSource");
if(!this.debug) {
for(int i = 0; i < 100; ++i) {
if(!this.dropped.isEmpty()) {
Long v = (Long)this.dropped.iterator().next();
Chunk chunk = (Chunk)this.chunks.getValueByKey(v.longValue());
if(chunk != null) {
chunk.onChunkUnload();
this.saveChunkData(chunk);
this.chunks.remove(v.longValue());
this.loaded.remove(chunk);
}
this.dropped.remove(v);
}
}
}
int light = this.calculateSkylightSubtracted(true);
if(light != this.getSkylightSubtracted())
this.setSkylightSubtracted(light);
// if(this.primary)
// this.info.tick();
this.time += 1L;
// this.dataModified = true;
if(Config.dayCycle) // {
this.daytime += this.timeFactor;
// if(this.dimension.getType().dayCycle)
// this.season = this.getSeasonByTime();
// }
// this.profiler.next("tickPending");
this.tickUpdates(false);
// this.profiler.next("tickBlocks");
this.updateBlocks();
// this.profiler.next("chunkMap");
this.updatePlayerInstances();
if(this.villageStorage != null)
// this.profiler.next("village");
this.villageStorage.tick(this);
//// this.server.getVillageSiege().tick();
// }
// this.profiler.next("portalForcer");
// this.teleporter.removeStalePortalLocations(this.time);
// this.profiler.end();
this.sendQueuedBlockEvents();
}
// public int getNextMapId() {
// return this.debug ? 0 : this.server.getMapId();
// }
public Random getGenRandom() {
return this.grng;
}
public State getSurfaceLiquid() {
return this.liquid;
}
public FeatureOres[] getOres() {
return this.ores;
}
public boolean addLoader(BlockPos pos) {
long chunk = LongHashMap.packInt(pos.getX() / 16, pos.getZ() / 16);
if(this.loaders.containsItem(chunk))
return false;
this.loaders.add(chunk, pos);
this.loaderList.add(pos);
this.loadersModified = true;
return true;
}
// public void setWarpsDirty() {
// this.warpsModified = true;
// }
public boolean removeLoader(BlockPos pos) {
long chunk = LongHashMap.packInt(pos.getX() / 16, pos.getZ() / 16);
BlockPos loader = this.loaders.getValueByKey(chunk);
if(!pos.equals(loader))
return false;
this.loaders.remove(chunk);
this.loaderList.remove(pos);
this.loadersModified = true;
return true;
}
private WeightedList<RngSpawn> getSpawnTypes(BlockPos pos) {
BaseBiome biome = this.getBiomeGenForCoords(pos);
if(this.bridgeGen != null && (this.bridgeGen.isPresent(pos)
|| (this.bridgeGen.isPositionInStructure(this, pos) && this.getState(pos.down()).getBlock() == Blocks.blood_brick)))
return MobConstants.FORTRESS_MOBS;
else if(this.scatteredGen != null && this.scatteredGen.hasMageHut(pos))
return MobConstants.MAGEHUT_MOBS;
return Biome.BIOMES[biome.id].getMobs();
}
public RngSpawn getSpawnListEntryForTypeAt(BlockPos pos) {
WeightedList<RngSpawn> list = this.getSpawnTypes(pos);
return list != null && !list.isEmpty() ? (RngSpawn)list.pick(this.rand) : null;
}
public boolean canCreatureTypeSpawnHere(RngSpawn spawnListEntry, BlockPos pos) {
WeightedList<RngSpawn> list = this.getSpawnTypes(pos);
return list != null && !list.isEmpty() ? list.contains(spawnListEntry) : false;
}
// public BlockPos getStrongholdPos(BlockPos pos) {
// return this.strongholdGen != null ? this.strongholdGen.getClosestStrongholdPos(this, pos) : null;
// }
public BiomeGenerator getBiomeGenerator() {
return this.biomeGen;
}
public BaseBiome getBiomeGenForCoords(final BlockPos pos) {
if(this.isBlockLoaded(pos))
return this.getChunk(pos).getBiome(pos, this.biomeGen);
else
return this.biomeGen.getBiomeGenerator(pos, BaseBiome.DEF_BIOME);
}
public void setItemData(String dataID, WorldSavedData worldSavedDataIn) {
if(!this.debug)
this.setData(dataID, worldSavedDataIn);
}
public WorldSavedData loadItemData(String dataID) {
return this.debug ? null : this.loadData(dataID);
}
protected void updateBlocks() {
this.setActivePlayerChunksAndCheckLight(Config.distance);
if(this.debug) {
for(ChunkPos chunkcoordintpair1 : this.active) {
this.getChunk(chunkcoordintpair1.x, chunkcoordintpair1.z).update(false);
}
}
else {
int i = 0;
int j = 0;
for(ChunkPos chunkcoordintpair : this.active) {
int k = chunkcoordintpair.x * 16;
int l = chunkcoordintpair.z * 16;
// this.profiler.start("getChunk");
Chunk chunk = this.getChunk(chunkcoordintpair.x, chunkcoordintpair.z);
// this.profiler.next("moodSound");
// this.playMoodSound(k, l, chunk);
// this.profiler.next("checkLight");
chunk.enqueueRelight();
// this.profiler.next("tickChunk");
chunk.update(false);
// this.profiler.next("thunder");
int l2 = Config.boltChance;
if(l2 > 0 && this.rand.zrange(l2) == 0 && this.isThundering()) {
this.updateLCG = this.updateLCG * 3 + 1013904223;
int i1 = this.updateLCG >> 2;
BlockPos blockpos = this.adjustPosToNearbyEntity(new BlockPos(k + (i1 & 15), 0, l + (i1 >> 8 & 15)));
if(this.canStrikeAt(blockpos)) {
this.strikeLightning((double)blockpos.getX(), (double)blockpos.getY(), (double)blockpos.getZ(), 0x737380, 120, true, null);
}
}
// this.profiler.next("iceandsnow");
l2 = Config.weatherTick;
for(int z = 0; z < l2; z++) {
if(this.rand.zrange(16) == 0) {
this.updateLCG = this.updateLCG * 3 + 1013904223;
int k2 = this.updateLCG >> 2;
BlockPos blockpos2 = this.getPrecipitationHeight(new BlockPos(k + (k2 & 15), 0, l + (k2 >> 8 & 15)));
BlockPos blockpos1 = blockpos2.down();
if(this.canBlockFreeze(blockpos1, true)) {
this.setState(blockpos1, Blocks.ice.getState());
}
if(this.snow && this.isRaining() && this.canSnowAt(blockpos2, true, Config.snowStack)) {
State layer = Config.snowStack ? this.getState(blockpos2) : null;
this.setState(blockpos2, Config.snowStack && layer.getBlock() == Blocks.snow_layer
? (Blocks.snow_layer.getState().withProperty(BlockSnow.LAYERS,
Math.min(layer.getValue(BlockSnow.LAYERS) + 1, 2))) : Blocks.snow_layer.getState());
}
if(this.isRaining()) { // && this.getBiomeGenForCoords(blockpos1).canRain()) {
this.getState(blockpos1).getBlock().fillWithRain(this, blockpos1);
}
if(Config.igniteChance > 0 && Config.fire && !this.isRaining() &&
this.rand.chance(this.hasDownfall() ? Math.max(1, Config.igniteChance / 3) : Config.igniteChance)
&& this.canPlaceFireAt(blockpos2)) {
this.setState(blockpos2, Blocks.fire.getState());
}
}
}
// this.profiler.next("tickBlocks");
l2 = Config.randomTick;
if(l2 > 0) {
for(BlockArray extendedblockstorage : chunk.getStorage()) {
if(extendedblockstorage != null && extendedblockstorage.isTicked()) {
for(int j1 = 0; j1 < l2; ++j1) {
this.updateLCG = this.updateLCG * 3 + 1013904223;
int k1 = this.updateLCG >> 2;
int l1 = k1 & 15;
int i2 = k1 >> 8 & 15;
int j2 = k1 >> 16 & 15;
++j;
State iblockstate = extendedblockstorage.get(l1, j2, i2);
Block block = iblockstate.getBlock();
if(block.getTickRandomly()) {
++i;
block.randomTick(this, new BlockPos(l1 + k, j2 + extendedblockstorage.getY(), i2 + l), iblockstate,
this.rand);
}
}
}
}
}
// this.profiler.end();
}
}
}
private BlockPos adjustPosToNearbyEntity(BlockPos pos) {
BlockPos blockpos = this.getPrecipitationHeight(pos);
BoundingBox axisalignedbb = (new BoundingBox(blockpos, new BlockPos(blockpos.getX(), World.HEIGHT, blockpos.getZ()))).expand(3.0D,
3.0D, 3.0D);
List<EntityLiving> list = this.getEntitiesWithinAABB(EntityLiving.class, axisalignedbb, new Predicate<EntityLiving>() {
public boolean test(EntityLiving p_apply_1_) {
return p_apply_1_ != null && p_apply_1_.isEntityAlive() && WorldServer.this.canSeeSky(p_apply_1_.getPosition());
}
});
return !list.isEmpty() ? ((EntityLiving)list.get(this.rand.zrange(list.size()))).getPosition() : blockpos;
}
public boolean isBlockTickPending(BlockPos pos, Block blockType) {
NextTickListEntry nextticklistentry = new NextTickListEntry(pos, blockType);
return this.ticksNow.contains(nextticklistentry);
}
public void scheduleUpdate(BlockPos pos, Block blockIn, int delay) {
this.updateBlockTick(pos, blockIn, delay, 0);
}
public void updateBlockTick(BlockPos pos, Block blockIn, int delay, int priority) {
NextTickListEntry nextticklistentry = new NextTickListEntry(pos, blockIn);
int i = 0;
if(this.updateForced && blockIn.getMaterial() != Material.air) {
if(blockIn.requiresUpdates()) {
i = 8;
if(this.isAreaLoaded(nextticklistentry.position.add(-i, -i, -i), nextticklistentry.position.add(i, i, i))) {
State iblockstate = this.getState(nextticklistentry.position);
if(iblockstate.getBlock().getMaterial() != Material.air && iblockstate.getBlock() == nextticklistentry.getBlock()) {
iblockstate.getBlock().updateTick(this, nextticklistentry.position, iblockstate, this.rand);
}
}
return;
}
delay = 1;
}
if(this.isAreaLoaded(pos.add(-i, -i, -i), pos.add(i, i, i))) {
if(blockIn.getMaterial() != Material.air) {
nextticklistentry.setScheduledTime((long)delay + this.time);
nextticklistentry.setPriority(priority);
}
if(!this.ticks.contains(nextticklistentry)) {
this.ticks.add(nextticklistentry);
this.ticksNext.add(nextticklistentry);
}
}
}
public void scheduleBlockUpdate(BlockPos pos, Block blockIn, int delay, int priority) {
NextTickListEntry nextticklistentry = new NextTickListEntry(pos, blockIn);
nextticklistentry.setPriority(priority);
if(blockIn.getMaterial() != Material.air) {
nextticklistentry.setScheduledTime((long)delay + this.time);
}
if(!this.ticks.contains(nextticklistentry)) {
this.ticks.add(nextticklistentry);
this.ticksNext.add(nextticklistentry);
}
}
public void updateEntities() {
if(this.players.isEmpty()) {
if(this.emptyTicks++ >= Config.unloadTicks) {
return;
}
}
else {
this.resetUpdateEntityTick();
}
super.updateEntities();
}
public void resetUpdateEntityTick() {
this.emptyTicks = 0;
}
public boolean shouldUnload() {
return this.emptyTicks >= Config.unloadTicks && this.loaderList.isEmpty();
}
public boolean tickUpdates(boolean p_72955_1_) {
if(this.debug) {
return false;
}
else {
int i = this.ticksNext.size();
if(i != this.ticks.size()) {
throw new IllegalStateException("TickNextTick list out of synch");
}
else {
if(i > 1000) {
i = 1000;
}
// this.profiler.start("cleaning");
for(int j = 0; j < i; ++j) {
NextTickListEntry nextticklistentry = (NextTickListEntry)this.ticksNext.first();
if(!p_72955_1_ && nextticklistentry.scheduledTime > this.time) {
break;
}
this.ticksNext.remove(nextticklistentry);
this.ticks.remove(nextticklistentry);
this.ticksNow.add(nextticklistentry);
}
// this.profiler.end();
// this.profiler.start("ticking");
Iterator<NextTickListEntry> iterator = this.ticksNow.iterator();
while(iterator.hasNext()) {
NextTickListEntry nextticklistentry1 = (NextTickListEntry)iterator.next();
iterator.remove();
int k = 0;
if(this.isAreaLoaded(nextticklistentry1.position.add(-k, -k, -k), nextticklistentry1.position.add(k, k, k))) {
State iblockstate = this.getState(nextticklistentry1.position);
if(iblockstate.getBlock().getMaterial() != Material.air
&& Block.isEqualTo(iblockstate.getBlock(), nextticklistentry1.getBlock())) {
iblockstate.getBlock().updateTick(this, nextticklistentry1.position, iblockstate, this.rand);
}
}
else {
this.scheduleUpdate(nextticklistentry1.position, nextticklistentry1.getBlock(), 0);
}
}
// this.profiler.end();
this.ticksNow.clear();
return !this.ticksNext.isEmpty();
}
}
}
public List<NextTickListEntry> getPendingBlockUpdates(Chunk chunk) {
int x1 = (chunk.xPos << 4) - 2;
int x2 = x1 + 16 + 2;
int z1 = (chunk.zPos << 4) - 2;
int z2 = z1 + 16 + 2;
List<NextTickListEntry> list = null;
for(int n = 0; n < 2; ++n) {
Iterator<NextTickListEntry> iter;
if(n == 0)
iter = this.ticksNext.iterator();
else
iter = this.ticksNow.iterator();
while(iter.hasNext()) {
NextTickListEntry tick = iter.next();
BlockPos pos = tick.position;
if(pos.getX() >= x1 && pos.getX() < x2 && pos.getZ() >= z1 && pos.getZ() < z2) {
if(list == null)
list = Lists.<NextTickListEntry>newArrayList();
list.add(tick);
}
}
}
return list;
}
public List<TileEntity> getTileEntitiesIn(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) {
List<TileEntity> list = Lists.<TileEntity>newArrayList();
for(int i = 0; i < this.tiles.size(); ++i) {
TileEntity tileentity = (TileEntity)this.tiles.get(i);
BlockPos blockpos = tileentity.getPos();
if(blockpos.getX() >= minX && blockpos.getY() >= minY && blockpos.getZ() >= minZ && blockpos.getX() < maxX && blockpos.getY() < maxY
&& blockpos.getZ() < maxZ) {
list.add(tileentity);
}
}
return list;
}
public static boolean needsLoading(Dimension dim) {
NBTTagCompound tag = null;
try {
File dat = new File(new File(new File("chunk"), dim.getDimensionName()), "loaders.nbt");
if(dat.exists() && dat.isFile())
tag = NBTLoader.readGZip(dat);
}
catch(Exception e) {
return false;
}
return tag != null && tag.hasKey("Loaders", 9) && !tag.getTagList("Loaders", 10).hasNoTags();
}
public static void loadWarps(Dimension dim, Map<String, Position> warps) {
NBTTagCompound tag = null;
try {
File dat = new File(new File(new File("chunk"), dim.getDimensionName()), "warps.nbt");
if(dat.exists() && dat.isFile())
tag = NBTLoader.readGZip(dat);
}
catch(Exception e) {
Log.JNI.error(e, "Konnte Warpliste nicht laden");
return;
}
if(tag != null && tag.hasKey("Warps", 9)) {
NBTTagList list = tag.getTagList("Warps", 10);
for(int z = 0; z < list.tagCount(); z++) {
NBTTagCompound pos = list.getCompoundTagAt(z);
warps.put(pos.getString("Name"), new Position(pos.getDouble("X"), pos.getDouble("Y"), pos.getDouble("Z"),
pos.getFloat("Yaw"), pos.getFloat("Pitch"), dim.getDimensionId()));
}
}
}
public static void saveWarps(Map<String, Position> warps) {
Map<Integer, NBTTagList> map = Maps.newHashMap();
for(Entry<String, Position> pos : warps.entrySet()) {
Dimension dim = UniverseRegistry.getDimension(pos.getValue().dim);
if(dim != null) {
NBTTagList list = map.get(pos.getValue().dim);
if(list == null)
map.put(pos.getValue().dim, list = new NBTTagList());
NBTTagCompound warp = new NBTTagCompound();
warp.setString("Name", pos.getKey());
warp.setDouble("X", pos.getValue().x);
warp.setDouble("Y", pos.getValue().y);
warp.setDouble("Z", pos.getValue().z);
warp.setFloat("Yaw", pos.getValue().yaw);
warp.setFloat("Pitch", pos.getValue().pitch);
list.appendTag(warp);
}
}
for(Dimension dim : UniverseRegistry.getDimensions()) {
NBTTagList list = map.get(dim.getDimensionId());
File file = new File(new File(new File("chunk"), dim.getDimensionName()), "warps.nbt");
if(list == null) {
file.delete();
}
else {
NBTTagCompound tag = new NBTTagCompound();
tag.setTag("Warps", list);
try {
NBTLoader.writeGZip(tag, file);
}
catch(Exception e) {
Log.JNI.error(e, "Konnte Warpliste nicht speichern");
}
}
}
map.clear();
}
public void saveAllChunks() {
if(/* (force || !this.disableSaving) && */ !this.debug) {
// if(this.primary) {
//
// }
if(this.loadersModified) {
this.loadersModified = false;
NBTTagCompound loaders = new NBTTagCompound();
NBTTagList list = new NBTTagList();
for(BlockPos pos : this.loaderList) {
NBTTagCompound loader = new NBTTagCompound();
loader.setInteger("X", pos.getX());
loader.setInteger("Y", pos.getY());
loader.setInteger("Z", pos.getZ());
list.appendTag(loader);
}
loaders.setTag("Loaders", list);
File file = new File(this.chunkDir, "loaders.nbt");
if(list.hasNoTags()) {
file.delete();
}
else {
try {
NBTLoader.writeGZip(loaders, file);
}
catch(Exception e) {
Log.JNI.error(e, "Konnte Ladeliste nicht speichern");
}
}
}
// if(this.warpsModified) {
// this.warpsModified = false;
// }
// if(this.dataModified) {
// this.dataModified = false;
NBTTagCompound data = new NBTTagCompound();
// data.setLong("Seed", this.seed);
data.setTag("Generator", this.dimension.toNbt(true));
data.setLong("Time", this.time);
data.setBoolean("Exterminated", this.exterminated);
data.setString("Weather", this.weather.getName());
// ...
File file = new File(this.chunkDir, "data.nbt");
try {
NBTLoader.writeGZip(data, file);
}
catch(Exception e) {
Log.JNI.error(e, "Konnte Weltdaten nicht speichern");
}
// }
for(int i = 0; i < this.dataList.size(); ++i) {
WorldSavedData wdata = this.dataList.get(i);
if(wdata.dirty) {
this.saveData(wdata);
wdata.dirty = false;
}
}
if(this.villageStorage != null && this.villageStorage.isDirty()) {
NBTTagCompound tag = this.villageStorage.writeToNBT();
File dat = new File(this.chunkDir, "villages.nbt");
try {
NBTLoader.writeGZip(tag, dat);
}
catch(Exception e) {
Log.JNI.error(e, "Konnte Dorfliste nicht speichern");
}
}
List<Chunk> list = Lists.newArrayList(this.loaded);
for(int n = 0; n < list.size(); ++n) {
Chunk chunk = list.get(n);
if(chunk.isDirty(this.time)) {
this.saveChunkData(chunk);
chunk.setModified(false);
}
}
for(Chunk chunk : Lists.newArrayList(this.loaded)) {
if(chunk != null && !this.hasPlayerInstance(chunk.xPos, chunk.zPos)) {
this.dropChunk(chunk.xPos, chunk.zPos);
}
}
}
}
protected void onEntityAdded(Entity entityIn) {
this.trackEntity(entityIn);
this.entityIds.addKey(entityIn.getId(), entityIn);
Entity[] aentity = entityIn.getParts();
if(aentity != null) {
for(int i = 0; i < aentity.length; ++i) {
this.entityIds.addKey(aentity[i].getId(), aentity[i]);
}
}
}
protected void onEntityRemoved(Entity entityIn) {
this.untrackEntity(entityIn);
this.entityIds.removeObject(entityIn.getId());
Entity[] aentity = entityIn.getParts();
if(aentity != null) {
for(int i = 0; i < aentity.length; ++i) {
this.entityIds.removeObject(aentity[i].getId());
}
}
}
public void strikeLightning(double x, double y, double z, int color, int damage, boolean fire, EntityLiving summoner) {
EntityLightning entity = new EntityLightning(this, x, y, z, color, damage, fire, summoner);
this.effects.add(entity);
this.server.sendNear(entity.posX, entity.posY, entity.posZ, 512.0D, this.dimension.getDimensionId(),
new S2CPacketSpawnGlobalEntity(entity, 1, entity.color));
if(fire && Config.fire) {
BlockPos pos = new BlockPos(entity);
if(this.isAreaLoaded(pos, 10)) {
if(this.getState(pos).getBlock().getMaterial() == Material.air && Blocks.fire.canPlaceBlockAt(this, pos))
this.setState(pos, Blocks.fire.getState());
for(int n = 0; n < 4; n++) {
BlockPos extra = pos.add(this.rand.range(-1, 1), this.rand.range(-1, 1), this.rand.range(-1, 1));
if(this.getState(extra).getBlock().getMaterial() == Material.air && Blocks.fire.canPlaceBlockAt(this, extra))
this.setState(extra, Blocks.fire.getState());
}
}
}
}
public void setEntityState(Entity entityIn, byte state) {
this.sendToAllTrackingAndSelf(entityIn, new S1APacketEntityStatus(entityIn, state));
}
public Explosion newExplosion(Entity entityIn, double x, double y, double z, float strength, boolean isFlaming, boolean isSmoking, boolean altSound) {
Explosion explosion = new Explosion(this, entityIn, x, y, z, strength, isFlaming, isSmoking);
explosion.doExplosionA();
explosion.doExplosionB(false, altSound);
if(!isSmoking) {
explosion.clearAffectedBlockPositions();
}
for(EntityNPC entityplayer : this.players) {
if(entityplayer.getDistanceSq(x, y, z) < 4096.0D) {
entityplayer.connection.sendPacket(new S27PacketExplosion(x, y, z, strength, explosion.getAffectedBlockPositions(),
(Vec3)explosion.getPlayerKnockbackMap().get(entityplayer), altSound));
}
}
return explosion;
}
public void addBlockEvent(BlockPos pos, Block blockIn, int eventID, int eventParam) {
BlockEventData blockeventdata = new BlockEventData(pos, blockIn, eventID, eventParam);
for(BlockEventData blockeventdata1 : this.queue[this.blockEvtIdx]) {
if(blockeventdata1.equals(blockeventdata)) {
return;
}
}
this.queue[this.blockEvtIdx].add(blockeventdata);
}
private void sendQueuedBlockEvents() {
while(!this.queue[this.blockEvtIdx].isEmpty()) {
int i = this.blockEvtIdx;
this.blockEvtIdx ^= 1;
for(BlockEventData blockeventdata : this.queue[i]) {
if(this.fireBlockEvent(blockeventdata)) {
this.server.sendNear((double)blockeventdata.getPosition().getX(), (double)blockeventdata.getPosition().getY(),
(double)blockeventdata.getPosition().getZ(), 64.0D, this.dimension.getDimensionId(),
new SPacketBlockAction(blockeventdata.getPosition(), blockeventdata.getBlock(), blockeventdata.getEventID(),
blockeventdata.getEventParameter()));
}
}
this.queue[i].clear();
}
}
private boolean fireBlockEvent(BlockEventData event) {
State iblockstate = this.getState(event.getPosition());
return iblockstate.getBlock() == event.getBlock()
? iblockstate.getBlock().onBlockEventReceived(this, event.getPosition(), iblockstate, event.getEventID(), event.getEventParameter())
: false;
}
public void resetWeather() {
this.calculateInitialWeather();
this.updateWeather(true);
}
public void setWeather(Weather weather) {
this.weather = weather;
// this.dataModified = true;
this.server.sendPacket(new S2BPacketChangeGameState(S2BPacketChangeGameState.Action.SET_WEATHER,
weather.getID()), this.dimension.getDimensionId());
}
protected void updateWeather(boolean force) {
// DimensionInfo dim = this.dimInfo;
// if(!this.dimension.hasNoSeasons()) {
// if(Config.seasonCycle && Config.seasonFlow > 0) {
// long time = dim.getSeasonTime();
// if(time <= 0L) {
// dim.setSeason(Season.getById(dim.getSeason().getIndex() + 1));
//// dim.setSeasonTime(dim.getSeason().getLength(this.dimension.getOrbitalPeriod()));
//// this.server.sendPacket(new S2BPacketChangeGameState(S2BPacketChangeGameState.Action.SET_SEASON,
//// dim.getSeason().getIndex()), this.dimension.getDimensionId());
// }
// else {
// this.dimInfo.setSeasonTime(time - (long)Config.seasonFlow);
// }
// }
// }
if((this.dimension.getType().weather && !this.exterminated) || force) {
float prevDarkness = this.darkness;
float prevRain = this.rain;
float prevFog = this.fog;
if(Config.weather && Config.weatherChance > 0) {
// int time = dim.getWeatherTime();
if(this.rand.chance(Config.weatherChance)) {
Weather nweather = Weather.pick(this.getBaseTemperature(), this.rand);
if(nweather != this.weather) {
// dim.setWeatherTime(this.rand.zrange(Config.weatherFlow) + Config.weatherFlow);
// }
// else {
// this.weather = nweather;
// this.dataModified = true;
this.setWeather(nweather);
// dim.setWeatherTime(this.rand.zrange(Config.weatherFlow * 14) + Config.weatherFlow);
// this.server.sendPacket(new S2BPacketChangeGameState(S2BPacketChangeGameState.Action.SET_WEATHER,
// this.weather.getID()), this.dimension.getDimensionId());
}
}
// else {
// dim.setWeatherTime(--time);
// }
}
if(this.weather.isDark()) {
this.darkness = (float)((double)this.darkness + 0.01D);
}
else {
this.darkness = (float)((double)this.darkness - 0.01D);
}
this.darkness = ExtMath.clampf(this.darkness, 0.0F, 1.0F);
if(this.weather.hasDownfall()) {
this.rain = (float)((double)this.rain + 0.01D);
}
else {
this.rain = (float)((double)this.rain - 0.01D);
}
this.rain = ExtMath.clampf(this.rain, 0.0F, 1.0F);
if(this.fog < this.weather.getFogIntensity()) {
this.fog = Math.min((float)((double)this.fog + 0.01D), this.weather.getFogIntensity());
}
else if(this.fog > this.weather.getFogIntensity()) {
this.fog = Math.max((float)((double)this.fog - 0.01D), this.weather.getFogIntensity());
}
if(prevRain != this.rain || force) {
this.server.sendPacket(new S2BPacketChangeGameState(S2BPacketChangeGameState.Action.RAIN_STRENGTH, this.rain), this.dimension.getDimensionId());
}
if(prevDarkness != this.darkness || force) {
this.server.sendPacket(new S2BPacketChangeGameState(S2BPacketChangeGameState.Action.DARKNESS, this.darkness), this.dimension.getDimensionId());
}
if(prevFog != this.fog || force) {
this.server.sendPacket(new S2BPacketChangeGameState(S2BPacketChangeGameState.Action.FOG_STRENGTH, this.fog), this.dimension.getDimensionId());
}
}
if((this.dimension.getType().days || (this.dimension.getType().weather && !this.exterminated)) || force) {
float prevTemp = this.temp;
float temp = this.getBaseTemperature() + this.weather.getTemperature();
if(this.temp < temp) {
this.temp = Math.min((float)((double)this.temp + 0.01D), temp);
}
else if(this.temp > temp) {
this.temp = Math.max((float)((double)this.temp - 0.01D), temp);
}
if(prevTemp != this.temp || force) {
this.server.sendPacket(new S2BPacketChangeGameState(S2BPacketChangeGameState.Action.TEMPERATURE, this.temp), this.dimension.getDimensionId());
}
}
// if(this.resetWeather)
// this.resetWeather = false;
}
public void spawnParticle(ParticleType particleType, double xCoord, double yCoord, double zCoord, int numberOfParticles, double xOffset,
double yOffset, double zOffset, double particleSpeed, int... particleArguments) {
this.spawnParticle(particleType, false, xCoord, yCoord, zCoord, numberOfParticles, xOffset, yOffset, zOffset, particleSpeed,
particleArguments);
}
public void spawnParticle(ParticleType particleType, boolean longDistance, double xCoord, double yCoord, double zCoord,
int numberOfParticles, double xOffset, double yOffset, double zOffset, double particleSpeed, int[] particleArguments) {
Packet packet = new S2APacketParticles(particleType, longDistance, (float)xCoord, (float)yCoord, (float)zCoord, (float)xOffset,
(float)yOffset, (float)zOffset, (float)particleSpeed, numberOfParticles, particleArguments);
for(int i = 0; i < this.players.size(); ++i) {
EntityNPC entityplayermp = this.players.get(i);
BlockPos blockpos = entityplayermp.getPosition();
double d0 = blockpos.distanceSq(xCoord, yCoord, zCoord);
if(d0 <= 256.0D || longDistance && d0 <= 65536.0D) {
entityplayermp.connection.sendPacket(packet);
}
}
}
protected boolean isLoaded(int x, int z, boolean allowEmpty) {
return this.chunkExists(x, z) && super.isLoaded(x, z, allowEmpty);
}
public Chunk getChunk(int x, int z) {
Chunk chunk = this.chunks.getValueByKey(LongHashMap.packInt(x, z));
return chunk == null ? this.loadChunk(x, z) : chunk;
}
private boolean chunkExists(int x, int z) {
return this.chunks.containsItem(LongHashMap.packInt(x, z));
}
public void dropChunk(int x, int z) {
long chunk = LongHashMap.packInt(x, z);
if(!this.loaders.containsItem(chunk))
this.dropped.add(Long.valueOf(chunk));
}
public void loadForcedChunks() {
for(BlockPos pos : this.loaderList) {
this.loadChunk(pos.getX() / 16, pos.getZ() / 16);
}
}
public void unloadAllChunks() {
for(Chunk chunk : this.loaded) {
this.dropChunk(chunk.xPos, chunk.zPos);
}
}
public Chunk loadChunk(int x, int z) {
long id = LongHashMap.packInt(x, z);
this.dropped.remove(Long.valueOf(id));
Chunk chunk = (Chunk)this.chunks.getValueByKey(id);
if(chunk == null) {
if(!this.debug)
chunk = this.loadChunkFromFile(x, z);
if(chunk == null) {
chunk = this.generate(x, z);
}
this.chunks.add(id, chunk);
this.loaded.add(chunk);
chunk.onChunkLoad();
this.popChunk(x, z);
}
return chunk;
}
private Chunk loadChunkFromFile(int x, int z) {
try {
ChunkPos coord = new ChunkPos(x, z);
NBTTagCompound tag = this.toRemove.get(coord);
if(tag == null) {
tag = Region.readChunk(this.chunkDir, x, z);
// DataInputStream in = ;
if(tag == null) {
return null;
}
// tag = CompressedStreamTools.read(in);
}
Chunk chunk = Region.readNbt(this, x, z, tag);
if(chunk != null) {
chunk.setSaved(this.time);
if(this.mineshaftGen != null) {
this.mineshaftGen.generate(this, x, z, null);
}
if(this.villageGen != null) {
this.villageGen.generate(this, x, z, null);
}
if(this.strongholdGen != null) {
this.strongholdGen.generate(this, x, z, null);
}
if(this.scatteredGen != null) {
this.scatteredGen.generate(this, x, z, null);
}
if(this.bridgeGen != null) {
this.bridgeGen.generate(this, x, z, null);
}
}
return chunk;
}
catch(Exception e) {
Log.JNI.error(e, "Konnte Chunk nicht laden");
return null;
}
}
private void saveChunkData(Chunk chunk) {
// try {
chunk.setSaved(this.time);
// this.lock.check();
try {
// NBTTagCompound ltag = new NBTTagCompound();
// tag.setTag("Level", ltag);
NBTTagCompound tag = Region.writeNbt(this, chunk);
ChunkPos coord = chunk.getPos();
if(!this.pending.contains(coord)) {
this.toRemove.put(coord, tag);
}
Region.queueIO(this);
}
catch(Exception e) {
Log.JNI.error(e, "Konnte Chunk nicht speichern");
}
// }
// catch(SaveException e) {
// Log.error("Konnte Chunk nicht speichern; bereits von einer anderen Instanz genutzt?", e);
// }
}
public boolean writeNextIO() {
if(this.toRemove.isEmpty()) {
// if(this.flushing) {
// Log.info(this.chunkDir + ": Alle Chunks sind gespeichert");
// }
return false;
}
else {
ChunkPos coord = this.toRemove.keySet().iterator().next();
boolean flag;
try {
this.pending.add(coord);
NBTTagCompound tag = this.toRemove.remove(coord);
if(tag != null) {
try {
// DataOutputStream out = RegionFile.getChunkOutputStream(this.chunkDir, coord.x, coord.z);
// CompressedStreamTools.write(tag, out);
// out.close();
Region.writeChunk(this.chunkDir, coord.x, coord.z, tag);
}
catch(Exception e) {
Log.JNI.error(e, "Konnte Chunk nicht speichern");
}
}
flag = true;
}
finally {
this.pending.remove(coord);
}
return flag;
}
}
// public void flushData() {
// if(!this.debug) {
// while(this.writeNextIO()) {
// ;
// }
// }
// }
public long getSeed() {
return this.seed;
}
public Random getRng(int x, int z, int seed) {
long i = (long)x * 341873128712L + (long)z * 132897987541L + this.seed + (long)seed;
this.rand.setSeed(i);
return this.rand;
}
// public void regenerateRegion(Set<Vector2D> chunks) {
// for(Vector2D coord : chunks) {
// long pos = LongHashMap.packInt(coord.getBlockX(), coord.getBlockZ());
// Chunk chunk;
// if(this.chunkExists(coord.getBlockX(), coord.getBlockZ())) {
// chunk = this.loadChunk(coord.getBlockX(), coord.getBlockZ());
// chunk.onChunkUnload();
// }
// this.dropped.remove(pos);
// this.chunks.remove(pos);
// chunk = this.generate(coord.getBlockX(), coord.getBlockZ());
// this.chunks.add(pos, chunk);
// this.loaded.add(chunk);
// chunk.onChunkLoad();
// this.popChunk(coord.getBlockX(), coord.getBlockZ());
// }
// }
private void popChunk(int x, int z) {
boolean n = this.chunkExists(x, z - 1);
boolean e = this.chunkExists(x + 1, z);
boolean s = this.chunkExists(x, z + 1);
boolean w = this.chunkExists(x - 1, z);
boolean nw = this.chunkExists(x - 1, z - 1);
boolean se = this.chunkExists(x + 1, z + 1);
boolean sw = this.chunkExists(x - 1, z + 1);
boolean ne = this.chunkExists(x + 1, z - 1);
if(e && s && se) {
this.populate(x, z);
}
if(w && s && sw) {
this.populate(x - 1, z);
}
if(n && e && ne) {
this.populate(x, z - 1);
}
if(nw && n && w) {
this.populate(x - 1, z - 1);
}
}
private void populate(int x, int z) {
Chunk chunk = this.getChunk(x, z);
if(!chunk.isTerrainPopulated()) {
chunk.checkLight();
BlockFalling.fallInstantly = true;
int bx = x * 16;
int bz = z * 16;
BlockPos pos = new BlockPos(bx, 0, bz);
Biome biome = Biome.BIOMES[this.getBiomeGenForCoords(pos.add(16, 0, 16)).id];
this.grng.setSeed(this.seed);
long sx = this.grng.longv() / 2L * 2L + 1L;
long sz = this.grng.longv() / 2L * 2L + 1L;
this.grng.setSeed((long)x * sx + (long)z * sz ^ this.seed);
boolean lakes = true;
ChunkPos coord = new ChunkPos(x, z);
if(this.bridgeGen != null) {
this.bridgeGen.generateStructure(this, this.grng, coord);
}
if(this.mineshaftGen != null) {
this.mineshaftGen.generateStructure(this, this.grng, coord);
}
if(this.villageGen != null) {
lakes = !this.villageGen.generateStructure(this, this.grng, coord);
}
if(this.strongholdGen != null) {
this.strongholdGen.generateStructure(this, this.grng, coord);
}
if(this.scatteredGen != null) {
this.scatteredGen.generateStructure(this, this.grng, coord);
}
if(lakes && this.lakes != null && biome.generateLakes) {
for(FeatureLakes lake : this.lakes) {
lake.generate(this, this.grng, pos);
}
}
if(this.dungeons != null) {
this.dungeons.generate(this, this.grng, pos);
}
if(this.ores != null) {
for(FeatureOres ore : this.ores) {
ore.generate(this, this.grng, pos);
}
}
if(this.populate) {
biome.decorate(this, this.grng, pos);
}
if(this.liquids != null && biome.generateLiquids) {
for(FeatureLiquids liquid : this.liquids) {
liquid.generate(this, this.grng, pos);
}
}
if(this.mobs && Config.mobs && Config.genSpawn) {
Spawner.generate(this, biome, bx + 8, bz + 8, 16, 16, this.grng);
}
// if(this.snow) {
pos = pos.add(8, 0, 8);
for(int fx = 0; fx < 16; ++fx) {
for(int fz = 0; fz < 16; ++fz) {
BlockPos snow = this.getPrecipitationHeight(pos.add(fx, 0, fz));
BlockPos ice = snow.down();
if(this.canBlockFreeze(ice, false)) {
this.setState(ice, Blocks.ice.getState(), 2);
}
if(this.snow && this.canSnowAt(snow, true, false)) {
this.setState(snow, Blocks.snow_layer.getState(), 2);
}
}
}
// }
BlockFalling.fallInstantly = false;
chunk.setModified();
}
}
private Chunk generate(int x, int z) {
this.grng.setSeed((long)x * 341873128712L + (long)z * 132897987541L);
ChunkPrimer primer = new ChunkPrimer(this.height);
this.generator.generateChunk(this, x, z, primer);
this.biomeGen.getChunkBiomes(this.biomes, x * 16, z * 16, 16, 16);
if(this.replacer != null) {
this.replacer.replaceBlocks(this, x, z, primer, this.grng, this.biomes);
}
if(this.caveGen != null) {
this.caveGen.generate(this, x, z, primer);
}
if(this.bigCaveGen != null) {
this.bigCaveGen.generate(this, x, z, primer);
}
if(this.ravineGen != null) {
this.ravineGen.generate(this, x, z, primer);
}
if(this.bridgeGen != null) {
this.bridgeGen.generate(this, x, z, primer);
}
if(this.mineshaftGen != null) {
this.mineshaftGen.generate(this, x, z, primer);
}
if(this.villageGen != null) {
this.villageGen.generate(this, x, z, primer);
}
if(this.strongholdGen != null) {
this.strongholdGen.generate(this, x, z, primer);
}
if(this.scatteredGen != null) {
this.scatteredGen.generate(this, x, z, primer);
}
return new Chunk(this, primer.getData(), primer.height, this.base, this.ceil, this.grng, this.biomes, x, z);
}
public boolean isExterminated() {
return this.exterminated;
}
public boolean exterminate() {
if(this.debug)
return true;
if(this.exterminated)
return false;
this.setWeather(Weather.CLEAR);
this.resetWeather();
// this.updateWeather();
if(!this.loaderList.isEmpty())
this.loadersModified = true;
for(BlockPos pos : this.loaderList) {
this.loaders.remove(LongHashMap.packInt(pos.getX() / 16, pos.getZ() / 16));
}
this.loaderList.clear();
for(Iterator<Entry<String, Position>> iter = this.server.getWarps().entrySet().iterator(); iter.hasNext();) {
Entry<String, Position> pos = iter.next();
if(pos.getValue().dim == this.dimension.getDimensionId())
iter.remove();
}
Region.finishWrite();
FileUtils.deleteFiles(this.chunkDir.listFiles(new FileFilter() {
public boolean accept(File file) {
return file.isDirectory();
}
}));
this.exterminated = true;
// this.dataModified = true;
for(Long v : this.dropped) {
Chunk chunk = this.chunks.getValueByKey(v.longValue());
if(chunk != null) {
chunk.onChunkUnload();
this.chunks.remove(v.longValue());
this.loaded.remove(chunk);
}
}
this.dropped.clear();
List<Chunk> loaded = Lists.<Chunk>newArrayList(this.loaded);
this.loaded.clear();
this.setExterminatedGen();
for(Chunk chunk : loaded) {
long pos = LongHashMap.packInt(chunk.xPos, chunk.zPos);
chunk.onChunkUnload();
this.chunks.remove(pos);
chunk = this.generate(chunk.xPos, chunk.zPos);
this.chunks.add(pos, chunk);
this.loaded.add(chunk);
chunk.onChunkLoad();
chunk.checkLight();
chunk.setModified();
}
for(Chunk chunk : this.loaded) {
chunk.update(false);
}
this.entities.removeAll(this.unloaded);
for(int l = 0; l < this.unloaded.size(); ++l) {
Entity ent = this.unloaded.get(l);
if(ent.isPlayer()) {
int i = ExtMath.floord(ent.posX / 16.0D);
int j = ExtMath.floord(ent.posZ / 16.0D);
this.getChunk(i, j).addEntity(ent);
this.entities.add(ent);
}
else {
this.onEntityRemoved(ent);
}
}
this.unloaded.clear();
for(int z = 0; z < this.instList.size(); ++z) {
this.instList.get(z).resend();
}
for(EntityNPC player : this.players) {
player.attackEntityFrom(DamageSource.causeExterminatusDamage(null), 5000);
Packet packet = new S2APacketParticles(ParticleType.EXPLOSION_HUGE, true,
(float)player.posX, (float)this.getSeaLevel() + 4.0f, (float)player.posZ, (float)128.0,
(float)2.0, (float)128.0, (float)0.15, 1000, new int[0]);
player.connection.sendPacket(packet);
packet = new S2APacketParticles(ParticleType.CLOUD, true,
(float)player.posX, (float)this.getSeaLevel() + 4.0f, (float)player.posZ, (float)128.0,
(float)2.0, (float)128.0, (float)0.15, 1000, new int[0]);
player.connection.sendPacket(packet);
packet = new S28PacketEffect(1025, new BlockPos(player.posX, (double)this.getSeaLevel() + 4.0, player.posZ), 0);
player.connection.sendPacket(packet);
}
return true;
}
private void setExterminatedGen() {
this.mobs = false;
this.snow = false;
this.caveGen = null;
this.bigCaveGen = null;
this.ravineGen = null;
this.strongholdGen = null;
this.villageGen = null;
this.villageStorage = null;
this.mineshaftGen = null;
this.scatteredGen = null;
this.bridgeGen = null;
this.generator = new GeneratorDestroyed(this.dimension.getSeaLevel());
this.biomeGen = new BiomeGenSingle(BaseBiome.EXTERMINATED);
this.replacer = null;
this.populate = false;
this.liquid = Blocks.air.getState();
this.base = Blocks.air.getState();
this.ceil = null;
this.height = this.generator.getMaximumHeight();
this.seaLevel = this.dimension.getSeaLevel();
this.ores = null;
this.lakes = null;
this.liquids = null;
this.dungeons = null;
}
public static String getLoadedInfo(Server server) {
int chunks = 0;
int entities = 0;
int tiles = 0;
int ticked = 0;
int forced = 0;
try {
Object[] worlds = server.getWorlds().toArray();
for(Object obj : worlds) {
WorldServer world = (WorldServer)obj;
chunks += world.chunks.getNumHashElements();
entities += world.entities.size();
tiles += world.tiles.size();
ticked += world.tickable.size();
forced += world.loaderList.size();
}
}
catch(Throwable e) {
}
return String.format("%d C, %d O, %d t, %d T, %d F", chunks, entities, tiles, ticked, forced);
}
public void forceBlockUpdateTick(Block blockType, BlockPos pos, Random random) {
this.updateForced = true;
blockType.updateTick(this, pos, this.getState(pos), random);
this.updateForced = false;
}
public Village getNearestVillage(BlockPos doorBlock, int radius) {
return this.villageStorage == null ? null : this.villageStorage.getNearestVillage(doorBlock, radius);
}
public void addToVillagerPositionList(BlockPos blockpos) {
if(this.villageStorage != null)
this.villageStorage.addToVillagerPositionList(blockpos);
}
public int getSeaLevel() {
return this.seaLevel;
}
public void playSound(SoundEvent sound, double x, double y, double z, float volume)
{
this.server.sendNear(x, y, z, volume > 1.0F ? (double)(16.0F * volume) : 16.0D, this.dimension.getDimensionId(), new S29PacketSoundEffect(sound, x, y, z, volume));
}
public void markBlockRangeForRenderUpdate(int x1, int y1, int z1, int x2, int y2, int z2)
{
}
protected void notifyLightSet(BlockPos pos)
{
}
public void playAuxSFX(EntityNPC player, int sfxType, BlockPos blockPosIn, int data)
{
this.server.sendNearExcept(player, (double)blockPosIn.getX(), (double)blockPosIn.getY(), (double)blockPosIn.getZ(), 64.0D, this.dimension.getDimensionId(), new S28PacketEffect(sfxType, blockPosIn, data));
}
// public void broadcastSound(int soundID, BlockPos pos, int data)
// {
// this.server.sendPacket(new S28PacketEffect(soundID, pos, data, true));
// }
public void sendBlockBreakProgress(int breakerId, BlockPos pos, int progress)
{
for (Player conn : this.server.getPlayers())
{
EntityNPC player = conn.getPresentEntity();
if (player != null && player.worldObj == this && player.getId() != breakerId)
{
double d0 = (double)pos.getX() - player.posX;
double d1 = (double)pos.getY() - player.posY;
double d2 = (double)pos.getZ() - player.posZ;
if (d0 * d0 + d1 * d1 + d2 * d2 < 1024.0D)
{
conn.sendPacket(new SPacketBlockBreakAnim(breakerId, pos, progress));
}
}
}
}
private void updatePlayerInstances() {
long time = this.time;
if(time - this.prevUpdate > 8000L) {
this.prevUpdate = time;
for(int z = 0; z < this.instList.size(); ++z) {
PlayerInstance inst = this.instList.get(z);
inst.onUpdate();
inst.processChunk();
}
}
else {
for(int z = 0; z < this.toUpdate.size(); ++z) {
PlayerInstance inst = this.toUpdate.get(z);
inst.onUpdate();
}
}
this.toUpdate.clear();
if(this.managed.isEmpty()) {
this.unloadAllChunks();
}
}
private boolean hasPlayerInstance(int chunkX, int chunkZ) {
long v = (long)chunkX + 2147483647L | (long)chunkZ + 2147483647L << 32;
return this.instances.getValueByKey(v) != null;
}
public boolean updateBiomes(int chunkX, int chunkZ) {
long v = (long)chunkX + 2147483647L | (long)chunkZ + 2147483647L << 32;
PlayerInstance ins = this.instances.getValueByKey(v);
if(ins == null)
return false;
Chunk chunk = this.getChunk(chunkX, chunkZ);
chunk.setModified();
ins.sendToAllPlayersWatchingChunk(new SPacketBiomes(chunkX, chunkZ, chunk.getBiomes()));
return true;
}
private PlayerInstance getPlayerInstance(int chunkX, int chunkZ, boolean create) {
long v = (long)chunkX + 2147483647L | (long)chunkZ + 2147483647L << 32;
PlayerInstance inst = this.instances.getValueByKey(v);
if(inst == null && create) {
inst = new PlayerInstance(chunkX, chunkZ);
this.instances.add(v, inst);
this.instList.add(inst);
}
return inst;
}
public void markBlockForUpdate(BlockPos pos) {
int x = pos.getX() >> 4;
int z = pos.getZ() >> 4;
PlayerInstance inst = this.getPlayerInstance(x, z, false);
if(inst != null) {
inst.flagChunkForUpdate(pos.getX() & 15, pos.getY(), pos.getZ() & 15);
}
}
public void addPlayer(EntityNPC player) {
int x = (int)player.posX >> 4;
int z = (int)player.posZ >> 4;
player.connection.setManagedPos(player.posX, player.posZ);
for(int cx = x - this.viewRadius; cx <= x + this.viewRadius; ++cx) {
for(int cz = z - this.viewRadius; cz <= z + this.viewRadius; ++cz) {
this.getPlayerInstance(cx, cz, true).addPlayer(player);
}
}
this.managed.add(player);
this.filterChunkLoadQueue(player);
}
private void filterChunkLoadQueue(EntityNPC player) {
List<ChunkPos> list = Lists.newArrayList(player.connection.getLoadedChunkList());
int p = 0;
int r = this.viewRadius;
int x = (int)player.posX >> 4;
int z = (int)player.posZ >> 4;
int cx = 0;
int cz = 0;
ChunkPos pos = this.getPlayerInstance(x, z, true).position;
player.connection.getLoadedChunkList().clear();
if(list.contains(pos)) {
player.connection.getLoadedChunkList().add(pos);
}
for(int n = 1; n <= r * 2; ++n) {
for(int m = 0; m < 2; ++m) {
int[] dirs = XZ_DIRS[p++ % 4];
for(int o = 0; o < n; ++o) {
cx += dirs[0];
cz += dirs[1];
pos = this.getPlayerInstance(x + cx, z + cz, true).position;
if(list.contains(pos)) {
player.connection.getLoadedChunkList().add(pos);
}
}
}
}
p = p % 4;
for(int n = 0; n < r * 2; ++n) {
cx += XZ_DIRS[p][0];
cz += XZ_DIRS[p][1];
pos = this.getPlayerInstance(x + cx, z + cz, true).position;
if(list.contains(pos)) {
player.connection.getLoadedChunkList().add(pos);
}
}
}
public void removePlayer(EntityNPC player) {
int x = (int)player.connection.getManagedX() >> 4;
int z = (int)player.connection.getManagedZ() >> 4;
for(int cx = x - this.viewRadius; cx <= x + this.viewRadius; ++cx) {
for(int cz = z - this.viewRadius; cz <= z + this.viewRadius; ++cz) {
PlayerInstance inst = this.getPlayerInstance(cx, cz, false);
if(inst != null) {
inst.removePlayer(player);
}
}
}
this.managed.remove(player);
}
private boolean overlaps(int x1, int z1, int x2, int z2, int radius) {
int dx = x1 - x2;
int dz = z1 - z2;
return dx >= -radius && dx <= radius ? dz >= -radius && dz <= radius : false;
}
public void updateMountedMovingPlayer(EntityNPC player) {
int x = (int)player.posX >> 4;
int z = (int)player.posZ >> 4;
double dx = player.connection.getManagedX() - player.posX;
double dz = player.connection.getManagedZ() - player.posZ;
double dist = dx * dx + dz * dz;
if(dist >= 64.0D) {
int px = (int)player.connection.getManagedX() >> 4;
int pz = (int)player.connection.getManagedZ() >> 4;
int r = this.viewRadius;
int mx = x - px;
int mz = z - pz;
if(mx != 0 || mz != 0) {
for(int cx = x - r; cx <= x + r; ++cx) {
for(int cz = z - r; cz <= z + r; ++cz) {
if(!this.overlaps(cx, cz, px, pz, r)) {
this.getPlayerInstance(cx, cz, true).addPlayer(player);
}
if(!this.overlaps(cx - mx, cz - mz, x, z, r)) {
PlayerInstance inst = this.getPlayerInstance(cx - mx, cz - mz, false);
if(inst != null) {
inst.removePlayer(player);
}
}
}
}
this.filterChunkLoadQueue(player);
player.connection.setManagedPos(player.posX, player.posZ);
}
}
}
public boolean isPlayerWatchingChunk(EntityNPC player, int chunkX, int chunkZ) {
PlayerInstance inst = this.getPlayerInstance(chunkX, chunkZ, false);
return inst != null && inst.watching.contains(player) && !player.connection.getLoadedChunkList().contains(inst.position);
}
public void updateViewRadius() {
int radius = ExtMath.clampi(Config.distance, 3, 128);
if(radius != this.viewRadius) {
int diff = radius - this.viewRadius;
for(EntityNPC player : Lists.newArrayList(this.managed)) {
int x = (int)player.posX >> 4;
int z = (int)player.posZ >> 4;
if(diff > 0) {
for(int cx = x - radius; cx <= x + radius; ++cx) {
for(int cz = z - radius; cz <= z + radius; ++cz) {
PlayerInstance inst = this.getPlayerInstance(cx, cz, true);
if(!inst.watching.contains(player)) {
inst.addPlayer(player);
}
}
}
}
else {
for(int cx = x - this.viewRadius; cx <= x + this.viewRadius; ++cx) {
for(int cz = z - this.viewRadius; cz <= z + this.viewRadius; ++cz) {
if(!this.overlaps(cx, cz, x, z, radius)) {
this.getPlayerInstance(cx, cz, true).removePlayer(player);
}
}
}
}
}
this.viewRadius = radius;
}
this.trackDistance = Config.distance * 16 - 16;
}
public void trackEntity(Entity entityIn) {
if(entityIn.getUpdateFrequency() > 0) {
this.addEntityToTracker(entityIn, entityIn.getTrackingRange(), entityIn.getUpdateFrequency(), entityIn.isSendingVeloUpdates());
}
if(entityIn.isPlayer()) {
// this.trackEntity(entityIn, 512, 2);
EntityNPC entityplayermp = (EntityNPC)entityIn;
for(EntityTrackerEntry entitytrackerentry : this.tracked) {
if(entitytrackerentry.trackedEntity != entityplayermp) {
entitytrackerentry.updatePlayerEntity(entityplayermp);
}
}
}
}
private void addEntityToTracker(Entity entityIn, int trackingRange, final int updateFrequency, boolean sendVelocityUpdates) {
if(trackingRange > this.trackDistance) {
trackingRange = this.trackDistance;
}
try {
if(this.trackMap.containsItem(entityIn.getId())) {
throw new IllegalStateException("Objekt ist bereits auf der Tracking-Liste!");
}
EntityTrackerEntry entitytrackerentry = new EntityTrackerEntry(entityIn, trackingRange, updateFrequency, sendVelocityUpdates);
this.tracked.add(entitytrackerentry);
this.trackMap.addKey(entityIn.getId(), entitytrackerentry);
entitytrackerentry.updatePlayerEntities(this.players);
}
catch(Throwable throwable) {
Log.JNI.error((Throwable)throwable, (String)"Fange Objekt-Tracking-Fehler \"leise\" auf.");
}
}
public void untrackEntity(Entity entityIn) {
if(entityIn.isPlayer()) {
EntityNPC entityplayermp = (EntityNPC)entityIn;
for(EntityTrackerEntry entitytrackerentry : this.tracked) {
entitytrackerentry.removeFromTrackedPlayers(entityplayermp);
}
}
EntityTrackerEntry entitytrackerentry1 = (EntityTrackerEntry)this.trackMap.removeObject(entityIn.getId());
if(entitytrackerentry1 != null) {
this.tracked.remove(entitytrackerentry1);
entitytrackerentry1.sendDestroyEntityPacketToTrackedPlayers();
}
}
public void updateTrackedEntities() {
List<EntityNPC> list = Lists.<EntityNPC>newArrayList();
for(EntityTrackerEntry entitytrackerentry : this.tracked) {
entitytrackerentry.updatePlayerList(this.players);
if(entitytrackerentry.isUpdated() && entitytrackerentry.trackedEntity.isPlayer()) {
list.add((EntityNPC)entitytrackerentry.trackedEntity);
}
}
for(int i = 0; i < ((List)list).size(); ++i) {
EntityNPC entityplayermp = list.get(i);
for(EntityTrackerEntry entitytrackerentry1 : this.tracked) {
if(entitytrackerentry1.trackedEntity != entityplayermp) {
entitytrackerentry1.updatePlayerEntity(entityplayermp);
}
}
}
}
public void updateTrackedPlayer(EntityNPC player) {
for(EntityTrackerEntry entitytrackerentry : this.tracked) {
if(entitytrackerentry.trackedEntity == player) {
entitytrackerentry.updatePlayerEntities(this.players);
}
else {
entitytrackerentry.updatePlayerEntity(player);
}
}
}
public void sendToAllTrackingEntity(Entity entityIn, Packet packet) {
EntityTrackerEntry entitytrackerentry = (EntityTrackerEntry)this.trackMap.lookup(entityIn.getId());
if(entitytrackerentry != null) {
entitytrackerentry.sendPacketToTrackedPlayers(packet);
}
}
public void sendToAllTrackingAndSelf(Entity entityIn, Packet packet) {
EntityTrackerEntry entitytrackerentry = (EntityTrackerEntry)this.trackMap.lookup(entityIn.getId());
if(entitytrackerentry != null) {
entitytrackerentry.sendPacketToTrackedAndSelf(packet);
}
}
public void removePlayerFromTrackers(EntityNPC player) {
for(EntityTrackerEntry entitytrackerentry : this.tracked) {
entitytrackerentry.removeTrackedPlayerSymmetric(player);
}
}
public void updateChunksForPlayer(EntityNPC player, Chunk chunk) {
for(EntityTrackerEntry entitytrackerentry : this.tracked) {
if(entitytrackerentry.trackedEntity != player && entitytrackerentry.trackedEntity.chunkCoordX == chunk.xPos
&& entitytrackerentry.trackedEntity.chunkCoordZ == chunk.zPos) {
entitytrackerentry.updatePlayerEntity(player);
}
}
}
public final boolean setBlock(BlockPos pos, ClipboardBlock block) {
// int x = position.getBlockX();
// int y = position.getBlockY();
// int z = position.getBlockZ();
Chunk chunk = this.getChunk(pos.getX() >> 4, pos.getZ() >> 4);
// BlockPos pos = new BlockPos(x, y, z);
State old = chunk.getState(pos);
State newState = block.getState();
if(newState.getBlock() instanceof BlockDoor) {
if(newState.getValue(BlockDoor.HALF) == BlockDoor.EnumDoorHalf.LOWER) {
ItemDoor.placeDoor(this, pos, newState.getValue(BlockDoor.FACING)/* .rotateYCCW() */, newState.getBlock(), false);
}
return true;
}
State successState = chunk.setState(pos, newState);
boolean successful = successState != null;
if(successful) {
if(block.getNbtData() != null) {
this.removeTileEntity(pos);
NBTTagCompound tag = block.getNbtData();
tag.setString("id", tag.getString("id"));
tag.setTag("x", new NBTTagInt(pos.getX()));
tag.setTag("y", new NBTTagInt(pos.getY()));
tag.setTag("z", new NBTTagInt(pos.getZ()));
TileEntity tileEntity = TileEntity.createAndLoadEntity(tag);
if(tileEntity != null) {
this.setTileEntity(pos, tileEntity);
}
}
}
// if(update) {
// if(!successful)
// newState = old;
this.checkLight(pos);
if(chunk.isPopulated())
this.markBlockForUpdate(pos);
// this.notifyNeighborsRespectDebug(pos, old.getBlock());
// if(newState.getBlock().hasComparatorInputOverride())
// this.updateComparatorOutputLevel(pos, newState.getBlock());
// }
// else {
// this.markBlockForUpdate(pos);
// }
return successful;
}
public final ClipboardBlock getBlock(BlockPos pos) {
// BlockPos pos = new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ());
State state = this.getState(pos);
TileEntity tile = this.getTileEntity(pos);
if(tile != null) {
return new ClipboardBlock(state, tile);
}
else {
return new ClipboardBlock(state);
}
}
// public final EditBlock getLazyBlock(Vector position) {
// State state = this.getState(new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ()));
// return new LazyBlock(state, this, position);
// }
public final boolean setBiome(BlockPos position, BaseBiome biome) {
Chunk chunk = this.getChunk(position);
if((chunk != null) && (chunk.isLoaded())) {
chunk.getBiomes()[((position.getZ() & 0xF) << 4 | position.getX() & 0xF)] = (byte)biome.id;
return true;
}
return false;
}
public final void setBiomes(BlockPos start, BlockPos end, BaseBiome biome) {
Set<ChunkPos> chunks = Sets.newHashSet();
for(int x = start.getX(); x <= end.getX(); x++) {
for(int z = start.getZ(); z <= end.getZ(); z++) {
if(this.setBiome(new BlockPos(x, 0, z), biome))
chunks.add(new ChunkPos(x >> 4, z >> 4));
}
}
for(ChunkPos pos : chunks) {
this.updateBiomes(pos.x, pos.z);
}
chunks.clear();
}
// public final List<? extends Entity> getEntities(EditRegion region) {
// List<Entity> entities = Lists.newArrayList();
// for(Entity entity : this.entities) {
// if(region.contains(new Vector(entity.posX, entity.posY, entity.posZ))) {
// entities.add(entity);
// }
// }
// return entities;
// }
public final List<? extends Entity> getEntities() {
List<Entity> entities = Lists.newArrayList();
for(Entity entity : this.entities) {
entities.add(entity);
}
return entities;
}
public boolean isDaytime() {
return this.subtract < 4;
}
public int getSkylightSubtracted() {
return this.subtract;
}
public void setSkylightSubtracted(int newSkylightSubtracted) {
this.subtract = newSkylightSubtracted;
}
public boolean isBlockinHighHumidity(BlockPos pos) {
BaseBiome biomegenbase = this.getBiomeGenForCoords(pos);
return biomegenbase.isHighHumidity();
}
public boolean canStrikeAt(BlockPos strikePosition) {
if(!this.canSeeSky(strikePosition)) {
return false;
}
else if(this.getPrecipitationHeight(strikePosition).getY() > strikePosition.getY()) {
return false;
}
return true;
// else {
// Biome biomegenbase = this.getBiomeGenForCoords(strikePosition);
// return biomegenbase.canRain() || biomegenbase.isSnowyBiome();
// }
}
public int countEntities(Class<?> entityType) {
int i = 0;
for(Entity entity : this.entities) {
if( // (!(entity instanceof EntityLiving) || !((EntityLiving)entity).isNotDespawning())
/* && */ entityType.isAssignableFrom(entity.getClass())) {
++i;
}
}
return i;
}
// public Entity getEntityByPID(long id) {
// for(Entity entity : this.entities) {
// if(entity.hasPersistentId() && entity.getPersistentId() == id) {
// return entity;
// }
// }
// return null;
// }
public <T extends Entity> T findNearestEntityWithinAABB(Class<? extends T> entityType, BoundingBox aabb, T closestTo) {
List<T> list = this.<T>getEntitiesWithinAABB(entityType, aabb);
T t = null;
double d0 = Double.MAX_VALUE;
for(int i = 0; i < list.size(); ++i) {
T t1 = list.get(i);
if(t1 != closestTo) { // && EntitySelectors.NOT_SPECTATING.apply(t1)) {
double d1 = closestTo.getDistanceSqToEntity(t1);
if(d1 <= d0) {
t = t1;
d0 = d1;
}
}
}
return t;
}
public boolean canPlaceFireAt(BlockPos pos) {
if(!this.canBurnAt(pos)) {
return false;
}
if(pos.getY() >= 0 && pos.getY() < 512) {
Block block = this.getState(pos).getBlock();
if(block.getMaterial() == Material.air && Blocks.fire.canPlaceBlockAt(this, pos)) {
return true;
}
}
return false;
}
public boolean canBlockFreeze(BlockPos pos, boolean noWaterAdj) {
if(!this.canFreezeAt(pos)) {
return false;
}
else {
if(pos.getY() >= 0 && pos.getY() < 512 && this.getLightFor(LightType.BLOCK, pos) < 10) {
State iblockstate = this.getState(pos);
Block block = iblockstate.getBlock();
if((block == Blocks.water || block == Blocks.flowing_water) && ((Integer)iblockstate.getValue(BlockLiquid.LEVEL)).intValue() == 0) {
if(!noWaterAdj) {
return true;
}
boolean flag = this.getState(pos.west()).getBlock().getMaterial() == Material.water &&
this.getState(pos.east()).getBlock().getMaterial() == Material.water &&
this.getState(pos.north()).getBlock().getMaterial() == Material.water &&
this.getState(pos.south()).getBlock().getMaterial() == Material.water;
if(!flag) {
return true;
}
}
}
return false;
}
}
public boolean checkBlockCollision(BoundingBox bb) {
int i = ExtMath.floord(bb.minX);
int j = ExtMath.floord(bb.maxX);
int k = ExtMath.floord(bb.minY);
int l = ExtMath.floord(bb.maxY);
int i1 = ExtMath.floord(bb.minZ);
int j1 = ExtMath.floord(bb.maxZ);
BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos();
for(int k1 = i; k1 <= j; ++k1) {
for(int l1 = k; l1 <= l; ++l1) {
for(int i2 = i1; i2 <= j1; ++i2) {
Block block = this.getState(blockpos$mutableblockpos.set(k1, l1, i2)).getBlock();
if(block.getMaterial() != Material.air) {
return true;
}
}
}
}
return false;
}
public BlockPos getTopSolidOrLiquidBlock(BlockPos pos) {
Chunk chunk = this.getChunk(pos);
BlockPos blockpos;
BlockPos blockpos1;
for(blockpos = new BlockPos(pos.getX(), chunk.getTopSegment() + 16, pos.getZ()); blockpos.getY() >= 0; blockpos = blockpos1) {
blockpos1 = blockpos.down();
Material material = chunk.getBlock(blockpos1).getMaterial();
if(material.blocksMovement() && material != Material.leaves) {
break;
}
}
return blockpos;
}
public void removePlayerEntityDangerously(Entity entityIn) {
entityIn.setDead();
if(entityIn.isPlayer()) {
this.players.remove(entityIn);
}
int i = entityIn.chunkCoordX;
int j = entityIn.chunkCoordZ;
if(entityIn.addedToChunk && this.isLoaded(i, j, true)) {
this.getChunk(i, j).removeEntity(entityIn);
}
this.entities.remove(entityIn);
this.onEntityRemoved(entityIn);
}
public Block getGroundAboveSeaLevel(BlockPos pos) {
BlockPos blockpos;
for(blockpos = new BlockPos(pos.getX(), this.getSeaLevel(), pos.getZ()); !this.isAirBlock(blockpos.up()); blockpos = blockpos.up()) {
;
}
return this.getState(blockpos).getBlock();
}
public long getTime() {
return this.time;
}
private File getSaveFile(String id) {
return new File(this.chunkDir, id.toLowerCase() + ".nbt");
}
private WorldSavedData loadData(String id) {
WorldSavedData data = this.dataMap.get(id);
if(data != null)
return data;
try {
File file = this.getSaveFile(id);
if(file.exists()) {
// try {
data = new WorldSavedData(id, NBTLoader.readGZip(file));
// }
// catch(Exception re) {
// throw new RuntimeException("Konnte " + clazz.toString() + " nicht instanzieren", re);
// }
// FileInputStream in = new FileInputStream(file);
// NBTTagCompound tag = ;
// in.close();
// data.readFromNBT(tag.getCompoundTag("data"));
}
}
catch(Exception e) {
e.printStackTrace();
}
if(data != null) {
this.dataMap.put(id, data);
this.dataList.add(data);
}
return data;
}
private void setData(String id, WorldSavedData data) {
if(this.dataMap.containsKey(id)) {
this.dataList.remove(this.dataMap.remove(id));
}
this.dataMap.put(id, data);
this.dataList.add(data);
}
private void saveData(WorldSavedData data) {
try {
File file = this.getSaveFile(data.id);
// NBTTagCompound tag = new NBTTagCompound();
// data.writeToNBT(tag);
// NBTTagCompound dtag = new NBTTagCompound();
// dtag.setTag("data", tag);
// FileOutputStream out = new FileOutputStream(file);
NBTLoader.writeGZip(data.tag, file);
// out.close();
}
catch(Exception e) {
e.printStackTrace();
}
}
// public boolean canBlockSeeSky(BlockPos pos) {
// if(pos.getY() >= this.getSeaLevel()) {
// return this.canSeeSky(pos);
// }
// else {
// BlockPos blockpos = new BlockPos(pos.getX(), this.getSeaLevel(), pos.getZ());
//
// if(!this.canSeeSky(blockpos)) {
// return false;
// }
// else {
// for(blockpos = blockpos.down(); blockpos.getY() > pos.getY(); blockpos = blockpos.down()) {
// Block block = this.getBlockState(blockpos).getBlock();
//
// if(block.getLightOpacity() > 0 && !block.getMaterial().isLiquid()) {
// return false;
// }
// }
//
// return true;
// }
// }
// }
public boolean makePortal(BlockPos pos, int maxHeight, PortalType type) // TODO: Portals
{
return false;
// int i = 16;
// double d0 = -1.0D;
// int j = pos.getX();
// int k = pos.getY();
// int l = pos.getZ();
// int i1 = j;
// int j1 = k;
// int k1 = l;
// int l1 = 0;
// int i2 = world.rand.zrange(4);
// BlockPos.MutableBlockPos bpos = new BlockPos.MutableBlockPos();
//
// for (int j2 = j - i; j2 <= j + i; ++j2)
// {
// double d1 = (double)j2 + 0.5D - (double)j;
//
// for (int l2 = l - i; l2 <= l + i; ++l2)
// {
// double d2 = (double)l2 + 0.5D - (double)l;
// label142:
//
// for (int j3 = maxHeight - 1; j3 >= 0; --j3)
// {
// if (world.isAirBlock(bpos.set(j2, j3, l2)))
// {
// while (j3 > 0 && world.isAirBlock(bpos.set(j2, j3 - 1, l2)))
// {
// --j3;
// }
//
// for (int k3 = i2; k3 < i2 + 4; ++k3)
// {
// int l3 = k3 % 2;
// int i4 = 1 - l3;
//
// if (k3 % 4 >= 2)
// {
// l3 = -l3;
// i4 = -i4;
// }
//
// for (int j4 = 0; j4 < 3; ++j4)
// {
// for (int k4 = 0; k4 < 4; ++k4)
// {
// for (int l4 = -1; l4 < 4; ++l4)
// {
// int i5 = j2 + (k4 - 1) * l3 + j4 * i4;
// int j5 = j3 + l4;
// int k5 = l2 + (k4 - 1) * i4 - j4 * l3;
// bpos.set(i5, j5, k5);
//
// if (l4 < 0 && !world.getBlockState(bpos).getBlock().getMaterial().isSolid()
// || l4 >= 0 && !world.isAirBlock(bpos))
// {
// continue label142;
// }
// }
// }
// }
//
// double d5 = (double)j3 + 0.5D - (double)k;
// double d7 = d1 * d1 + d5 * d5 + d2 * d2;
//
// if (d0 < 0.0D || d7 < d0)
// {
// d0 = d7;
// i1 = j2;
// j1 = j3;
// k1 = l2;
// l1 = k3 % 4;
// }
// }
// }
// }
// }
// }
//
// if (d0 < 0.0D)
// {
// for (int l5 = j - i; l5 <= j + i; ++l5)
// {
// double d3 = (double)l5 + 0.5D - (double)j;
//
// for (int j6 = l - i; j6 <= l + i; ++j6)
// {
// double d4 = (double)j6 + 0.5D - (double)l;
// label562:
//
// for (int i7 = maxHeight - 1; i7 >= 0; --i7)
// {
// if (world.isAirBlock(bpos.set(l5, i7, j6)))
// {
// while (i7 > 0 && world.isAirBlock(bpos.set(l5, i7 - 1, j6)))
// {
// --i7;
// }
//
// for (int k7 = i2; k7 < i2 + 2; ++k7)
// {
// int j8 = k7 % 2;
// int j9 = 1 - j8;
//
// for (int j10 = 0; j10 < 4; ++j10)
// {
// for (int j11 = -1; j11 < 4; ++j11)
// {
// int j12 = l5 + (j10 - 1) * j8;
// int i13 = i7 + j11;
// int j13 = j6 + (j10 - 1) * j9;
// bpos.set(j12, i13, j13);
//
// if (j11 < 0 && !world.getBlockState(bpos).getBlock().getMaterial().isSolid()
// || j11 >= 0 && !world.isAirBlock(bpos))
// {
// continue label562;
// }
// }
// }
//
// double d6 = (double)i7 + 0.5D - (double)k;
// double d8 = d3 * d3 + d6 * d6 + d4 * d4;
//
// if (d0 < 0.0D || d8 < d0)
// {
// d0 = d8;
// i1 = l5;
// j1 = i7;
// k1 = j6;
// l1 = k7 % 2;
// }
// }
// }
// }
// }
// }
// }
//
// int i6 = i1;
// int k2 = j1;
// int k6 = k1;
// int l6 = l1 % 2;
// int i3 = 1 - l6;
//
// if (l1 % 4 >= 2)
// {
// l6 = -l6;
// i3 = -i3;
// }
//
// if (d0 < 0.0D)
// {
// j1 = MathHelper.clamp_int(j1, 70, maxHeight - 10);
// k2 = j1;
//
// for (int j7 = -1; j7 <= 1; ++j7)
// {
// for (int l7 = 1; l7 < 3; ++l7)
// {
// for (int k8 = -1; k8 < 3; ++k8)
// {
// int k9 = i6 + (l7 - 1) * l6 + j7 * i3;
// int k10 = k2 + k8;
// int k11 = k6 + (l7 - 1) * i3 - j7 * l6;
// boolean flag = k8 < 0;
// world.setBlockState(new BlockPos(k9, k10, k11), flag ? Blocks.obsidian.getDefaultState() :
// Blocks.air.getDefaultState());
// }
// }
// }
// }
//
// IBlockState state = Blocks.portal.getDefaultState().withProperty(BlockPortal.AXIS, l6 != 0 ? EnumFacing.Axis.X :
// EnumFacing.Axis.Z).withProperty(BlockPortal.DIM, dim);
//
// for (int i8 = 0; i8 < 4; ++i8)
// {
// for (int l8 = 0; l8 < 4; ++l8)
// {
// for (int l9 = -1; l9 < 4; ++l9)
// {
// int l10 = i6 + (l8 - 1) * l6;
// int l11 = k2 + l9;
// int k12 = k6 + (l8 - 1) * i3;
// boolean flag1 = l8 == 0 || l8 == 3 || l9 == -1 || l9 == 3;
// world.setBlockState(new BlockPos(l10, l11, k12), flag1 ? Blocks.obsidian.getDefaultState() : state, 2);
// }
// }
//
// for (int i9 = 0; i9 < 4; ++i9)
// {
// for (int i10 = -1; i10 < 4; ++i10)
// {
// int i11 = i6 + (i9 - 1) * l6;
// int i12 = k2 + i10;
// int l12 = k6 + (i9 - 1) * i3;
// BlockPos blockpos = new BlockPos(i11, i12, l12);
// world.notifyNeighborsOfStateChange(blockpos, world.getBlockState(blockpos).getBlock());
// }
// }
// }
//
// return true;
}
public List<IPlayer> getAllPlayers() {
return (List)this.server.getPlayers();
}
public void placeInDimension(Entity entity, AWorldServer oldWorld, AWorldServer world, BlockPos pos, PortalType portal) {
this.server.placeInDimension(entity, (WorldServer)oldWorld, (WorldServer)world, pos, portal);
}
public AWorldServer getOtherWorld(int dimension) {
return this.server.getWorld(dimension);
}
private static class EventList extends ArrayList<BlockEventData> {
private EventList() {
}
}
public static class WorldSavedData {
public final String id;
public final NBTTagCompound tag;
public boolean dirty;
public WorldSavedData(String id, NBTTagCompound tag) {
this.id = id;
this.tag = tag;
}
}
private class PlayerInstance {
private final List<EntityNPC> watching = Lists.<EntityNPC>newArrayList();
private final ChunkPos position;
private int[] changes = new int[64];
private int updates;
private int sections;
private long prevTime;
private boolean biomes;
public PlayerInstance(int chunkX, int chunkZ) {
this.position = new ChunkPos(chunkX, chunkZ);
WorldServer.this.loadChunk(chunkX, chunkZ);
}
public void addPlayer(EntityNPC player) {
if(this.watching.contains(player)) {
Log.JNI.warn("Konnte Spieler nicht hinzufügen. #" + player.getId() + " ist bereits in Chunk " + this.position.x + ", "
+ this.position.z);
}
else {
if(this.watching.isEmpty()) {
this.prevTime = WorldServer.this.time;
}
this.watching.add(player);
player.connection.getLoadedChunkList().add(this.position);
}
}
public void removePlayer(EntityNPC player) {
if(this.watching.contains(player)) {
Chunk chunk = WorldServer.this.getChunk(this.position.x, this.position.z);
if(chunk.isPopulated()) {
player.connection.sendPacket(new SPacketChunkData(chunk, true, 0));
}
this.watching.remove(player);
player.connection.getLoadedChunkList().remove(this.position);
if(this.watching.isEmpty()) {
long v = (long)this.position.x + 2147483647L | (long)this.position.z + 2147483647L << 32;
this.increaseInhabitedTime(chunk);
WorldServer.this.instances.remove(v);
WorldServer.this.instList.remove(this);
if(this.updates > 0) {
WorldServer.this.toUpdate.remove(this);
}
WorldServer.this.dropChunk(this.position.x, this.position.z);
}
}
}
public void processChunk() {
this.increaseInhabitedTime(WorldServer.this.getChunk(this.position.x, this.position.z));
}
public void resend() {
if(this.updates == 0)
WorldServer.this.toUpdate.add(this);
this.updates = 64;
this.sections = 0xffffffff;
this.biomes = true;
}
private void increaseInhabitedTime(Chunk chunk) {
chunk.setInhabited(chunk.getInhabited() + WorldServer.this.time - this.prevTime);
this.prevTime = WorldServer.this.time;
}
public void flagChunkForUpdate(int x, int y, int z) {
if(this.updates == 0) {
WorldServer.this.toUpdate.add(this);
}
this.sections |= 1 << (y >> 4);
if(this.updates < 64) {
int pos = x << 13 | z << 9 | y;
for(int i = 0; i < this.updates; ++i) {
if(this.changes[i] == pos) {
return;
}
}
this.changes[this.updates++] = pos;
}
}
public void sendToAllPlayersWatchingChunk(Packet packet) {
for(int z = 0; z < this.watching.size(); ++z) {
EntityNPC player = this.watching.get(z);
if(!player.connection.getLoadedChunkList().contains(this.position)) {
player.connection.sendPacket(packet);
}
}
}
public void onUpdate() {
if(this.updates != 0) {
if(this.updates == 1) {
int x = (this.changes[0] >> 13 & 15) + this.position.x * 16;
int y = this.changes[0] & 511;
int z = (this.changes[0] >> 9 & 15) + this.position.z * 16;
BlockPos pos = new BlockPos(x, y, z);
this.sendToAllPlayersWatchingChunk(new SPacketBlockChange(WorldServer.this, pos));
if(WorldServer.this.getState(pos).getBlock().hasTileEntity()) {
this.sendTileToAllPlayersWatchingChunk(WorldServer.this.getTileEntity(pos));
}
}
else if(this.updates == 64) {
int x = this.position.x * 16;
int z = this.position.z * 16;
this.sendToAllPlayersWatchingChunk(new SPacketChunkData(WorldServer.this.getChunk(this.position.x, this.position.z),
this.biomes, this.sections));
for(int cy = 0; cy < 32; ++cy) {
if((this.sections & 1 << cy) != 0) {
int y = cy << 4;
List<TileEntity> list = WorldServer.this.getTileEntitiesIn(x, y, z, x + 16, y + 16, z + 16);
for(int n = 0; n < list.size(); ++n) {
this.sendTileToAllPlayersWatchingChunk(list.get(n));
}
}
}
}
else {
this.sendToAllPlayersWatchingChunk(new SPacketMultiBlockChange(this.updates, this.changes,
WorldServer.this.getChunk(this.position.x, this.position.z)));
for(int n = 0; n < this.updates; ++n) {
int x = (this.changes[n] >> 13 & 15) + this.position.x * 16;
int y = this.changes[n] & 511;
int z = (this.changes[n] >> 9 & 15) + this.position.z * 16;
BlockPos pos = new BlockPos(x, y, z);
if(WorldServer.this.getState(pos).getBlock().hasTileEntity()) {
this.sendTileToAllPlayersWatchingChunk(WorldServer.this.getTileEntity(pos));
}
}
}
this.updates = 0;
this.sections = 0;
this.biomes = false;
}
}
private void sendTileToAllPlayersWatchingChunk(TileEntity te) {
if(te != null) {
Packet packet = te.getDescriptionPacket();
if(packet != null) {
this.sendToAllPlayersWatchingChunk(packet);
}
}
}
}
}