Fork of Poseidon providing Bukkit #1060 to older Beta versions (b1.0-b1.7.3)
1package org.bukkit.craftbukkit;
2
3import com.google.common.collect.MapMaker;
4import net.minecraft.server.BiomeBase;
5import net.minecraft.server.ChunkPosition;
6import net.minecraft.server.WorldChunkManager;
7import net.minecraft.server.WorldServer;
8import org.bukkit.Chunk;
9import org.bukkit.ChunkSnapshot;
10import org.bukkit.World;
11import org.bukkit.block.Block;
12import org.bukkit.block.BlockState;
13import org.bukkit.craftbukkit.block.CraftBlock;
14import org.bukkit.entity.Entity;
15
16import java.lang.ref.WeakReference;
17import java.util.concurrent.ConcurrentMap;
18
19public class CraftChunk implements Chunk {
20 private WeakReference<net.minecraft.server.Chunk> weakChunk;
21 private final ConcurrentMap<Integer, Block> cache = new MapMaker().softValues().makeMap();
22 private WorldServer worldServer;
23 private int x;
24 private int z;
25
26 public CraftChunk(net.minecraft.server.Chunk chunk) {
27 this.weakChunk = new WeakReference<net.minecraft.server.Chunk>(chunk);
28 worldServer = (WorldServer) getHandle().world;
29 x = getHandle().x;
30 z = getHandle().z;
31 }
32
33 public World getWorld() {
34 return worldServer.getWorld();
35 }
36
37 public net.minecraft.server.Chunk getHandle() {
38 net.minecraft.server.Chunk c = weakChunk.get();
39 if (c == null) {
40 c = worldServer.getChunkAt(x, z);
41 weakChunk = new WeakReference<net.minecraft.server.Chunk>(c);
42 }
43 return c;
44 }
45
46 void breakLink() {
47 weakChunk.clear();
48 }
49
50 public int getX() {
51 return x;
52 }
53
54 public int getZ() {
55 return z;
56 }
57
58 @Override
59 public String toString() {
60 return "CraftChunk{" + "x=" + getX() + "z=" + getZ() + '}';
61 }
62
63 public Block getBlock(int x, int y, int z) {
64 int pos = (x & 0xF) << 11 | (z & 0xF) << 7 | (y & 0x7F);
65 Block block = this.cache.get(pos);
66 if (block == null) {
67 Block newBlock = new CraftBlock(this, (getX() << 4) | (x & 0xF), y & 0x7F, (getZ() << 4) | (z & 0xF));
68 Block oldBlock = this.cache.put(pos, newBlock);
69 if (oldBlock == null) {
70 block = newBlock;
71 } else {
72 block = oldBlock;
73 }
74 }
75 return block;
76 }
77
78 public Entity[] getEntities() {
79 int count = 0, index = 0;
80 net.minecraft.server.Chunk chunk = getHandle();
81 for (int i = 0; i < 8; i++) {
82 count += chunk.entitySlices[i].size();
83 }
84
85 Entity[] entities = new Entity[count];
86 for (int i = 0; i < 8; i++) {
87 for (Object obj : chunk.entitySlices[i].toArray()) {
88 if (!(obj instanceof net.minecraft.server.Entity)) {
89 continue;
90 }
91 entities[index++] = ((net.minecraft.server.Entity) obj).getBukkitEntity();
92 }
93 }
94 return entities;
95 }
96
97 public BlockState[] getTileEntities() {
98 int index = 0;
99 net.minecraft.server.Chunk chunk = getHandle();
100 BlockState[] entities = new BlockState[chunk.tileEntities.size()];
101 for (Object obj : chunk.tileEntities.keySet().toArray()) {
102 if (!(obj instanceof ChunkPosition)) {
103 continue;
104 }
105 ChunkPosition position = (ChunkPosition) obj;
106 entities[index++] = worldServer.getWorld().getBlockAt(position.x + (chunk.x << 4), position.y, position.z + (chunk.z << 4)).getState();
107 }
108 return entities;
109 }
110
111 public boolean isLoaded() {
112 return getWorld().isChunkLoaded(this);
113 }
114
115 public boolean load() {
116 return getWorld().loadChunk(getX(), getZ(), true);
117 }
118
119 public boolean load(boolean generate) {
120 return getWorld().loadChunk(getX(), getZ(), generate);
121 }
122
123 public boolean unload() {
124 return getWorld().unloadChunk(getX(), getZ());
125 }
126
127 public boolean unload(boolean save) {
128 return getWorld().unloadChunk(getX(), getZ(), save);
129 }
130
131 public boolean unload(boolean save, boolean safe) {
132 return getWorld().unloadChunk(getX(), getZ(), save, safe);
133 }
134
135 public ChunkSnapshot getChunkSnapshot() {
136 return getChunkSnapshot(true, false, false);
137 }
138
139 public ChunkSnapshot getChunkSnapshot(boolean includeMaxblocky, boolean includeBiome, boolean includeBiomeTempRain) {
140 net.minecraft.server.Chunk chunk = getHandle();
141 byte[] buf = new byte[32768 + 16384 + 16384 + 16384]; // Get big enough buffer for whole chunk
142 chunk.getData(buf, 0, 0, 0, 16, 128, 16, 0); // Get whole chunk
143 byte[] hmap = null;
144
145 if (includeMaxblocky) {
146 hmap = new byte[256]; // Get copy of height map
147 System.arraycopy(chunk.heightMap, 0, hmap, 0, 256);
148 }
149
150 BiomeBase[] biome = null;
151 double[] biomeTemp = null;
152 double[] biomeRain = null;
153
154 if (includeBiome || includeBiomeTempRain) {
155 WorldChunkManager wcm = chunk.world.getWorldChunkManager();
156 BiomeBase[] biomeBase = wcm.getBiomeData(getX() << 4, getZ() << 4, 16, 16);
157
158 if (includeBiome) {
159 biome = new BiomeBase[256];
160 System.arraycopy(biomeBase, 0, biome, 0, biome.length);
161 }
162
163 if (includeBiomeTempRain) {
164 biomeTemp = new double[256];
165 biomeRain = new double[256];
166 System.arraycopy(wcm.temperature, 0, biomeTemp, 0, biomeTemp.length);
167 System.arraycopy(wcm.rain, 0, biomeRain, 0, biomeRain.length);
168 }
169 }
170 World world = getWorld();
171 return new CraftChunkSnapshot(getX(), getZ(), world.getName(), world.getFullTime(), buf, hmap, biome, biomeTemp, biomeRain);
172 }
173
174 /**
175 * Empty chunk snapshot - nothing but air blocks, but can include valid biome data
176 */
177 private static class EmptyChunkSnapshot extends CraftChunkSnapshot {
178 EmptyChunkSnapshot(int x, int z, String worldName, long time, BiomeBase[] biome, double[] biomeTemp, double[] biomeRain) {
179 super(x, z, worldName, time, null, null, biome, biomeTemp, biomeRain);
180 }
181
182 public final int getBlockTypeId(int x, int y, int z) {
183 return 0;
184 }
185
186 public final int getBlockData(int x, int y, int z) {
187 return 0;
188 }
189
190 public final int getBlockSkyLight(int x, int y, int z) {
191 return 15;
192 }
193
194 public final int getBlockEmittedLight(int x, int y, int z) {
195 return 0;
196 }
197
198 public final int getHighestBlockYAt(int x, int z) {
199 return 0;
200 }
201 }
202
203 public static ChunkSnapshot getEmptyChunkSnapshot(int x, int z, CraftWorld world, boolean includeBiome, boolean includeBiomeTempRain) {
204 BiomeBase[] biome = null;
205 double[] biomeTemp = null;
206 double[] biomeRain = null;
207
208 if (includeBiome || includeBiomeTempRain) {
209 WorldChunkManager wcm = world.getHandle().getWorldChunkManager();
210 BiomeBase[] biomeBase = wcm.getBiomeData(x << 4, z << 4, 16, 16);
211
212 if (includeBiome) {
213 biome = new BiomeBase[256];
214 System.arraycopy(biomeBase, 0, biome, 0, biome.length);
215 }
216
217 if (includeBiomeTempRain) {
218 biomeTemp = new double[256];
219 biomeRain = new double[256];
220 System.arraycopy(wcm.temperature, 0, biomeTemp, 0, biomeTemp.length);
221 System.arraycopy(wcm.rain, 0, biomeRain, 0, biomeRain.length);
222 }
223 }
224 return new EmptyChunkSnapshot(x, z, world.getName(), world.getFullTime(), biome, biomeTemp, biomeRain);
225 }
226}