the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
1#include "stdafx.h"
2#include "net.minecraft.world.level.h"
3#include "LiquidTileDynamic.h"
4#include "net.minecraft.world.level.dimension.h"
5
6LiquidTileDynamic::LiquidTileDynamic(int id, Material *material) : LiquidTile(id, material)
7{
8 maxCount = 0;
9 result = new bool[4];
10 dist = new int[4];
11 m_iterativeInstatick = false;
12}
13
14LiquidTileDynamic::~LiquidTileDynamic()
15{
16 delete[] result;
17 delete[] dist;
18}
19
20void LiquidTileDynamic::setStatic(Level *level, int x, int y, int z)
21{
22 int d = level->getData(x, y, z);
23 level->setTileAndData(x, y, z, id + 1, d, Tile::UPDATE_CLIENTS);
24}
25
26bool LiquidTileDynamic::isPathfindable(LevelSource *level, int x, int y, int z)
27{
28 return material != Material::lava;
29}
30
31void LiquidTileDynamic::iterativeTick(Level *level, int x, int y, int z, Random *random)
32{
33 m_tilesToTick.push_back(LiquidTickData(level, x,y,z,random));
34
35 int failsafe = 100;
36 while((m_tilesToTick.size() > 0) && ( failsafe > 0 ) )
37 {
38 LiquidTickData tickData = m_tilesToTick.front();
39 m_tilesToTick.pop_front();
40 mainTick(tickData.level, tickData.x, tickData.y, tickData.z, tickData.random);
41 failsafe--;
42 }
43 m_tilesToTick.clear();
44}
45
46void LiquidTileDynamic::tick(Level *level, int x, int y, int z, Random *random)
47{
48 if(!m_iterativeInstatick && level->getInstaTick() )
49 {
50 m_iterativeInstatick = true;
51 iterativeTick(level, x, y, z, random);
52 m_iterativeInstatick = false;
53 }
54 else if(m_iterativeInstatick && level->getInstaTick())
55 {
56 m_tilesToTick.push_back(LiquidTickData(level, x,y,z,random));
57 }
58 else
59 {
60 mainTick(level, x, y, z, random);
61 }
62}
63
64// 4J Stu - Split off what was the tick function to be able to change between recursive and iterative ticking
65// This is to fix the stack overflow that occurs sometimes when instaticking on level gen.
66void LiquidTileDynamic::mainTick(Level *level, int x, int y, int z, Random *random)
67{
68 int depth = getDepth(level, x, y, z);
69
70 int dropOff = 1;
71 if (material == Material::lava && !level->dimension->ultraWarm) dropOff = 2;
72
73 bool becomeStatic = true;
74 int tickDelay = getTickDelay(level);
75 if (depth > 0)
76 {
77 int highest = -100;
78 maxCount = 0;
79 highest = getHighest(level, x - 1, y, z, highest);
80 highest = getHighest(level, x + 1, y, z, highest);
81 highest = getHighest(level, x, y, z - 1, highest);
82 highest = getHighest(level, x, y, z + 1, highest);
83
84 int newDepth = highest + dropOff;
85 if (newDepth >= 8 || highest < 0)
86 {
87 newDepth = -1;
88 }
89 if (getDepth(level, x, y + 1, z) >= 0)
90 {
91 int above = getDepth(level, x, y + 1, z);
92 if (above >= 8) newDepth = above;
93 else newDepth = above + 8;
94 }
95 if (maxCount >= 2 && material == Material::water)
96 {
97 // Only spread spring if it's on top of an existing spring, or
98 // on top of solid ground.
99 if (level->getMaterial(x, y - 1, z)->isSolid())
100 {
101 newDepth = 0;
102 }
103 else if (level->getMaterial(x, y - 1, z) == material && level->getData(x, y - 1, z) == 0)
104 {
105 newDepth = 0;
106 }
107 }
108 if (material == Material::lava)
109 {
110 if (depth < 8 && newDepth < 8)
111 {
112 if (newDepth > depth)
113 {
114 if (random->nextInt(4) != 0)
115 {
116 tickDelay = tickDelay * 4;
117 }
118 }
119 }
120 }
121 if (newDepth == depth)
122 {
123 if (becomeStatic)
124 {
125 setStatic(level, x, y, z);
126 }
127 }
128 else
129 {
130 depth = newDepth;
131 if (depth < 0)
132 {
133 level->removeTile(x, y, z);
134 }
135 else
136 {
137 level->setData(x, y, z, depth, Tile::UPDATE_CLIENTS);
138 level->addToTickNextTick(x, y, z, id, tickDelay);
139 level->updateNeighborsAt(x, y, z, id);
140 }
141 }
142 }
143 else
144 {
145 setStatic(level, x, y, z);
146 }
147 if (canSpreadTo(level, x, y - 1, z))
148 {
149 if (material == Material::lava)
150 {
151 if (level->getMaterial(x, y - 1, z) == Material::water)
152 {
153 level->setTileAndUpdate(x, y - 1, z, Tile::stone_Id);
154 fizz(level, x, y - 1, z);
155 return;
156 }
157 }
158
159 if (depth >= 8) trySpreadTo(level, x, y - 1, z, depth);
160 else trySpreadTo(level, x, y - 1, z, depth + 8);
161 }
162 else if (depth >= 0 && (depth == 0 || isWaterBlocking(level, x, y - 1, z)))
163 {
164 bool *spreads = getSpread(level, x, y, z);
165 int neighbor = depth + dropOff;
166 if (depth >= 8)
167 {
168 neighbor = 1;
169 }
170 if (neighbor >= 8) return;
171 if (spreads[0]) trySpreadTo(level, x - 1, y, z, neighbor);
172 if (spreads[1]) trySpreadTo(level, x + 1, y, z, neighbor);
173 if (spreads[2]) trySpreadTo(level, x, y, z - 1, neighbor);
174 if (spreads[3]) trySpreadTo(level, x, y, z + 1, neighbor);
175 }
176}
177
178void LiquidTileDynamic::trySpreadTo(Level *level, int x, int y, int z, int neighbor)
179{
180 if (canSpreadTo(level, x, y, z))
181 {
182 {
183 int old = level->getTile(x, y, z);
184 if (old > 0)
185 {
186 if (material == Material::lava)
187 {
188 fizz(level, x, y, z);
189 }
190 else
191 {
192 Tile::tiles[old]->spawnResources(level, x, y, z, level->getData(x, y, z), 0);
193 }
194 }
195 }
196 level->setTileAndData(x, y, z, id, neighbor, Tile::UPDATE_ALL);
197 }
198}
199
200int LiquidTileDynamic::getSlopeDistance(Level *level, int x, int y, int z, int pass, int from)
201{
202 int lowest = 1000;
203 for (int d = 0; d < 4; d++)
204 {
205 if (d == 0 && from == 1) continue;
206 if (d == 1 && from == 0) continue;
207 if (d == 2 && from == 3) continue;
208 if (d == 3 && from == 2) continue;
209
210 int xx = x;
211 int yy = y;
212 int zz = z;
213
214 if (d == 0) xx--;
215 if (d == 1) xx++;
216 if (d == 2) zz--;
217 if (d == 3) zz++;
218
219 if (isWaterBlocking(level, xx, yy, zz))
220 {
221 continue;
222 } else if (level->getMaterial(xx, yy, zz) == material && level->getData(xx, yy, zz) == 0)
223 {
224 continue;
225 }
226 else
227 {
228 if (isWaterBlocking(level, xx, yy - 1, zz))
229 {
230 if (pass < 4)
231 {
232 int v = getSlopeDistance(level, xx, yy, zz, pass + 1, d);
233 if (v < lowest) lowest = v;
234 }
235 }
236 else
237 {
238 return pass;
239 }
240 }
241 }
242 return lowest;
243
244}
245
246bool *LiquidTileDynamic::getSpread(Level *level, int x, int y, int z)
247{
248 for (int d = 0; d < 4; d++)
249 {
250 dist[d] = 1000;
251 int xx = x;
252 int yy = y;
253 int zz = z;
254
255 if (d == 0) xx--;
256 if (d == 1) xx++;
257 if (d == 2) zz--;
258 if (d == 3) zz++;
259 if (isWaterBlocking(level, xx, yy, zz))
260 {
261 continue;
262 }
263 else if (level->getMaterial(xx, yy, zz) == material && level->getData(xx, yy, zz) == 0)
264 {
265 continue;
266 }
267
268 {
269 if (isWaterBlocking(level, xx, yy - 1, zz))
270 {
271 dist[d] = getSlopeDistance(level, xx, yy, zz, 1, d);
272 }
273 else
274 {
275 dist[d] = 0;
276 }
277 }
278 }
279
280 int lowest = dist[0];
281 for (int d = 1; d < 4; d++)
282 {
283 if (dist[d] < lowest) lowest = dist[d];
284 }
285
286
287 for (int d = 0; d < 4; d++)
288 {
289 result[d] = (dist[d] == lowest);
290 }
291 return result;
292
293}
294
295bool LiquidTileDynamic::isWaterBlocking(Level *level, int x, int y, int z)
296{
297 int t = level->getTile(x, y, z);
298 if (t == Tile::door_wood_Id || t == Tile::door_iron_Id || t == Tile::sign_Id || t == Tile::ladder_Id || t == Tile::reeds_Id)
299 {
300 return true;
301 }
302 if (t == 0) return false;
303 Material *m = Tile::tiles[t]->material;
304 if (m == Material::portal) return true;
305 if (m->blocksMotion()) return true;
306 return false;
307}
308
309int LiquidTileDynamic::getHighest(Level *level, int x, int y, int z, int current)
310{
311 int d = getDepth(level, x, y, z);
312 if (d < 0) return current;
313 if (d == 0) maxCount++;
314 if (d >= 8)
315 {
316 d = 0;
317 }
318 return current < 0 || d < current ? d : current;
319}
320
321bool LiquidTileDynamic::canSpreadTo(Level *level, int x, int y, int z)
322{
323 // 4J added - don't try and spread out of our restricted map. If we don't do this check then tiles at the edge of the world will try and spread outside as the outside tiles report that they contain
324 // only air. The fact that this successfully spreads then updates the neighbours of the tile outside of the map, one of which is the original tile just inside the map, which gets set back to being
325 // dynamic, and added to the pending ticks array.
326 int xc = x >> 4;
327 int zc = z >> 4;
328 int ix = xc + (level->chunkSourceXZSize/2);
329 int iz = zc + (level->chunkSourceXZSize/2);
330 if( ( ix < 0 ) || ( ix >= level->chunkSourceXZSize ) ) return false;
331 if( ( iz < 0 ) || ( iz >= level->chunkSourceXZSize ) ) return false;
332
333 Material *target = level->getMaterial(x, y, z);
334 if (target == material) return false;
335 if (target == Material::lava) return false;
336 return !isWaterBlocking(level, x, y, z);
337}
338
339void LiquidTileDynamic::onPlace(Level *level, int x, int y, int z)
340{
341 LiquidTile::onPlace(level, x, y, z);
342 if (level->getTile(x, y, z) == id)
343 {
344 level->addToTickNextTick(x, y, z, id, getTickDelay(level));
345 }
346}
347
348bool LiquidTileDynamic::canInstantlyTick()
349{
350 return true;
351}