Fork of Poseidon providing Bukkit #1060 to older Beta versions (b1.0-b1.7.3)
1package net.minecraft.server;
2
3import com.legacyminecraft.poseidon.PoseidonConfig;
4import org.bukkit.craftbukkit.CraftChunk;
5import org.bukkit.craftbukkit.util.LongHashset;
6import org.bukkit.craftbukkit.util.LongHashtable;
7import org.bukkit.event.world.ChunkLoadEvent;
8import org.bukkit.event.world.ChunkPopulateEvent;
9import org.bukkit.event.world.ChunkUnloadEvent;
10import org.bukkit.generator.BlockPopulator;
11
12import java.util.ArrayList;
13import java.util.List;
14import java.util.Random;
15
16// CraftBukkit start
17// CraftBukkit end
18
19public class ChunkProviderServer implements IChunkProvider {
20
21 // CraftBukkit start
22 public LongHashset unloadQueue = new LongHashset();
23 public Chunk emptyChunk;
24 public IChunkProvider chunkProvider; // CraftBukkit
25 private IChunkLoader e;
26 public boolean forceChunkLoad = false;
27 public LongHashtable<Chunk> chunks = new LongHashtable<Chunk>();
28 public List chunkList = new ArrayList();
29 public WorldServer world;
30 // CraftBukkit end
31
32 public ChunkProviderServer(WorldServer worldserver, IChunkLoader ichunkloader, IChunkProvider ichunkprovider) {
33 this.emptyChunk = new EmptyChunk(worldserver, new byte['\u8000'], 0, 0);
34 this.world = worldserver;
35 this.e = ichunkloader;
36 this.chunkProvider = ichunkprovider;
37 }
38
39 public boolean isChunkLoaded(int i, int j) {
40 return this.chunks.containsKey(i, j); // CraftBukkit
41 }
42
43 public void queueUnload(int i, int j) {
44 ChunkCoordinates chunkcoordinates = this.world.getSpawn();
45 int k = i * 16 + 8 - chunkcoordinates.x;
46 int l = j * 16 + 8 - chunkcoordinates.z;
47 short short1 = 128;
48
49 if (k < -short1 || k > short1 || l < -short1 || l > short1 || !(this.world.keepSpawnInMemory)) { // CraftBukkit - added 'this.world.keepSpawnInMemory'
50 this.unloadQueue.add(i, j); // CraftBukkit
51 }
52 }
53
54 public Chunk getChunkAt(int i, int j) {
55 // CraftBukkit start
56 this.unloadQueue.remove(i, j);
57 Chunk chunk = (Chunk) this.chunks.get(i, j);
58 boolean newChunk = false;
59 // CraftBukkit end
60
61 if (chunk == null) {
62 chunk = this.loadChunk(i, j);
63 if (chunk == null) {
64 if (this.chunkProvider == null) {
65 chunk = this.emptyChunk;
66 } else {
67 chunk = this.chunkProvider.getOrCreateChunk(i, j);
68 }
69 newChunk = true; // CraftBukkit
70 }
71
72 this.chunks.put(i, j, chunk); // CraftBukkit
73 this.chunkList.add(chunk);
74 if (chunk != null) {
75 chunk.loadNOP();
76 chunk.addEntities();
77 }
78
79 // CraftBukkit start
80 org.bukkit.Server server = this.world.getServer();
81 if (server != null) {
82 /*
83 * If it's a new world, the first few chunks are generated inside
84 * the World constructor. We can't reliably alter that, so we have
85 * no way of creating a CraftWorld/CraftServer at that point.
86 */
87 server.getPluginManager().callEvent(new ChunkLoadEvent(chunk.bukkitChunk, newChunk));
88 }
89 // CraftBukkit end
90
91 if (!chunk.done && this.isChunkLoaded(i + 1, j + 1) && this.isChunkLoaded(i, j + 1) && this.isChunkLoaded(i + 1, j)) {
92 this.getChunkAt(this, i, j);
93 }
94
95 if (this.isChunkLoaded(i - 1, j) && !this.getOrCreateChunk(i - 1, j).done && this.isChunkLoaded(i - 1, j + 1) && this.isChunkLoaded(i, j + 1) && this.isChunkLoaded(i - 1, j)) {
96 this.getChunkAt(this, i - 1, j);
97 }
98
99 if (this.isChunkLoaded(i, j - 1) && !this.getOrCreateChunk(i, j - 1).done && this.isChunkLoaded(i + 1, j - 1) && this.isChunkLoaded(i, j - 1) && this.isChunkLoaded(i + 1, j)) {
100 this.getChunkAt(this, i, j - 1);
101 }
102
103 if (this.isChunkLoaded(i - 1, j - 1) && !this.getOrCreateChunk(i - 1, j - 1).done && this.isChunkLoaded(i - 1, j - 1) && this.isChunkLoaded(i, j - 1) && this.isChunkLoaded(i - 1, j)) {
104 this.getChunkAt(this, i - 1, j - 1);
105 }
106 }
107
108 return chunk;
109 }
110
111 public Chunk getOrCreateChunk(int i, int j) {
112 // CraftBukkit start
113 Chunk chunk = (Chunk) this.chunks.get(i, j);
114
115 //Poseidon chunk regenerate
116 try {
117 chunk = chunk == null ? (!this.world.isLoading && !this.forceChunkLoad ? this.emptyChunk : this.getChunkAt(i, j)) : chunk;
118 } catch (Exception e) {
119 //Poseidon chunk regenerate
120 if (PoseidonConfig.getInstance().getConfigBoolean("emergency.debug.regenerate-corrupt-chunks.enable")) {
121 System.out.println("Poseidon ran into a critical error when attempting to load a chunk (" + i + "," + j + "+. Regenerating chunk...");
122 chunk = this.emptyChunk;
123 } else {
124 System.out.println("Poseidon ran into a critical error when attempting to load a chunk (" + i + "," + j + "+. The server will now likely hang. Enabling \"emergency.debug.regenerate-corrupt-chunks.enable\" in the Poseidon.yml may help.");
125 e.printStackTrace();
126 }
127 e.printStackTrace();
128 }
129
130
131 if (chunk == this.emptyChunk) return chunk;
132 if (i != chunk.x || j != chunk.z) {
133 MinecraftServer.log.info("Chunk (" + chunk.x + ", " + chunk.z + ") stored at (" + i + ", " + j + ")");
134 MinecraftServer.log.info(chunk.getClass().getName());
135 Throwable ex = new Throwable();
136 ex.fillInStackTrace();
137 ex.printStackTrace();
138 }
139 return chunk;
140 // CraftBukkit end
141 }
142
143 public Chunk loadChunk(int i, int j) { // CraftBukkit - private -> public
144 if (this.e == null) {
145 return null;
146 } else {
147 try {
148 Chunk chunk = this.e.a(this.world, i, j);
149
150 if (chunk != null) {
151 chunk.r = this.world.getTime();
152 }
153
154 return chunk;
155 } catch (Exception exception) {
156 exception.printStackTrace();
157 return null;
158 }
159 }
160 }
161
162 public void saveChunkNOP(Chunk chunk) { // CraftBukkit - private -> public
163 if (this.e != null) {
164 try {
165 this.e.b(this.world, chunk);
166 } catch (Exception exception) {
167 exception.printStackTrace();
168 }
169 }
170 }
171
172 public void saveChunk(Chunk chunk) { // CraftBukkit - private -> public
173 if (this.e != null) {
174 try {
175 chunk.r = this.world.getTime();
176 this.e.a(this.world, chunk);
177 } catch (Exception ioexception) { // CraftBukkit - IOException -> Exception
178 ioexception.printStackTrace();
179 }
180 }
181 }
182
183 public void getChunkAt(IChunkProvider ichunkprovider, int i, int j) {
184 Chunk chunk = this.getOrCreateChunk(i, j);
185
186 if (!chunk.done) {
187 chunk.done = true;
188 if (this.chunkProvider != null) {
189 this.chunkProvider.getChunkAt(ichunkprovider, i, j);
190
191 // CraftBukkit start
192 BlockSand.instaFall = true;
193 Random random = new Random();
194 random.setSeed(world.getSeed());
195 long xRand = random.nextLong() / 2L * 2L + 1L;
196 long zRand = random.nextLong() / 2L * 2L + 1L;
197 random.setSeed((long) i * xRand + (long) j * zRand ^ world.getSeed());
198
199 org.bukkit.World world = this.world.getWorld();
200 if (world != null) {
201 for (BlockPopulator populator : world.getPopulators()) {
202 populator.populate(world, random, chunk.bukkitChunk);
203 }
204 }
205 BlockSand.instaFall = false;
206 this.world.getServer().getPluginManager().callEvent(new ChunkPopulateEvent(chunk.bukkitChunk));
207 // CraftBukkit end
208
209 chunk.f();
210 }
211 }
212 }
213
214 public boolean saveChunks(boolean flag, IProgressUpdate iprogressupdate) {
215 int i = 0;
216
217 for (int j = 0; j < this.chunkList.size(); ++j) {
218 Chunk chunk = (Chunk) this.chunkList.get(j);
219
220 if (flag && !chunk.p) {
221 this.saveChunkNOP(chunk);
222 }
223
224 if (chunk.a(flag)) {
225 this.saveChunk(chunk);
226 chunk.o = false;
227 ++i;
228 if (i == 24 && !flag) {
229 return false;
230 }
231 }
232 }
233
234 if (flag) {
235 if (this.e == null) {
236 return true;
237 }
238
239 this.e.b();
240 }
241
242 return true;
243 }
244
245 public boolean unloadChunks() {
246 if (!this.world.canSave) {
247 // CraftBukkit start
248 org.bukkit.Server server = this.world.getServer();
249 for (int i = 0; i < 50 && !this.unloadQueue.isEmpty(); i++) {
250 long chunkcoordinates = this.unloadQueue.popFirst();
251 Chunk chunk = this.chunks.get(chunkcoordinates);
252 if (chunk == null) continue;
253
254 ChunkUnloadEvent event = new ChunkUnloadEvent(chunk.bukkitChunk);
255 server.getPluginManager().callEvent(event);
256 if (!event.isCancelled()) {
257// this.world.getWorld().preserveChunk((CraftChunk) chunk.bukkitChunk);
258
259 chunk.removeEntities();
260 this.saveChunk(chunk);
261 this.saveChunkNOP(chunk);
262 // this.unloadQueue.remove(integer);
263 this.chunks.remove(chunkcoordinates); // CraftBukkit
264 this.chunkList.remove(chunk);
265 }
266 }
267 // CraftBukkit end
268
269 if (this.e != null) {
270 this.e.a();
271 }
272 }
273
274 return this.chunkProvider.unloadChunks();
275 }
276
277 public boolean canSave() {
278 return !this.world.canSave;
279 }
280}