/** Populate a single chunk if needed. */ private void populateChunk(int x, int z, boolean force) { GlowChunk chunk = getChunk(x, z); // cancel out if it's already populated if (chunk.isPopulated()) { return; } // cancel out if the 3x3 around it isn't available for (int x2 = x - 1; x2 <= x + 1; ++x2) { for (int z2 = z - 1; z2 <= z + 1; ++z2) { if (!getChunk(x2, z2).isLoaded() && (!force || !loadChunk(x2, z2, true))) { return; } } } // it might have loaded since before, so check again that it's not already populated if (chunk.isPopulated()) { return; } chunk.setPopulated(true); Random random = new Random(world.getSeed()); long xRand = random.nextLong() / 2 * 2 + 1; long zRand = random.nextLong() / 2 * 2 + 1; random.setSeed((long) x * xRand + (long) z * zRand ^ world.getSeed()); for (BlockPopulator p : world.getPopulators()) { p.populate(world, random, chunk); } EventFactory.callEvent(new ChunkPopulateEvent(chunk)); }
/** * Gets a list of loaded chunks. * * @return The currently loaded chunks. */ public GlowChunk[] getLoadedChunks() { ArrayList<GlowChunk> result = new ArrayList<>(); for (GlowChunk chunk : chunks.values()) { if (chunk.isLoaded()) { result.add(chunk); } } return result.toArray(new GlowChunk[result.size()]); }
/** * Forces generation of the given chunk. * * @param x The X coordinate. * @param z The Z coordinate. * @return Whether the chunk was successfully regenerated. */ public boolean forceRegeneration(int x, int z) { GlowChunk chunk = getChunk(x, z); if (chunk == null || !chunk.unload(false, false)) { return false; } chunk.setPopulated(false); try { generateChunk(chunk, x, z); populateChunk(x, z, false); // should this be forced? } catch (Throwable ex) { GlowServer.logger.log( Level.SEVERE, "Error while regenerating chunk (" + x + "," + z + ")", ex); return false; } return true; }
/** * Performs the save for the given chunk using the storage provider. * * @param chunk The chunk to save. */ public boolean performSave(GlowChunk chunk) { if (chunk.isLoaded()) { try { service.write(chunk); return true; } catch (IOException ex) { GlowServer.logger.log(Level.SEVERE, "Error while saving " + chunk, ex); return false; } } return false; }
/** * Call the ChunkIoService to load a chunk, optionally generating the chunk. * * @param x The X coordinate of the chunk to load. * @param z The Y coordinate of the chunk to load. * @param generate Whether to generate the chunk if needed. * @return True on success, false on failure. */ public boolean loadChunk(int x, int z, boolean generate) { GlowChunk chunk = getChunk(x, z); // try to load chunk try { if (service.read(chunk)) { EventFactory.callEvent(new ChunkLoadEvent(chunk, false)); return true; } } catch (Exception e) { GlowServer.logger.log(Level.SEVERE, "Error while loading chunk (" + x + "," + z + ")", e); // an error in chunk reading may have left the chunk in an invalid state // (i.e. double initialization errors), so it's forcibly unloaded here chunk.unload(false, false); } // stop here if we can't generate if (!generate) { return false; } // get generating try { generateChunk(chunk, x, z); } catch (Throwable ex) { GlowServer.logger.log(Level.SEVERE, "Error while generating chunk (" + x + "," + z + ")", ex); return false; } EventFactory.callEvent(new ChunkLoadEvent(chunk, true)); // right now, forcePopulate takes care of populating chunks that players actually see. /*for (int x2 = x - 1; x2 <= x + 1; ++x2) { for (int z2 = z - 1; z2 <= z + 1; ++z2) { populateChunk(x2, z2, false); } }*/ return true; }
/** Initialize a single chunk from the chunk generator. */ private void generateChunk(GlowChunk chunk, int x, int z) { Random random = new Random((long) x * 341873128712L + (long) z * 132897987541L); BiomeGrid biomes = new BiomeGrid(); int[] biomeValues = biomeGrid[0].generateValues( x * GlowChunk.WIDTH, z * GlowChunk.HEIGHT, GlowChunk.WIDTH, GlowChunk.HEIGHT); for (int i = 0; i < biomeValues.length; i++) { biomes.biomes[i] = (byte) biomeValues[i]; } // extended sections with data if (generator instanceof GlowChunkGenerator) { short[][] extSections = ((GlowChunkGenerator) generator) .generateExtBlockSectionsWithData(world, random, x, z, biomes); if (extSections != null) { GlowChunk.ChunkSection[] sections = new GlowChunk.ChunkSection[extSections.length]; for (int i = 0; i < extSections.length; ++i) { // this is sort of messy. if (extSections[i] != null) { sections[i] = new GlowChunk.ChunkSection(); for (int j = 0; j < extSections[i].length; ++j) { sections[i].types[j] = (char) extSections[i][j]; } sections[i].recount(); } } chunk.initializeSections(sections); chunk.setBiomes(biomes.biomes); chunk.automaticHeightMap(); return; } } // extended sections short[][] extSections = generator.generateExtBlockSections(world, random, x, z, biomes); if (extSections != null) { GlowChunk.ChunkSection[] sections = new GlowChunk.ChunkSection[extSections.length]; for (int i = 0; i < extSections.length; ++i) { // this is sort of messy. if (extSections[i] != null) { sections[i] = new GlowChunk.ChunkSection(); for (int j = 0; j < extSections[i].length; ++j) { sections[i].types[j] = (char) (extSections[i][j] << 4); } sections[i].recount(); } } chunk.initializeSections(sections); chunk.setBiomes(biomes.biomes); chunk.automaticHeightMap(); return; } // normal sections byte[][] blockSections = generator.generateBlockSections(world, random, x, z, biomes); if (blockSections != null) { GlowChunk.ChunkSection[] sections = new GlowChunk.ChunkSection[blockSections.length]; for (int i = 0; i < blockSections.length; ++i) { // this is sort of messy. if (blockSections[i] != null) { sections[i] = new GlowChunk.ChunkSection(); for (int j = 0; j < blockSections[i].length; ++j) { sections[i].types[j] = (char) (blockSections[i][j] << 4); } sections[i].recount(); } } chunk.initializeSections(sections); chunk.setBiomes(biomes.biomes); chunk.automaticHeightMap(); return; } // deprecated flat generation byte[] types = generator.generate(world, random, x, z); GlowChunk.ChunkSection[] sections = new GlowChunk.ChunkSection[8]; for (int sy = 0; sy < sections.length; ++sy) { GlowChunk.ChunkSection sec = new GlowChunk.ChunkSection(); int by = 16 * sy; for (int cx = 0; cx < 16; ++cx) { for (int cz = 0; cz < 16; ++cz) { for (int cy = by; cy < by + 16; ++cy) { char type = (char) types[(cx * 16 + cz) * 128 + cy]; sec.types[sec.index(cx, cy, cz)] = (char) (type << 4); } } } sec.recount(); sections[sy] = sec; } chunk.initializeSections(sections); chunk.setBiomes(biomes.biomes); chunk.automaticHeightMap(); }