Commits

Aikar authored and md_5 committed 1953f52da1e
SPIGOT-2439: Consistently fire Chunk(Load|Unload)Event

Clean up implementation and firing of both of these events by routing both unload and load behaviors to consistent method calls. This fixes issues where a few places would not call Load or Unload events when it should have. Additionally, reduces diff by moving the neighbor marking code into these consistent points. Additional benefits of the change include improving the neighbor marking methods to use getChunkIfLoaded instead of getLoadedChunkAt in some places, as the latter will cause chunks to be marked active and not unload. Finally, this also updates CraftWorld.loadChunk to use the new methods, as the previous logic did not properly handle the new unload queue.
No tags

nms-patches/Chunk.patch

Modified
1 1 --- a/net/minecraft/server/Chunk.java
2 2 +++ b/net/minecraft/server/Chunk.java
3 3 @@ -14,6 +14,9 @@
4 4 import org.apache.logging.log4j.LogManager;
5 5 import org.apache.logging.log4j.Logger;
6 6
7 7 +import com.google.common.collect.Lists; // CraftBukkit
8 -+import org.bukkit.Bukkit; // CraftBukkit
8 ++import org.bukkit.Server; // CraftBukkit
9 9 +
10 10 public class Chunk {
11 11
12 12 private static final Logger e = LogManager.getLogger();
13 -@@ -42,6 +45,34 @@
13 +@@ -42,6 +45,35 @@
14 14 private ConcurrentLinkedQueue<BlockPosition> y;
15 15 public boolean d;
16 16
17 17 + // CraftBukkit start - Neighbor loaded cache for chunk lighting and entity ticking
18 18 + private int neighbors = 0x1 << 12;
19 ++ public long chunkKey;
19 20 +
20 21 + public boolean areNeighborsLoaded(final int radius) {
21 22 + switch (radius) {
22 23 + case 2:
23 24 + return this.neighbors == Integer.MAX_VALUE >> 6;
24 25 + case 1:
25 26 + final int mask =
26 27 + // x z offset x z offset x z offset
27 28 + (0x1 << (1 * 5 + 1 + 12)) | (0x1 << (0 * 5 + 1 + 12)) | (0x1 << (-1 * 5 + 1 + 12)) |
28 29 + (0x1 << (1 * 5 + 0 + 12)) | (0x1 << (0 * 5 + 0 + 12)) | (0x1 << (-1 * 5 + 0 + 12)) |
38 39 + }
39 40 +
40 41 + public void setNeighborUnloaded(final int x, final int z) {
41 42 + this.neighbors &= ~(0x1 << (x * 5 + 12 + z));
42 43 + }
43 44 + // CraftBukkit end
44 45 +
45 46 public Chunk(World world, int i, int j) {
46 47 this.sections = new ChunkSection[16];
47 48 this.g = new byte[256];
48 -@@ -62,8 +93,14 @@
49 +@@ -62,8 +94,15 @@
49 50
50 51 Arrays.fill(this.h, -999);
51 52 Arrays.fill(this.g, (byte) -1);
52 53 + // CraftBukkit start
53 54 + this.bukkitChunk = new org.bukkit.craftbukkit.CraftChunk(this);
55 ++ this.chunkKey = ChunkCoordIntPair.a(this.locX, this.locZ);
54 56 }
55 57
56 58 + public org.bukkit.Chunk bukkitChunk;
57 59 + public boolean mustSave;
58 60 + // CraftBukkit end
59 61 +
60 62 public Chunk(World world, ChunkSnapshot chunksnapshot, int i, int j) {
61 63 this(world, i, j);
62 64 boolean flag = true;
63 -@@ -467,7 +504,8 @@
65 +@@ -467,7 +506,8 @@
64 66 }
65 67 }
66 68
67 69 - if (!this.world.isClientSide && block1 != block) {
68 70 + // CraftBukkit - Don't place while processing the BlockPlaceEvent, unless it's a BlockContainer. Prevents blocks such as TNT from activating when cancelled.
69 71 + if (!this.world.isClientSide && block1 != block && (!this.world.captureBlockStates || block instanceof BlockTileEntity)) {
70 72 block.onPlace(this.world, blockposition, iblockdata);
71 73 }
72 74
73 -@@ -604,7 +642,15 @@
75 +@@ -604,7 +644,15 @@
74 76
75 77 @Nullable
76 78 public TileEntity a(BlockPosition blockposition, Chunk.EnumTileEntityState chunk_enumtileentitystate) {
77 79 - TileEntity tileentity = (TileEntity) this.tileEntities.get(blockposition);
78 80 + // CraftBukkit start
79 81 + TileEntity tileentity = null;
80 82 + if (world.captureBlockStates) {
81 83 + tileentity = world.capturedTileEntities.get(blockposition);
82 84 + }
83 85 + if (tileentity == null) {
84 86 + tileentity = (TileEntity) this.tileEntities.get(blockposition);
85 87 + }
86 88 + // CraftBukkit end
87 89
88 90 if (tileentity == null) {
89 91 if (chunk_enumtileentitystate == Chunk.EnumTileEntityState.IMMEDIATE) {
90 -@@ -639,6 +685,13 @@
92 +@@ -639,6 +687,13 @@
91 93
92 94 tileentity.z();
93 95 this.tileEntities.put(blockposition, tileentity);
94 96 + // CraftBukkit start
95 97 + } else {
96 98 + System.out.println("Attempted to place a tile entity (" + tileentity + ") at " + tileentity.position.getX() + "," + tileentity.position.getY() + "," + tileentity.position.getZ()
97 99 + + " (" + org.bukkit.craftbukkit.util.CraftMagicNumbers.getMaterial(getBlockData(blockposition).getBlock()) + ") where there was no entity tile!");
98 100 + System.out.println("Chunk coordinates: " + (this.locX * 16) + "," + (this.locZ * 16));
99 101 + new Exception().printStackTrace();
100 102 + // CraftBukkit end
101 103 }
102 104 }
103 105
104 -@@ -681,9 +734,21 @@
106 +@@ -681,9 +736,21 @@
105 107 int i = aentityslice.length;
106 108
107 109 for (int j = 0; j < i; ++j) {
108 110 - EntitySlice entityslice = aentityslice[j];
109 111 + // CraftBukkit start
110 112 + List<Entity> newList = Lists.newArrayList(aentityslice[j]);
111 113 + java.util.Iterator<Entity> iter = newList.iterator();
112 114 + while (iter.hasNext()) {
113 115 + Entity entity = iter.next();
114 -
115 -- this.world.c((Collection) entityslice);
116 ++
116 117 + // Do not pass along players, as doing so can get them stuck outside of time.
117 118 + // (which for example disables inventory icon updates and prevents block breaking)
118 119 + if (entity instanceof EntityPlayer) {
119 120 + iter.remove();
120 121 + }
121 122 + }
122 -+
123 -+ this.world.c((Collection) newList);
123 +
124 +- this.world.c((Collection) entityslice);
125 ++ this.world.c(newList);
124 126 + // CraftBukkit end
125 127 }
126 128
127 129 }
128 -@@ -745,8 +810,8 @@
130 +@@ -745,8 +812,8 @@
129 131 while (iterator.hasNext()) {
130 132 Entity entity = (Entity) iterator.next();
131 133
132 134 - if (entity.getBoundingBox().b(axisalignedbb) && (predicate == null || predicate.apply(entity))) {
133 135 - list.add(entity);
134 136 + if (entity.getBoundingBox().b(axisalignedbb) && (predicate == null || predicate.apply((T) entity))) { // CraftBukkit - fix decompile error
135 137 + list.add((T) entity); // Fix decompile error
136 138 }
137 139 }
138 140 }
139 -@@ -809,6 +874,29 @@
141 +@@ -773,7 +840,34 @@
142 + return false;
143 + }
144 +
145 +- public void loadNearby(IChunkProvider ichunkprovider, ChunkGenerator chunkgenerator) {
146 ++ // CraftBukkit start
147 ++ public void loadNearby(IChunkProvider ichunkprovider, ChunkGenerator chunkgenerator, boolean newChunk) {
148 ++ Server server = world.getServer();
149 ++ if (server != null) {
150 ++ /*
151 ++ * If it's a new world, the first few chunks are generated inside
152 ++ * the World constructor. We can't reliably alter that, so we have
153 ++ * no way of creating a CraftWorld/CraftServer at that point.
154 ++ */
155 ++ server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkLoadEvent(bukkitChunk, newChunk));
156 ++ }
157 ++
158 ++ // Update neighbor counts
159 ++ for (int x = -2; x < 3; x++) {
160 ++ for (int z = -2; z < 3; z++) {
161 ++ if (x == 0 && z == 0) {
162 ++ continue;
163 ++ }
164 ++
165 ++ Chunk neighbor = getWorld().getChunkIfLoaded(locX + x, locZ + z);
166 ++ if (neighbor != null) {
167 ++ neighbor.setNeighborLoaded(-x, -z);
168 ++ setNeighborLoaded(x, z);
169 ++ }
170 ++ }
171 ++ }
172 ++ // CraftBukkit end
173 ++
174 + Chunk chunk = ichunkprovider.getLoadedChunkAt(this.locX, this.locZ - 1);
175 + Chunk chunk1 = ichunkprovider.getLoadedChunkAt(this.locX + 1, this.locZ);
176 + Chunk chunk2 = ichunkprovider.getLoadedChunkAt(this.locX, this.locZ + 1);
177 +@@ -809,6 +903,29 @@
140 178 } else {
141 179 this.o();
142 180 chunkgenerator.recreateStructures(this.locX, this.locZ);
143 181 +
144 182 + // CraftBukkit start
145 183 + BlockSand.instaFall = true;
146 184 + Random random = new Random();
147 185 + random.setSeed(world.getSeed());
148 186 + long xRand = random.nextLong() / 2L * 2L + 1L;
149 187 + long zRand = random.nextLong() / 2L * 2L + 1L;

Everything looks good. We'll let you know here if there's anything you should know about.

Add shortcut